geonetwork-ui 2.11.0-dev.4976ded4f → 2.11.0-dev.57f4be358

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 (49) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1291 -1283
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +116 -80
  4. package/index.d.ts.map +1 -1
  5. package/package.json +2 -1
  6. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +90 -31
  7. package/src/libs/common/domain/src/lib/model/search/aggregation.model.ts +2 -0
  8. package/src/libs/common/domain/src/lib/model/search/filter.model.ts +12 -2
  9. package/src/libs/feature/map/src/index.ts +0 -2
  10. package/src/libs/feature/map/src/lib/feature-map.module.ts +1 -8
  11. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +8 -3
  12. package/src/libs/feature/search/src/index.ts +2 -0
  13. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +3 -0
  14. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +21 -4
  15. package/src/libs/feature/{map/src/lib → search/src/lib/geocoding}/geocoding.service.ts +16 -7
  16. package/src/libs/feature/search/src/lib/location-search/location-search.component.html +8 -0
  17. package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +40 -0
  18. package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +2 -0
  19. package/src/libs/feature/search/src/lib/state/reducer.ts +1 -4
  20. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +56 -4
  21. package/src/libs/feature/search/src/lib/utils/service/fields.ts +67 -9
  22. package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.ts +2 -1
  23. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +10 -1
  24. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +8 -0
  25. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +7 -4
  26. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +12 -9
  27. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.model.ts +2 -2
  28. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +5 -11
  29. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +34 -4
  30. package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +1 -0
  31. package/src/libs/util/app-config/src/lib/app-config.ts +22 -0
  32. package/src/libs/util/app-config/src/lib/fixtures.ts +33 -1
  33. package/src/libs/util/app-config/src/lib/model.ts +14 -1
  34. package/src/libs/util/shared/src/lib/links/link-utils.ts +19 -10
  35. package/src/libs/util/shared/src/lib/utils/geojson.ts +16 -0
  36. package/translations/de.json +10 -3
  37. package/translations/en.json +11 -4
  38. package/translations/es.json +10 -3
  39. package/translations/fr.json +15 -8
  40. package/translations/it.json +10 -3
  41. package/translations/nl.json +10 -3
  42. package/translations/pt.json +10 -3
  43. package/translations/sk.json +10 -3
  44. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.css +0 -0
  45. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +0 -41
  46. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +0 -112
  47. package/src/libs/feature/map/src/lib/style/index.ts +0 -2
  48. package/src/libs/feature/map/src/lib/style/map-style.fixtures.ts +0 -47
  49. package/src/libs/feature/map/src/lib/style/map-style.service.ts +0 -108
@@ -6,7 +6,7 @@ import GeoJSON from 'ol/format/GeoJSON.js';
6
6
  import { parse as parse$1 } from 'ol/xml.js';
7
7
  import { format } from 'date-fns/format';
8
8
  import { Namespace, Literal, lit, parse as parse$2, sym, BlankNode, graph } from 'rdflib';
9
- import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, forkJoin, combineLatest, from, exhaustMap, throwError, takeLast, firstValueFrom, merge, BehaviorSubject, timer, ReplaySubject, Subscription, first, distinctUntilChanged as distinctUntilChanged$1, animationFrameScheduler, debounceTime as debounceTime$1, Observable, buffer, tap as tap$2, combineLatestWith, take as take$1, catchError as catchError$1, takeUntil, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1 } from 'rxjs';
9
+ import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, forkJoin, combineLatest, from, exhaustMap, throwError, takeLast, firstValueFrom, merge, BehaviorSubject, timer, ReplaySubject, Subscription, first, distinctUntilChanged as distinctUntilChanged$1, animationFrameScheduler, debounceTime as debounceTime$1, Observable, buffer, tap as tap$2, combineLatestWith, take as take$1, catchError as catchError$1, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1, takeUntil } from 'rxjs';
10
10
  import * as i0 from '@angular/core';
11
11
  import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef, afterNextRender, booleanAttribute, Input, Directive, HostListener, Renderer2, DestroyRef, EventEmitter, Output, ViewChild, ChangeDetectionStrategy, Component, ViewEncapsulation, ChangeDetectorRef, HostBinding, ViewContainerRef, TemplateRef, ViewChildren, ContentChild, input, output, signal, viewChild, computed, ContentChildren, NgZone, ComponentFactoryResolver, viewChildren } from '@angular/core';
12
12
  import { HttpClient, HttpHeaders, HttpParams, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, HttpEventType } from '@angular/common/http';
@@ -26,7 +26,6 @@ import { getLength } from 'ol/sphere.js';
26
26
  import { LineString } from 'ol/geom.js';
27
27
  import * as i1 from '@ngrx/store';
28
28
  import { createAction, props, createReducer, on, createFeatureSelector, createSelector, Store, select, StoreModule } from '@ngrx/store';
29
- import { queryDataGouvFr, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
30
29
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
31
30
  import { FeaturesClickEventType, FeaturesHoverEventType, MapClickEventType, MapExtentChangeEventType, SourceLoadErrorType, computeMapContextDiff, createViewFromLayer } from '@geospatial-sdk/core';
32
31
  import { createMapFromContext, applyContextDiffToMap, listen } from '@geospatial-sdk/openlayers';
@@ -37,11 +36,8 @@ import { createLegendFromLayer } from '@geospatial-sdk/legend';
37
36
  import { mouseOnly, noModifierKeys, primaryAction, platformModifierKeyOnly } from 'ol/events/condition.js';
38
37
  import { defaults, DragPan, MouseWheelZoom } from 'ol/interaction.js';
39
38
  import { extend } from 'ol/extent.js';
40
- import * as TOML from '@ltd/j-toml';
41
- import { Style, Stroke, Fill, Circle } from 'ol/style.js';
42
- import CircleStyle from 'ol/style/Circle.js';
43
39
  import EmblaCarousel from 'embla-carousel';
44
- import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirTrash, iconoirSquareDashed, iconoirImport, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
40
+ import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirUpload, iconoirTrash, iconoirSquareDashed, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirImport, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
45
41
  import { MatButtonModule } from '@angular/material/button';
46
42
  import * as i1$7 from '@angular/cdk/overlay';
47
43
  import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
@@ -74,6 +70,7 @@ import { MatTabsModule } from '@angular/material/tabs';
74
70
  import * as i2$2 from '@ngrx/effects';
75
71
  import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
76
72
  import { valid as valid$1 } from 'geojson-validation';
73
+ import { queryGeoplateforme, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
77
74
  import { TemplatePortal } from '@angular/cdk/portal';
78
75
  import { parse as parse$3 } from 'marked';
79
76
  import * as i2$3 from '@angular/cdk/scrolling';
@@ -101,6 +98,7 @@ import { TextFieldModule } from '@angular/cdk/text-field';
101
98
  import * as i2$5 from '@ngrx/router-store';
102
99
  import { getRouterSelectors, routerReducer, StoreRouterConnectingModule, FullRouterStateSerializer } from '@ngrx/router-store';
103
100
  import { navigation } from '@ngrx/router-store/data-persistence';
101
+ import * as TOML from '@ltd/j-toml';
104
102
 
105
103
  class MetadataMapperContext {
106
104
  }
@@ -19596,6 +19594,19 @@ function isBoundingBox(value) {
19596
19594
  value.length === 4 &&
19597
19595
  value.every((item) => typeof item === 'number'));
19598
19596
  }
19597
+ /**
19598
+ * Checks that a bounding box's coordinates stay within the valid
19599
+ * longitude (-180/180) and latitude (-90/90) ranges.
19600
+ */
19601
+ function isBoundingBoxWithinWorldExtent(bbox) {
19602
+ const [minX, minY, maxX, maxY] = bbox;
19603
+ return (minX >= -180 &&
19604
+ maxX <= 180 &&
19605
+ minY >= -90 &&
19606
+ maxY <= 90 &&
19607
+ minX <= maxX &&
19608
+ minY <= maxY);
19609
+ }
19599
19610
  function getGeometryBoundingBox(geometry) {
19600
19611
  // use the bounding box if specified in the GeoJSON object
19601
19612
  if (geometry.bbox) {
@@ -20264,7 +20275,7 @@ function getLinkLabel(link) {
20264
20275
  const label = link.description || ('name' in link ? link.name : '');
20265
20276
  return format ? `${label} (${format})` : label;
20266
20277
  }
20267
- async function getLayers(url, serviceProtocol) {
20278
+ async function getLayers(url, serviceProtocol, deep = false) {
20268
20279
  switch (serviceProtocol) {
20269
20280
  case 'ogcFeatures': {
20270
20281
  const layers = await new OgcApiEndpoint(url).allCollections;
@@ -20272,7 +20283,10 @@ async function getLayers(url, serviceProtocol) {
20272
20283
  }
20273
20284
  case 'wfs': {
20274
20285
  const endpointWfs = await new WfsEndpoint(url).isReady();
20275
- const featureTypes = await endpointWfs.getFeatureTypes();
20286
+ const featureTypes = endpointWfs.getFeatureTypes();
20287
+ if (!deep) {
20288
+ return featureTypes;
20289
+ }
20276
20290
  const layers = (await Promise.allSettled(featureTypes.map((collection) => {
20277
20291
  return endpointWfs.getFeatureTypeFull(collection.name);
20278
20292
  })))
@@ -20282,12 +20296,14 @@ async function getLayers(url, serviceProtocol) {
20282
20296
  }
20283
20297
  case 'wms': {
20284
20298
  const endpointWms = await new WmsEndpoint(url).isReady();
20285
- const layers = (await endpointWms
20299
+ const layersSummary = endpointWms
20286
20300
  .getLayers()
20287
20301
  .flatMap(wmsLayerFlatten)
20288
- .filter((l) => l.name)).map((collection) => {
20289
- return endpointWms.getLayerByName(collection.name);
20290
- });
20302
+ .filter((l) => l.name);
20303
+ if (!deep) {
20304
+ return layersSummary;
20305
+ }
20306
+ const layers = layersSummary.map((collection) => endpointWms.getLayerByName(collection.name));
20291
20307
  return layers;
20292
20308
  }
20293
20309
  case 'wmts': {
@@ -20434,7 +20450,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
20434
20450
  }] } });
20435
20451
 
20436
20452
  var name = "geonetwork-ui";
20437
- var version = "2.11.0-dev.4976ded4f";
20453
+ var version = "2.11.0-dev.57f4be358";
20438
20454
  var engines = {
20439
20455
  node: ">=24"
20440
20456
  };
@@ -20455,6 +20471,7 @@ var peerDependencies = {
20455
20471
  "@angular/core": "19.x || 20.x || 21.x",
20456
20472
  "@angular/forms": "19.x || 20.x || 21.x",
20457
20473
  "@angular/material": "19.x || 20.x || 21.x",
20474
+ "@angular/material-date-fns-adapter": "19.x || 20.x",
20458
20475
  "@angular/platform-browser": "19.x || 20.x || 21.x",
20459
20476
  "@angular/platform-browser-dynamic": "19.x || 20.x || 21.x",
20460
20477
  "@angular/router": "19.x || 20.x || 21.x",
@@ -20671,6 +20688,7 @@ class ElasticsearchService {
20671
20688
  // runtime fields are computed using a Painless script
20672
20689
  // see: https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-mapping-fields.html
20673
20690
  this.runtimeFields = {};
20691
+ this.fieldAliases = {};
20674
20692
  }
20675
20693
  // we're using getters in case the defined languages change over time
20676
20694
  get metadataLang() {
@@ -20696,8 +20714,8 @@ class ElasticsearchService {
20696
20714
  if (!payload.runtime_mappings)
20697
20715
  payload.runtime_mappings = {};
20698
20716
  payload.runtime_mappings[fieldName] = {
20699
- type: 'keyword',
20700
- script: this.runtimeFields[fieldName],
20717
+ type: this.runtimeFields[fieldName].type,
20718
+ script: this.runtimeFields[fieldName].script,
20701
20719
  };
20702
20720
  };
20703
20721
  const lookForField = (node) => {
@@ -20717,6 +20735,12 @@ class ElasticsearchService {
20717
20735
  (node[runtimeField] === 'asc' || node[runtimeField] === 'desc')) {
20718
20736
  addMapping(runtimeField);
20719
20737
  }
20738
+ if (runtimeField in node &&
20739
+ typeof node[runtimeField] === 'object' &&
20740
+ node[runtimeField] !== null &&
20741
+ ('gte' in node[runtimeField] || 'lte' in node[runtimeField])) {
20742
+ addMapping(runtimeField);
20743
+ }
20720
20744
  if ('query' in node &&
20721
20745
  typeof node.query === 'string' &&
20722
20746
  node.query.indexOf(runtimeField + ':') > -1) {
@@ -20733,8 +20757,11 @@ class ElasticsearchService {
20733
20757
  lookForField(payload.query);
20734
20758
  return payload;
20735
20759
  }
20736
- registerRuntimeField(fieldName, expression) {
20737
- this.runtimeFields[fieldName] = expression;
20760
+ registerRuntimeField(fieldName, expression, type = 'keyword') {
20761
+ this.runtimeFields[fieldName] = { script: expression, type };
20762
+ }
20763
+ registerFieldAlias(fieldIdentifier, esFieldName) {
20764
+ this.fieldAliases[fieldIdentifier] = esFieldName;
20738
20765
  }
20739
20766
  getMetadataByIdsPayload(uuids) {
20740
20767
  return {
@@ -20857,6 +20884,55 @@ class ElasticsearchService {
20857
20884
  }
20858
20885
  return Object.values(filters).find(isBoundingBox);
20859
20886
  }
20887
+ // builds a query matching records whose dates intersect the filter range
20888
+ buildDateRangeQuery(searchField, dateRange) {
20889
+ // fields ending with 'DateRange' maps as ES range type
20890
+ if (searchField.endsWith('DateRange')) {
20891
+ return {
20892
+ range: {
20893
+ [searchField]: {
20894
+ ...(dateRange.start && { gte: formatDate(dateRange.start) }),
20895
+ ...(dateRange.end && { lte: formatDate(dateRange.end) }),
20896
+ format: 'yyyy-MM-dd',
20897
+ relation: 'intersects',
20898
+ },
20899
+ },
20900
+ };
20901
+ }
20902
+ const minField = `${searchField}Min`;
20903
+ const maxField = `${searchField}Max`;
20904
+ if (minField in this.runtimeFields && maxField in this.runtimeFields) {
20905
+ // min/max runtime fields form an interval per record; match if it intersects the filter range
20906
+ const filter = [
20907
+ dateRange.start && {
20908
+ range: {
20909
+ [maxField]: {
20910
+ gte: formatDate(dateRange.start),
20911
+ format: 'yyyy-MM-dd',
20912
+ },
20913
+ },
20914
+ },
20915
+ dateRange.end && {
20916
+ range: {
20917
+ [minField]: {
20918
+ lte: formatDate(dateRange.end),
20919
+ format: 'yyyy-MM-dd',
20920
+ },
20921
+ },
20922
+ },
20923
+ ].filter(Boolean);
20924
+ return { bool: { filter } };
20925
+ }
20926
+ return {
20927
+ range: {
20928
+ [searchField]: {
20929
+ ...(dateRange.start && { gte: formatDate(dateRange.start) }),
20930
+ ...(dateRange.end && { lte: formatDate(dateRange.end) }),
20931
+ format: 'yyyy-MM-dd',
20932
+ },
20933
+ },
20934
+ };
20935
+ }
20860
20936
  filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
20861
20937
  const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
20862
20938
  const makeQuery = (filter) => {
@@ -20881,39 +20957,19 @@ class ElasticsearchService {
20881
20957
  .filter((fieldname) => !Array.isArray(filters[fieldname]))
20882
20958
  .filter((fieldname) => filters[fieldname] &&
20883
20959
  JSON.stringify(filters[fieldname]) !== '{}')
20884
- .map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
20960
+ .map((fieldname) => `${this.fieldAliases[fieldname] ?? fieldname}:(${makeQuery(filters[fieldname])})`)
20885
20961
  .join(' AND ');
20886
20962
  if (filters['gn-ui-crossFieldFilter']) {
20887
20963
  queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
20888
20964
  }
20889
- const queryRange = Object.entries(filters)
20890
- .filter(([, value]) => isDateRange(value))
20891
- .map(([searchField, dateRange]) => {
20892
- return {
20893
- searchField,
20894
- dateRange,
20895
- };
20896
- })[0];
20965
+ const queryRanges = Object.entries(filters).filter(([, value]) => isDateRange(value));
20897
20966
  const queryParts = [
20898
20967
  queryString && {
20899
20968
  query_string: {
20900
20969
  query: queryString,
20901
20970
  },
20902
20971
  },
20903
- queryRange &&
20904
- queryRange.dateRange && {
20905
- range: {
20906
- [queryRange.searchField]: {
20907
- ...(queryRange.dateRange.start && {
20908
- gte: formatDate(queryRange.dateRange.start),
20909
- }),
20910
- ...(queryRange.dateRange.end && {
20911
- lte: formatDate(queryRange.dateRange.end),
20912
- }),
20913
- format: 'yyyy-MM-dd',
20914
- },
20915
- },
20916
- },
20972
+ ...queryRanges.map(([searchField, dateRange]) => this.buildDateRangeQuery(searchField, dateRange)),
20917
20973
  spatialFilterExtent && {
20918
20974
  geo_shape: {
20919
20975
  geom: {
@@ -21199,6 +21255,12 @@ class ElasticsearchService {
21199
21255
  order: {
21200
21256
  [`_${aggregation.sort[1]}`]: aggregation.sort[0],
21201
21257
  },
21258
+ ...(aggregation.includeValues && {
21259
+ include: aggregation.includeValues,
21260
+ }),
21261
+ ...(aggregation.excludeValues && {
21262
+ exclude: aggregation.excludeValues,
21263
+ }),
21202
21264
  },
21203
21265
  };
21204
21266
  case 'histogram':
@@ -22587,48 +22649,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
22587
22649
  type: Injectable
22588
22650
  }] });
22589
22651
 
22590
- const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider');
22591
- class GeocodingService {
22592
- constructor() {
22593
- this.provider = inject(GEOCODING_PROVIDER);
22594
- }
22595
- query(text) {
22596
- let queryObservable;
22597
- switch (this.provider[0]) {
22598
- case 'geoadmin':
22599
- queryObservable = from(queryGeoadmin(text, this.provider[1]));
22600
- break;
22601
- case 'geonames':
22602
- queryObservable = from(queryGeonames(text, this.provider[1]));
22603
- break;
22604
- case 'data-gouv-fr':
22605
- queryObservable = from(queryDataGouvFr(text, this.provider[1]));
22606
- break;
22607
- default:
22608
- return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
22609
- }
22610
- return queryObservable.pipe(catchError((error) => throwError(error)));
22611
- }
22612
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22613
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
22614
- }
22615
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
22616
- type: Injectable,
22617
- args: [{
22618
- providedIn: 'root',
22619
- }]
22620
- }] });
22621
-
22622
22652
  class FeatureMapModule {
22623
22653
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
22624
22654
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, imports: [i1.StoreFeatureModule] }); }
22625
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [
22626
- MapFacade,
22627
- {
22628
- provide: GEOCODING_PROVIDER,
22629
- useValue: ['geonames', { maxRows: 5 }],
22630
- },
22631
- ], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
22655
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [MapFacade], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
22632
22656
  }
22633
22657
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, decorators: [{
22634
22658
  type: NgModule,
@@ -22636,13 +22660,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
22636
22660
  imports: [
22637
22661
  StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
22638
22662
  ],
22639
- providers: [
22640
- MapFacade,
22641
- {
22642
- provide: GEOCODING_PROVIDER,
22643
- useValue: ['geonames', { maxRows: 5 }],
22644
- },
22645
- ],
22663
+ providers: [MapFacade],
22646
22664
  }]
22647
22665
  }] });
22648
22666
 
@@ -23085,1114 +23103,406 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
23085
23103
  }]
23086
23104
  }] });
23087
23105
 
23088
- const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
23089
- const path = base ? `${base}.${curr}` : curr;
23090
- const val = obj[curr];
23091
- if (keepLevel) {
23092
- return { ...prev, [path]: flatten('', val) };
23106
+ class AnchorLinkDirective {
23107
+ constructor() {
23108
+ this.changeDetector = inject(ChangeDetectorRef);
23109
+ this.disabled = false;
23110
+ this.observer = new MutationObserver(() => {
23111
+ this.refreshDisabledState();
23112
+ });
23113
+ this.inView = false;
23114
+ this.initialized = false;
23093
23115
  }
23094
- else if (typeof val === 'object' && !Array.isArray(val)) {
23095
- return {
23096
- ...prev,
23097
- ...flatten(path, val),
23098
- };
23116
+ get elementClass() {
23117
+ if (this.disabled) {
23118
+ return this.disabledClass;
23119
+ }
23120
+ if (this.inView) {
23121
+ return `${this.inViewClass} ${this.enabledClass}`;
23122
+ }
23123
+ else {
23124
+ return `${this.outOfViewClass} ${this.enabledClass}`;
23125
+ }
23099
23126
  }
23100
- else {
23101
- return { ...prev, [path]: val };
23127
+ ngOnInit() {
23128
+ this.observer.observe(document.body, {
23129
+ childList: true,
23130
+ subtree: true,
23131
+ });
23132
+ this.refreshDisabledState();
23102
23133
  }
23103
- }, {});
23104
- const checkKeys = (input, mandatory, optional) => {
23105
- const keys = Object.keys(input);
23106
- const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
23107
- const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
23108
- return {
23109
- missing,
23110
- unrecognized,
23111
- };
23112
- };
23113
- /**
23114
- * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
23115
- * pushes warnings and errors to the given arrays; returns null in case of error
23116
- */
23117
- function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23118
- if (typeof fullConfigObj[sectionName] !== 'object') {
23119
- if (mandatoryKeys.length === 0)
23120
- return null;
23121
- outErrors.push(`The [${sectionName}] mandatory section is missing.`);
23122
- return null;
23134
+ ngAfterViewChecked() {
23135
+ if (!this.initialized && !this.disabled) {
23136
+ const target = document.getElementById(this.targetId);
23137
+ if (target) {
23138
+ this.initializeIntersectionObserver(target);
23139
+ this.initialized = true;
23140
+ }
23141
+ }
23123
23142
  }
23124
- const sectionConf = fullConfigObj[sectionName];
23125
- const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
23126
- if (keysCheck.missing.length) {
23127
- // note: this is not thrown to allow merging several Errors down the line
23128
- outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
23129
- return null;
23143
+ initializeIntersectionObserver(target) {
23144
+ this.intersectionObserver = new IntersectionObserver((entries) => {
23145
+ entries.forEach((entry) => {
23146
+ this.inView = entry.isIntersecting;
23147
+ this.changeDetector.detectChanges();
23148
+ });
23149
+ }, {
23150
+ root: null,
23151
+ rootMargin: '-30% 0% -60% 0%',
23152
+ });
23153
+ this.intersectionObserver.observe(target);
23130
23154
  }
23131
- else if (keysCheck.unrecognized.length) {
23132
- outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
23133
- keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
23155
+ ngOnDestroy() {
23156
+ this.observer.disconnect();
23157
+ if (this.intersectionObserver) {
23158
+ this.intersectionObserver.disconnect();
23159
+ }
23134
23160
  }
23135
- return sectionConf;
23161
+ refreshDisabledState() {
23162
+ const targetNotPresent = !document.getElementById(this.targetId);
23163
+ if (targetNotPresent !== this.disabled) {
23164
+ this.disabled = targetNotPresent;
23165
+ this.changeDetector.detectChanges();
23166
+ }
23167
+ }
23168
+ scrollToTarget() {
23169
+ const target = document.getElementById(this.targetId);
23170
+ if (!target)
23171
+ return;
23172
+ target.scrollIntoView({
23173
+ behavior: 'smooth',
23174
+ block: 'start',
23175
+ });
23176
+ }
23177
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23178
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: AnchorLinkDirective, isStandalone: true, selector: "[gnUiAnchorLink]", inputs: { targetId: ["gnUiAnchorLink", "targetId"], disabledClass: ["gnUiAnchorLinkDisabledClass", "disabledClass"], enabledClass: ["gnUiAnchorLinkEnabledClass", "enabledClass"], inViewClass: ["gnUiAnchorLinkInViewClass", "inViewClass"], outOfViewClass: ["gnUiAnchorLinkOutOfViewClass", "outOfViewClass"] }, host: { listeners: { "click": "scrollToTarget()" }, properties: { "class": "this.elementClass" } }, ngImport: i0 }); }
23136
23179
  }
23137
- /**
23138
- * Same as parseConfigSection but keeps all keys, recognized or not
23139
- * Also the first level is the language code (e.g. 'en')
23140
- * This is optional
23141
- */
23142
- function parseTranslationsConfigSection(fullConfigObj, sectionName) {
23143
- if (typeof fullConfigObj[sectionName] !== 'object') {
23144
- return {};
23180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23181
+ type: Directive,
23182
+ args: [{
23183
+ selector: '[gnUiAnchorLink]',
23184
+ standalone: true,
23185
+ }]
23186
+ }], propDecorators: { targetId: [{
23187
+ type: Input,
23188
+ args: ['gnUiAnchorLink']
23189
+ }], disabledClass: [{
23190
+ type: Input,
23191
+ args: ['gnUiAnchorLinkDisabledClass']
23192
+ }], enabledClass: [{
23193
+ type: Input,
23194
+ args: ['gnUiAnchorLinkEnabledClass']
23195
+ }], inViewClass: [{
23196
+ type: Input,
23197
+ args: ['gnUiAnchorLinkInViewClass']
23198
+ }], outOfViewClass: [{
23199
+ type: Input,
23200
+ args: ['gnUiAnchorLinkOutOfViewClass']
23201
+ }], elementClass: [{
23202
+ type: HostBinding,
23203
+ args: ['class']
23204
+ }], scrollToTarget: [{
23205
+ type: HostListener,
23206
+ args: ['click']
23207
+ }] } });
23208
+
23209
+ class PaginationDotsComponent {
23210
+ constructor() {
23211
+ this.containerClass = '';
23145
23212
  }
23146
- return flatten('', fullConfigObj[sectionName], true);
23213
+ // 1-based
23214
+ get steps() {
23215
+ return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23216
+ }
23217
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23218
+ 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: [
23219
+ provideIcons({
23220
+ iconoirNavArrowRight,
23221
+ iconoirNavArrowLeft,
23222
+ }),
23223
+ ] }); }
23147
23224
  }
23148
- /**
23149
- * Same as parseConfigSection but handles an array of configs; this is
23150
- * considered optional; returns null in case of error in at least one of
23151
- * the sections
23152
- */
23153
- function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23154
- const sections = fullConfigObj[sectionName];
23155
- if (!sections) {
23156
- return [];
23225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23226
+ type: Component,
23227
+ args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23228
+ provideIcons({
23229
+ iconoirNavArrowRight,
23230
+ iconoirNavArrowLeft,
23231
+ }),
23232
+ ], 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"] }]
23233
+ }], propDecorators: { listComponent: [{
23234
+ type: Input
23235
+ }], containerClass: [{
23236
+ type: Input
23237
+ }] } });
23238
+
23239
+ class CarouselComponent {
23240
+ constructor() {
23241
+ this.changeDetector = inject(ChangeDetectorRef);
23242
+ this.containerClass = '';
23243
+ this.stepsContainerClass = 'w-full bottom-0 top-auto';
23244
+ this.currentStepChange = new EventEmitter();
23245
+ this.steps = [];
23246
+ this.currentStep = 0;
23247
+ this.refreshSteps = () => {
23248
+ this.steps = this.emblaApi.scrollSnapList();
23249
+ this.currentStep = this.emblaApi.selectedScrollSnap();
23250
+ this.currentStepChange.emit(this.currentStep);
23251
+ this.changeDetector.detectChanges();
23252
+ };
23157
23253
  }
23158
- if (!Array.isArray(sections)) {
23159
- outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
23160
- return null;
23254
+ // Paginable API
23255
+ get isFirstPage() {
23256
+ return this.currentStep === 0;
23161
23257
  }
23162
- const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
23163
- if (result.some((r) => r === null)) {
23164
- return null;
23258
+ get isLastPage() {
23259
+ return this.currentStep === this.steps.length - 1;
23165
23260
  }
23166
- return result;
23167
- }
23168
- function checkMetadataLanguage(parsedConfigSection, outWarnings) {
23169
- const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
23170
- if (lang2?.length !== 2) {
23171
- outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
23261
+ get currentPage() {
23262
+ return this.currentStep + 1; // this is 1-based
23172
23263
  }
23173
- return parsedConfigSection;
23174
- }
23175
- function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
23176
- const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
23177
- if (!(lang2 in LANG_2_TO_3_MAPPER)) {
23178
- outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
23179
- return {
23180
- ...parsedConfigSection,
23181
- new_record_default_language: undefined,
23182
- };
23264
+ get pagesCount() {
23265
+ return this.steps.length;
23183
23266
  }
23184
- return {
23185
- ...parsedConfigSection,
23186
- new_record_default_language: lang2,
23187
- };
23188
- }
23189
- function checkNewRecordStandard(parsedConfigSection, outWarnings) {
23190
- const standard = parsedConfigSection.new_record_standard;
23191
- const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
23192
- if (normalizedStandard === 'iso19139' ||
23193
- normalizedStandard === 'iso19115-3') {
23194
- return {
23195
- ...parsedConfigSection,
23196
- new_record_standard: normalizedStandard,
23197
- };
23267
+ goToPage(stepIndex) {
23268
+ this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23198
23269
  }
23199
- outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
23200
- return {
23201
- ...parsedConfigSection,
23202
- new_record_standard: undefined,
23203
- };
23270
+ goToPrevPage() {
23271
+ if (this.isFirstPage)
23272
+ return;
23273
+ this.emblaApi.scrollPrev();
23274
+ }
23275
+ goToNextPage() {
23276
+ if (this.isLastPage)
23277
+ return;
23278
+ this.emblaApi.scrollNext();
23279
+ }
23280
+ ngAfterViewInit() {
23281
+ this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23282
+ duration: 15,
23283
+ });
23284
+ this.emblaApi
23285
+ .on('init', this.refreshSteps)
23286
+ .on('reInit', this.refreshSteps)
23287
+ .on('select', this.refreshSteps);
23288
+ }
23289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23290
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: CarouselComponent, isStandalone: true, selector: "gn-ui-carousel", inputs: { containerClass: "containerClass", stepsContainerClass: "stepsContainerClass" }, outputs: { currentStepChange: "currentStepChange" }, viewQueries: [{ propertyName: "carouselOverflowContainer", first: true, predicate: ["carouselOverflowContainer"], descendants: true }], ngImport: i0, template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23204
23291
  }
23292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23293
+ type: Component,
23294
+ 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"] }]
23295
+ }], propDecorators: { carouselOverflowContainer: [{
23296
+ type: ViewChild,
23297
+ args: ['carouselOverflowContainer']
23298
+ }], containerClass: [{
23299
+ type: Input
23300
+ }], stepsContainerClass: [{
23301
+ type: Input
23302
+ }], currentStepChange: [{
23303
+ type: Output
23304
+ }] } });
23205
23305
 
23206
- /**
23207
- * This loader extends the default one based on JSON files but also loads custom translations
23208
- * defined in the app configuration
23209
- * Implements a fallback on default lang if translated labels are empty
23210
- */
23211
- class FileWithOverridesTranslateLoader extends FileTranslateLoader {
23212
- getTranslation(lang) {
23213
- const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
23214
- return super.getTranslation(baseLang).pipe(map$1((translations) => ({
23215
- ...translations,
23216
- ...getCustomTranslations(baseLang),
23217
- })));
23306
+ class ProgressBarComponent {
23307
+ constructor() {
23308
+ this.value = 0;
23309
+ this.type = 'default';
23310
+ }
23311
+ get progress() {
23312
+ return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
23313
+ }
23314
+ get color() {
23315
+ switch (this.type) {
23316
+ case 'default':
23317
+ return {
23318
+ outerBar: 'bg-gray-200',
23319
+ innerBar: 'bg-gray-100',
23320
+ text: 'text-gray-900',
23321
+ };
23322
+ case 'primary':
23323
+ return {
23324
+ outerBar: 'bg-primary',
23325
+ innerBar: 'bg-primary-lighter',
23326
+ text: 'text-white',
23327
+ };
23328
+ case 'secondary':
23329
+ return {
23330
+ outerBar: 'bg-secondary',
23331
+ innerBar: 'bg-secondary-lighter',
23332
+ text: 'text-white',
23333
+ };
23334
+ case 'light':
23335
+ return {
23336
+ outerBar: 'bg-primary-white',
23337
+ innerBar: 'bg-primary',
23338
+ text: 'text-main',
23339
+ };
23340
+ }
23218
23341
  }
23342
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23343
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ProgressBarComponent, isStandalone: true, selector: "gn-ui-progress-bar", inputs: { value: "value", type: "type" }, ngImport: i0, template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }); }
23219
23344
  }
23345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
23346
+ type: Component,
23347
+ 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"] }]
23348
+ }], propDecorators: { value: [{
23349
+ type: Input
23350
+ }], type: [{
23351
+ type: Input
23352
+ }] } });
23220
23353
 
23221
- const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
23222
- This error might show up in case of an invalid/malformed configuration file.
23223
-
23224
- Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
23225
- let globalConfig = null;
23226
- function getGlobalConfig() {
23227
- if (globalConfig === null)
23228
- throw new Error(MISSING_CONFIG_ERROR);
23229
- return globalConfig;
23230
- }
23231
- let themeConfig = null;
23232
- function getThemeConfig() {
23233
- if (themeConfig === null)
23234
- throw new Error(MISSING_CONFIG_ERROR);
23235
- return themeConfig;
23236
- }
23237
- let mapConfig = null;
23238
- function getOptionalMapConfig() {
23239
- return mapConfig;
23240
- }
23241
- let searchConfig = null;
23242
- function getOptionalSearchConfig() {
23243
- return searchConfig;
23244
- }
23245
- let editorConfig = null;
23246
- function getOptionalEditorConfig() {
23247
- return editorConfig;
23248
- }
23249
- let metadataQualityConfig = null;
23250
- function getMetadataQualityConfig() {
23251
- return (metadataQualityConfig ||
23252
- {
23253
- ENABLED: false,
23354
+ class PopoverComponent {
23355
+ constructor() {
23356
+ this.viewContainerRef = inject(ViewContainerRef);
23357
+ this.renderer = inject(Renderer2);
23358
+ }
23359
+ getContent() {
23360
+ if (this.content instanceof TemplateRef) {
23361
+ if (this.view) {
23362
+ this.view.destroy();
23363
+ }
23364
+ this.view = this.viewContainerRef.createEmbeddedView(this.content);
23365
+ this.view.detectChanges();
23366
+ const wrapper = this.renderer.createElement('div'); // Create a wrapper div
23367
+ this.view.rootNodes.forEach((node) => {
23368
+ this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
23369
+ });
23370
+ return wrapper;
23371
+ }
23372
+ return this.content;
23373
+ }
23374
+ ngAfterViewInit() {
23375
+ this.tippyInstance = tippy(this.popoverContent.nativeElement, {
23376
+ content: this.getContent(),
23377
+ allowHTML: true,
23378
+ theme: this.theme,
23254
23379
  });
23255
- }
23256
- let customTranslations = null;
23257
- function getCustomTranslations(langCode) {
23258
- if (customTranslations === null)
23259
- throw new Error(MISSING_CONFIG_ERROR);
23260
- return langCode in customTranslations ? customTranslations[langCode] : {};
23261
- }
23262
- let appConfigLoaded = false;
23263
- function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
23264
- console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
23265
- return fetch(configUrl)
23266
- .then((resp) => {
23267
- if (!resp.ok)
23268
- throw new Error('Configuration file could not be loaded');
23269
- return resp.text();
23270
- })
23271
- .then((conf) => {
23272
- let parsed;
23273
- try {
23274
- parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
23380
+ }
23381
+ ngOnChanges(changes) {
23382
+ if (changes['theme']) {
23383
+ this.theme = changes['theme'].currentValue;
23384
+ if (this.tippyInstance) {
23385
+ this.tippyInstance.setProps({ theme: this.theme });
23386
+ }
23275
23387
  }
23276
- catch (e) {
23277
- throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
23388
+ if (changes['content']) {
23389
+ this.content = changes['content'].currentValue;
23390
+ if (this.tippyInstance) {
23391
+ this.tippyInstance.setContent(this.getContent());
23392
+ }
23278
23393
  }
23279
- const errors = [];
23280
- const warnings = [];
23281
- let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
23282
- 'datahub_url',
23283
- 'edit_url_template',
23284
- 'proxy_path',
23285
- 'metadata_language',
23286
- 'login_url',
23287
- 'logout_url',
23288
- 'settings_url',
23289
- 'web_component_embedder_url',
23290
- 'languages',
23291
- 'contact_email',
23292
- 'reuse_form_url',
23293
- ], warnings, errors);
23294
- if (parsedGlobalSection?.metadata_language) {
23295
- parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
23296
- }
23297
- globalConfig =
23298
- parsedGlobalSection === null
23299
- ? null
23300
- : {
23301
- GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
23302
- DATAHUB_URL: parsedGlobalSection.datahub_url,
23303
- EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
23304
- PROXY_PATH: parsedGlobalSection.proxy_path,
23305
- METADATA_LANGUAGE: parsedGlobalSection.metadata_language
23306
- ? parsedGlobalSection.metadata_language.toLowerCase()
23307
- : undefined,
23308
- LOGIN_URL: parsedGlobalSection.login_url,
23309
- LOGOUT_URL: parsedGlobalSection.logout_url,
23310
- SETTINGS_URL: parsedGlobalSection.settings_url,
23311
- WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
23312
- LANGUAGES: parsedGlobalSection.languages,
23313
- CONTACT_EMAIL: parsedGlobalSection.contact_email,
23314
- REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
23315
- };
23316
- const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
23317
- const parsedMapSection = parseConfigSection(parsed, 'map', [], [
23318
- 'max_zoom',
23319
- 'do_not_tile_wms',
23320
- 'max_extent',
23321
- 'max_feature_count',
23322
- 'baselayer',
23323
- 'do_not_use_default_basemap',
23324
- 'external_viewer_url_template',
23325
- 'external_viewer_open_new_tab',
23326
- ], warnings, errors);
23327
- mapConfig =
23328
- parsedMapSection === null || parsedLayersSections === null
23329
- ? null
23330
- : {
23331
- MAX_ZOOM: parsedMapSection.max_zoom,
23332
- DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
23333
- MAX_EXTENT: parsedMapSection.max_extent,
23334
- MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
23335
- EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
23336
- EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
23337
- DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
23338
- MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
23339
- TYPE: map_layer.type,
23340
- URL: map_layer.url,
23341
- NAME: map_layer.name,
23342
- DATA: map_layer.data,
23343
- STYLE_URL: map_layer.styleUrl,
23344
- ACCESS_TOKEN: map_layer.accessToken,
23345
- })),
23346
- };
23347
- const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
23348
- 'header_foreground_color',
23349
- 'main_font',
23350
- 'title_font',
23351
- 'fonts_stylesheet_url',
23352
- 'thumbnail_placeholder',
23353
- 'header_background',
23354
- 'favicon',
23355
- ], warnings, errors);
23356
- themeConfig =
23357
- parsedThemeSection === null
23358
- ? null
23359
- : {
23360
- PRIMARY_COLOR: parsedThemeSection.primary_color,
23361
- SECONDARY_COLOR: parsedThemeSection.secondary_color,
23362
- MAIN_COLOR: parsedThemeSection.main_color,
23363
- BACKGROUND_COLOR: parsedThemeSection.background_color,
23364
- HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
23365
- THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
23366
- HEADER_BACKGROUND: parsedThemeSection.header_background,
23367
- TITLE_FONT: parsedThemeSection.title_font,
23368
- MAIN_FONT: parsedThemeSection.main_font,
23369
- FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
23370
- FAVICON: parsedThemeSection.favicon,
23371
- };
23372
- const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
23373
- 'record_kind_quick_filter',
23374
- 'filter_geometry_data',
23375
- 'filter_geometry_url',
23376
- 'do_not_use_default_search_preset',
23377
- 'search_preset',
23378
- 'advanced_filters',
23379
- 'limit',
23380
- 'spatial_extent_max_file_size',
23381
- ], warnings, errors);
23382
- const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
23383
- searchConfig =
23384
- parsedSearchSection === null
23385
- ? null
23386
- : {
23387
- RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
23388
- FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
23389
- FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
23390
- DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
23391
- SEARCH_PRESET: parsedSearchParams.map((param) => ({
23392
- sort: param.sort,
23393
- name: param.name,
23394
- filters: param.filters,
23395
- })),
23396
- ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
23397
- LIMIT: parsedSearchSection.limit,
23398
- SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
23399
- };
23400
- const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
23401
- metadataQualityConfig =
23402
- parsedMetadataQualitySection === null
23403
- ? null
23404
- : {
23405
- ENABLED: parsedMetadataQualitySection.enabled,
23406
- SORTABLE: parsedMetadataQualitySection.sortable,
23407
- };
23408
- let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
23409
- if (parsedEditingSection !== null &&
23410
- parsedEditingSection.new_record_default_language !== undefined) {
23411
- parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
23412
- }
23413
- if (parsedEditingSection !== null &&
23414
- parsedEditingSection.new_record_standard !== undefined) {
23415
- parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
23416
- }
23417
- editorConfig =
23418
- parsedEditingSection === null
23419
- ? null
23420
- : {
23421
- NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
23422
- NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
23423
- };
23424
- customTranslations = parseTranslationsConfigSection(parsed, 'translations');
23425
- if (errors.length) {
23426
- throw new Error(`One or more mandatory settings were missing from the configuration file.
23427
- ${errors.join('\n')}`);
23394
+ }
23395
+ ngOnDestroy() {
23396
+ if (this.tippyInstance) {
23397
+ this.tippyInstance.destroy();
23428
23398
  }
23429
- else if (warnings.length) {
23430
- console.warn(`One or more unexpected settings were encountered in the configuration file.
23431
- ${warnings.join('\n')}`);
23399
+ if (this.view) {
23400
+ this.view.destroy();
23432
23401
  }
23433
- appConfigLoaded = true;
23434
- });
23435
- }
23436
- function isConfigLoaded() {
23437
- return appConfigLoaded;
23438
- }
23439
- function _reset() {
23440
- globalConfig = null;
23441
- themeConfig = null;
23442
- editorConfig = null;
23443
- customTranslations = null;
23402
+ }
23403
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23404
+ 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: [""] }); }
23444
23405
  }
23445
- const TRANSLATE_WITH_OVERRIDES_CONFIG = {
23446
- compiler: {
23447
- provide: TranslateCompiler,
23448
- useClass: TranslateMessageFormatCompiler,
23449
- },
23450
- loader: [
23451
- {
23452
- provide: TRANSLATE_HTTP_LOADER_CONFIG,
23453
- useValue: {
23454
- prefix: './assets/i18n/',
23455
- suffix: '.json',
23456
- },
23457
- },
23458
- {
23459
- provide: TranslateLoader,
23460
- useClass: FileWithOverridesTranslateLoader,
23461
- deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
23462
- },
23463
- ],
23464
- };
23465
-
23466
- const okAppConfigFixture = () => `
23467
- [global]
23468
- geonetwork4_api_url = "/geonetwork/srv/api"
23469
- proxy_path = "/proxy/?url="
23470
- metadata_language = "fre"
23471
- login_url = "/cas/login?service="
23472
- logout_url = "/geonetwork/signout"
23473
- settings_url = "/geonetwork/settings"
23474
- web_component_embedder_url = "/datahub/wc-embedder.html"
23475
-
23476
- [map]
23477
- max_zoom = 10
23478
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23479
- do_not_use_default_basemap = false
23480
- external_viewer_url_template = 'https://example.com/myviewer?'
23481
- external_viewer_open_new_tab = true
23482
- [[map_layer]]
23483
- type = "wms"
23484
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23485
- name = "masque_hdf_ign_carto_latin1"
23486
- [[map_layer]]
23487
- type = "wfs"
23488
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23489
- name = "masque_hdf_ign_carto_latin1"
23490
-
23491
- [theme]
23492
- primary_color = "#093564"
23493
- secondary_color = "#c2e9dc"
23494
- main_color = "#212029" # All-purpose text color
23495
- background_color = "#fdfbff"
23496
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23497
- header_background = 'teal'
23498
- header_foreground_color = "#872e2e"
23499
- main_font = 'sans-serif'
23500
- title_font = 'serif'
23501
- fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
23502
-
23503
- [search]
23504
- record_kind_quick_filter = false
23505
- filter_geometry_url = 'https://my.domain.org/geom.json'
23506
- do_not_use_default_search_preset = false
23507
- advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license']
23508
-
23509
- [[search_preset]]
23510
- sort = "-createDate"
23511
- name = 'filterByOrgs'
23512
- filters.q = 'Carto'
23513
- filters.organisation = ['Org1', 'Org2']
23514
- filters.format = ['ESRI Shapefile']
23515
- filters.topic = ['boundaries']
23516
- filters.publicationYear = ['2023', '2022']
23517
- filters.spatial = ['yes']
23518
-
23519
- [translations.en]
23520
- "my.first.key" = 'First label.'
23521
- "my.second.key" = """
23522
- Second label,
23523
- on two lines."""
23524
-
23525
- [translations.de]
23526
- my.first.key = 'Erste Etikett.'
23527
-
23528
- [translations.fr]
23529
- my.sample.text = "Un bon exemple de texte."
23530
- "my.quoted.text" = 'du texte entre guillements.'
23531
- `;
23532
- const appConfigWithTranslationFixture = () => okAppConfigFixture();
23533
- const minimalAppConfigFixture = () => `
23534
- [global]
23535
- geonetwork4_api_url = "/geonetwork/srv/api"
23536
- proxy_path = "/proxy/?url="
23406
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
23407
+ type: Component,
23408
+ args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
23409
+ }], propDecorators: { popoverContent: [{
23410
+ type: ViewChild,
23411
+ args: ['popoverContent', { static: false }]
23412
+ }], content: [{
23413
+ type: Input
23414
+ }], theme: [{
23415
+ type: Input
23416
+ }] } });
23537
23417
 
23538
- [theme]
23539
- primary_color = "#093564"
23540
- secondary_color = "#c2e9dc"
23541
- main_color = "#212029" # All-purpose text color
23542
- background_color = "#fdfbff"
23543
- `;
23544
- const mapConfigFixture = () => ({
23545
- MAX_ZOOM: 10,
23546
- MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
23547
- DO_NOT_USE_DEFAULT_BASEMAP: false,
23548
- DO_NOT_TILE_WMS: false,
23549
- EXTERNAL_VIEWER_URL_TEMPLATE: 'https://example.com/myviewer/#/?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["${layer_name}"],"sources":[{"url":"${service_url}","type":"${service_type}"}]}]',
23550
- EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
23551
- MAP_LAYERS: [
23552
- {
23553
- TYPE: 'xyz',
23554
- URL: 'https://some-basemap-server',
23555
- },
23556
- {
23557
- TYPE: 'wms',
23558
- URL: 'https://some-wms-server',
23559
- NAME: 'some_layername',
23560
- },
23561
- {
23562
- TYPE: 'wfs',
23563
- URL: 'https://some-wfs-server',
23564
- NAME: 'some_layername',
23565
- },
23566
- ],
23567
- });
23568
- const malformedConfigFixture = () => `
23569
- {
23570
- "I thought": "we were still doing json"
23418
+ class LoadingMaskComponent {
23419
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23420
+ 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 }); }
23571
23421
  }
23572
- `;
23573
- const missingMandatoryConfigFixture = () => `
23574
- [theme]
23575
- primary_color = "#093564"
23576
- secondary_color = "#c2e9dc"
23577
- background_color = "#fdfbff"
23578
- main_font = 'sans-serif'
23579
- `;
23580
- const wrongLanguageCodeConfigFixture = () => `
23581
- [global]
23582
- geonetwork4_api_url = "/geonetwork/srv/api"
23583
- proxy_path = "/proxy/?url="
23584
- metadata_language = "abc"
23585
-
23586
- [map]
23587
-
23588
- [theme]
23589
- primary_color = "#093564"
23590
- secondary_color = "#c2e9dc"
23591
- main_color = "#212029" # All-purpose text color
23592
- background_color = "#fdfbff"
23593
- `;
23594
- const unrecognizedKeysConfigFixture = () => `
23595
- [global]
23596
- geonetwork4_api_url = "/geonetwork/srv/api"
23597
- proxy_path = "/proxy/?url="
23598
- metadata_language = "fre"
23599
- another_path = '/whatever'
23600
-
23601
- [map]
23602
- max_zoom = 10
23603
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23604
- do_not_use_default_basemap = false
23605
- external_viewer_url_template = 'https://example.com/myviewer?'
23606
- external_viewer_open_new_tab = true
23607
- another_zoom = 15
23608
- [[map_layer]]
23609
- type = "wms"
23610
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23611
- name = "masque_hdf_ign_carto_latin1"
23612
- [[map_layer]]
23613
- type = "wfs"
23614
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23615
- name = "masque_hdf_ign_carto_latin1"
23616
- another_layer = "wrong layer definition"
23617
-
23618
- [theme]
23619
- primary_color = "#093564"
23620
- secondary_color = "#c2e9dc"
23621
- main_color = "#212029" # All-purpose text color
23622
- background_color = "#fdfbff"
23623
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23624
- header_background = 'teal'
23625
- header_foreground_color = "#872e2e"
23626
- main_font = 'sans-serif'
23627
- title_font = 'serif'
23628
- another_color = 'red'
23629
- `;
23422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
23423
+ type: Component,
23424
+ 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"] }]
23425
+ }], propDecorators: { message: [{
23426
+ type: Input
23427
+ }] } });
23630
23428
 
23631
- function getMapContextLayerFromConfig(config) {
23632
- switch (config.TYPE) {
23633
- case 'wms':
23634
- return {
23635
- type: 'wms',
23636
- url: config.URL,
23637
- name: config.NAME,
23638
- };
23639
- case 'wfs':
23640
- return {
23641
- type: 'wfs',
23642
- url: config.URL,
23643
- featureType: config.NAME,
23644
- };
23645
- case 'xyz':
23646
- return {
23647
- type: config.TYPE,
23648
- url: config.URL,
23649
- };
23650
- case 'geojson':
23651
- return {
23652
- type: config.TYPE,
23653
- ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
23654
- };
23655
- case 'maplibre-style':
23656
- return {
23657
- type: config.TYPE,
23658
- styleUrl: config.STYLE_URL,
23659
- accessToken: config.ACCESS_TOKEN,
23660
- };
23661
- }
23429
+ class ColorScaleComponent {
23430
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23431
+ 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: [""] }); }
23662
23432
  }
23433
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
23434
+ type: Component,
23435
+ 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" }]
23436
+ }] });
23663
23437
 
23664
- class MapStyleService {
23438
+ class PopupAlertComponent {
23665
23439
  constructor() {
23666
- this.styles = {
23667
- default: this.createStyleFunction(this.createGeometryStyles({
23668
- color: isConfigLoaded() ? getThemeConfig().PRIMARY_COLOR : 'blue',
23669
- })),
23670
- defaultHL: this.createStyleFunction(this.createGeometryStyles({
23671
- color: isConfigLoaded() ? getThemeConfig().SECONDARY_COLOR : 'red',
23672
- isFocused: true,
23673
- })),
23674
- };
23440
+ this.changeDetector = inject(ChangeDetectorRef);
23441
+ this.type = 'info';
23442
+ this.position = 'top';
23443
+ this.expanded = false;
23444
+ this.timeout = null;
23675
23445
  }
23676
- createGeometryStyles(options) {
23677
- const { color, isFocused } = options;
23678
- const zIndex = isFocused ? 10 : undefined;
23679
- return {
23680
- polygon: new Style({
23681
- fill: new Fill({
23682
- color: this.computeTransparentFillColor(color),
23683
- }),
23684
- stroke: new Stroke({
23685
- color: 'white',
23686
- width: 2,
23687
- }),
23688
- zIndex,
23689
- }),
23690
- point: new Style({
23691
- image: new CircleStyle({
23692
- fill: new Fill({
23693
- color,
23694
- }),
23695
- stroke: new Stroke({
23696
- color: 'white',
23697
- width: isFocused ? 3 : 2,
23698
- }),
23699
- radius: isFocused ? 8 : 7,
23700
- }),
23701
- zIndex,
23702
- }),
23703
- line: [
23704
- new Style({
23705
- stroke: new Stroke({
23706
- color: 'white',
23707
- width: isFocused ? 8 : 6,
23708
- }),
23709
- zIndex,
23710
- }),
23711
- new Style({
23712
- stroke: new Stroke({
23713
- color,
23714
- width: isFocused ? 3 : 2,
23715
- }),
23716
- zIndex,
23717
- }),
23718
- ],
23719
- };
23446
+ get showDuration() {
23447
+ const chars = this.content.nativeElement.innerHTML.length;
23448
+ return Math.max(3000, chars * 20);
23720
23449
  }
23721
- createStyleFunction(styleByGeometryType) {
23722
- return (feature) => {
23723
- const geometryType = feature?.getGeometry()?.getType();
23724
- switch (geometryType) {
23725
- case 'LinearRing':
23726
- case 'LineString':
23727
- case 'MultiLineString':
23728
- return styleByGeometryType.line;
23729
- case 'Point':
23730
- case 'MultiPoint':
23731
- return styleByGeometryType.point;
23732
- case 'Circle':
23733
- case 'Polygon':
23734
- case 'MultiPolygon':
23735
- return styleByGeometryType.polygon;
23736
- default:
23737
- return styleByGeometryType.point;
23738
- }
23739
- };
23450
+ ngOnInit() {
23451
+ this.expandAndClose();
23452
+ }
23453
+ expand() {
23454
+ this.expanded = true;
23455
+ this.changeDetector.detectChanges();
23456
+ clearTimeout(this.timeout);
23740
23457
  }
23741
- computeTransparentFillColor(color, alpha = 0.25) {
23742
- return chroma(color).alpha(alpha).css();
23458
+ expandAndClose() {
23459
+ this.expanded = true;
23460
+ this.changeDetector.detectChanges();
23461
+ clearTimeout(this.timeout);
23462
+ this.timeout = setTimeout(() => {
23463
+ this.expanded = false;
23464
+ this.changeDetector.detectChanges();
23465
+ }, this.showDuration);
23743
23466
  }
23744
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23745
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, providedIn: 'root' }); }
23467
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23468
+ 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: [
23469
+ provideIcons({ matErrorOutlineOutline }),
23470
+ provideNgIconsConfig({
23471
+ size: '1.5em',
23472
+ }),
23473
+ ], 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 }); }
23746
23474
  }
23747
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, decorators: [{
23748
- type: Injectable,
23749
- args: [{
23750
- providedIn: 'root',
23751
- }]
23752
- }] });
23475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, decorators: [{
23476
+ type: Component,
23477
+ args: [{ selector: 'gn-ui-popup-alert', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, NgIconComponent], providers: [
23478
+ provideIcons({ matErrorOutlineOutline }),
23479
+ provideNgIconsConfig({
23480
+ size: '1.5em',
23481
+ }),
23482
+ ], 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"] }]
23483
+ }], propDecorators: { icon: [{
23484
+ type: Input
23485
+ }], type: [{
23486
+ type: Input
23487
+ }], position: [{
23488
+ type: Input
23489
+ }], content: [{
23490
+ type: ViewChild,
23491
+ args: ['content']
23492
+ }] } });
23753
23493
 
23754
- const colorPrimary = 'blue';
23755
- const colorSecondary = 'red';
23756
- const colorStroke = 'white';
23757
- const defaultMapStyleFixture = () => new Style({
23758
- image: new Circle({
23759
- fill: new Fill({
23760
- color: colorPrimary,
23761
- }),
23762
- stroke: new Stroke({
23763
- color: colorStroke,
23764
- width: 2,
23765
- }),
23766
- radius: 5,
23767
- }),
23768
- fill: new Fill({
23769
- color: 'rgba(0,0,255,0.25)',
23770
- }),
23771
- stroke: new Stroke({
23772
- color: colorStroke,
23773
- width: 2,
23774
- }),
23775
- });
23776
- const defaultMapStyleHlFixture = () => new Style({
23777
- image: new Circle({
23778
- fill: new Fill({
23779
- color: colorSecondary,
23780
- }),
23781
- stroke: new Stroke({
23782
- color: colorStroke,
23783
- width: 3,
23784
- }),
23785
- radius: 6,
23786
- }),
23787
- fill: new Fill({
23788
- color: 'rgba(255,0,0,0.25)',
23789
- }),
23790
- stroke: new Stroke({
23791
- color: colorSecondary,
23792
- width: 3,
23793
- }),
23794
- });
23494
+ class SpinningLoaderComponent {
23495
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23496
+ 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: [""] }); }
23497
+ }
23498
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, decorators: [{
23499
+ type: Component,
23500
+ 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" }]
23501
+ }] });
23795
23502
 
23796
- class AnchorLinkDirective {
23503
+ class ButtonComponent {
23797
23504
  constructor() {
23798
- this.changeDetector = inject(ChangeDetectorRef);
23799
- this.disabled = false;
23800
- this.observer = new MutationObserver(() => {
23801
- this.refreshDisabledState();
23802
- });
23803
- this.inView = false;
23804
- this.initialized = false;
23805
- }
23806
- get elementClass() {
23807
- if (this.disabled) {
23808
- return this.disabledClass;
23809
- }
23810
- if (this.inView) {
23811
- return `${this.inViewClass} ${this.enabledClass}`;
23812
- }
23813
- else {
23814
- return `${this.outOfViewClass} ${this.enabledClass}`;
23815
- }
23816
- }
23817
- ngOnInit() {
23818
- this.observer.observe(document.body, {
23819
- childList: true,
23820
- subtree: true,
23821
- });
23822
- this.refreshDisabledState();
23823
- }
23824
- ngAfterViewChecked() {
23825
- if (!this.initialized && !this.disabled) {
23826
- const target = document.getElementById(this.targetId);
23827
- if (target) {
23828
- this.initializeIntersectionObserver(target);
23829
- this.initialized = true;
23830
- }
23831
- }
23832
- }
23833
- initializeIntersectionObserver(target) {
23834
- this.intersectionObserver = new IntersectionObserver((entries) => {
23835
- entries.forEach((entry) => {
23836
- this.inView = entry.isIntersecting;
23837
- this.changeDetector.detectChanges();
23838
- });
23839
- }, {
23840
- root: null,
23841
- rootMargin: '-30% 0% -60% 0%',
23842
- });
23843
- this.intersectionObserver.observe(target);
23844
- }
23845
- ngOnDestroy() {
23846
- this.observer.disconnect();
23847
- if (this.intersectionObserver) {
23848
- this.intersectionObserver.disconnect();
23849
- }
23850
- }
23851
- refreshDisabledState() {
23852
- const targetNotPresent = !document.getElementById(this.targetId);
23853
- if (targetNotPresent !== this.disabled) {
23854
- this.disabled = targetNotPresent;
23855
- this.changeDetector.detectChanges();
23856
- }
23857
- }
23858
- scrollToTarget() {
23859
- const target = document.getElementById(this.targetId);
23860
- if (!target)
23861
- return;
23862
- target.scrollIntoView({
23863
- behavior: 'smooth',
23864
- block: 'start',
23865
- });
23866
- }
23867
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23868
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: AnchorLinkDirective, isStandalone: true, selector: "[gnUiAnchorLink]", inputs: { targetId: ["gnUiAnchorLink", "targetId"], disabledClass: ["gnUiAnchorLinkDisabledClass", "disabledClass"], enabledClass: ["gnUiAnchorLinkEnabledClass", "enabledClass"], inViewClass: ["gnUiAnchorLinkInViewClass", "inViewClass"], outOfViewClass: ["gnUiAnchorLinkOutOfViewClass", "outOfViewClass"] }, host: { listeners: { "click": "scrollToTarget()" }, properties: { "class": "this.elementClass" } }, ngImport: i0 }); }
23869
- }
23870
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23871
- type: Directive,
23872
- args: [{
23873
- selector: '[gnUiAnchorLink]',
23874
- standalone: true,
23875
- }]
23876
- }], propDecorators: { targetId: [{
23877
- type: Input,
23878
- args: ['gnUiAnchorLink']
23879
- }], disabledClass: [{
23880
- type: Input,
23881
- args: ['gnUiAnchorLinkDisabledClass']
23882
- }], enabledClass: [{
23883
- type: Input,
23884
- args: ['gnUiAnchorLinkEnabledClass']
23885
- }], inViewClass: [{
23886
- type: Input,
23887
- args: ['gnUiAnchorLinkInViewClass']
23888
- }], outOfViewClass: [{
23889
- type: Input,
23890
- args: ['gnUiAnchorLinkOutOfViewClass']
23891
- }], elementClass: [{
23892
- type: HostBinding,
23893
- args: ['class']
23894
- }], scrollToTarget: [{
23895
- type: HostListener,
23896
- args: ['click']
23897
- }] } });
23898
-
23899
- class PaginationDotsComponent {
23900
- constructor() {
23901
- this.containerClass = '';
23902
- }
23903
- // 1-based
23904
- get steps() {
23905
- return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23906
- }
23907
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23908
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PaginationDotsComponent, isStandalone: true, selector: "gn-ui-pagination-dots", inputs: { listComponent: "listComponent", containerClass: "containerClass" }, ngImport: i0, template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], viewProviders: [
23909
- provideIcons({
23910
- iconoirNavArrowRight,
23911
- iconoirNavArrowLeft,
23912
- }),
23913
- ] }); }
23914
- }
23915
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23916
- type: Component,
23917
- args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23918
- provideIcons({
23919
- iconoirNavArrowRight,
23920
- iconoirNavArrowLeft,
23921
- }),
23922
- ], template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"] }]
23923
- }], propDecorators: { listComponent: [{
23924
- type: Input
23925
- }], containerClass: [{
23926
- type: Input
23927
- }] } });
23928
-
23929
- class CarouselComponent {
23930
- constructor() {
23931
- this.changeDetector = inject(ChangeDetectorRef);
23932
- this.containerClass = '';
23933
- this.stepsContainerClass = 'w-full bottom-0 top-auto';
23934
- this.currentStepChange = new EventEmitter();
23935
- this.steps = [];
23936
- this.currentStep = 0;
23937
- this.refreshSteps = () => {
23938
- this.steps = this.emblaApi.scrollSnapList();
23939
- this.currentStep = this.emblaApi.selectedScrollSnap();
23940
- this.currentStepChange.emit(this.currentStep);
23941
- this.changeDetector.detectChanges();
23942
- };
23943
- }
23944
- // Paginable API
23945
- get isFirstPage() {
23946
- return this.currentStep === 0;
23947
- }
23948
- get isLastPage() {
23949
- return this.currentStep === this.steps.length - 1;
23950
- }
23951
- get currentPage() {
23952
- return this.currentStep + 1; // this is 1-based
23953
- }
23954
- get pagesCount() {
23955
- return this.steps.length;
23956
- }
23957
- goToPage(stepIndex) {
23958
- this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23959
- }
23960
- goToPrevPage() {
23961
- if (this.isFirstPage)
23962
- return;
23963
- this.emblaApi.scrollPrev();
23964
- }
23965
- goToNextPage() {
23966
- if (this.isLastPage)
23967
- return;
23968
- this.emblaApi.scrollNext();
23969
- }
23970
- ngAfterViewInit() {
23971
- this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23972
- duration: 15,
23973
- });
23974
- this.emblaApi
23975
- .on('init', this.refreshSteps)
23976
- .on('reInit', this.refreshSteps)
23977
- .on('select', this.refreshSteps);
23978
- }
23979
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23980
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: CarouselComponent, isStandalone: true, selector: "gn-ui-carousel", inputs: { containerClass: "containerClass", stepsContainerClass: "stepsContainerClass" }, outputs: { currentStepChange: "currentStepChange" }, viewQueries: [{ propertyName: "carouselOverflowContainer", first: true, predicate: ["carouselOverflowContainer"], descendants: true }], ngImport: i0, template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23981
- }
23982
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23983
- type: Component,
23984
- args: [{ selector: 'gn-ui-carousel', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, PaginationDotsComponent], template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"] }]
23985
- }], propDecorators: { carouselOverflowContainer: [{
23986
- type: ViewChild,
23987
- args: ['carouselOverflowContainer']
23988
- }], containerClass: [{
23989
- type: Input
23990
- }], stepsContainerClass: [{
23991
- type: Input
23992
- }], currentStepChange: [{
23993
- type: Output
23994
- }] } });
23995
-
23996
- class ProgressBarComponent {
23997
- constructor() {
23998
- this.value = 0;
23999
- this.type = 'default';
24000
- }
24001
- get progress() {
24002
- return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
24003
- }
24004
- get color() {
24005
- switch (this.type) {
24006
- case 'default':
24007
- return {
24008
- outerBar: 'bg-gray-200',
24009
- innerBar: 'bg-gray-100',
24010
- text: 'text-gray-900',
24011
- };
24012
- case 'primary':
24013
- return {
24014
- outerBar: 'bg-primary',
24015
- innerBar: 'bg-primary-lighter',
24016
- text: 'text-white',
24017
- };
24018
- case 'secondary':
24019
- return {
24020
- outerBar: 'bg-secondary',
24021
- innerBar: 'bg-secondary-lighter',
24022
- text: 'text-white',
24023
- };
24024
- case 'light':
24025
- return {
24026
- outerBar: 'bg-primary-white',
24027
- innerBar: 'bg-primary',
24028
- text: 'text-main',
24029
- };
24030
- }
24031
- }
24032
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24033
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ProgressBarComponent, isStandalone: true, selector: "gn-ui-progress-bar", inputs: { value: "value", type: "type" }, ngImport: i0, template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }); }
24034
- }
24035
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
24036
- type: Component,
24037
- args: [{ selector: 'gn-ui-progress-bar', standalone: true, imports: [], template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }]
24038
- }], propDecorators: { value: [{
24039
- type: Input
24040
- }], type: [{
24041
- type: Input
24042
- }] } });
24043
-
24044
- class PopoverComponent {
24045
- constructor() {
24046
- this.viewContainerRef = inject(ViewContainerRef);
24047
- this.renderer = inject(Renderer2);
24048
- }
24049
- getContent() {
24050
- if (this.content instanceof TemplateRef) {
24051
- if (this.view) {
24052
- this.view.destroy();
24053
- }
24054
- this.view = this.viewContainerRef.createEmbeddedView(this.content);
24055
- this.view.detectChanges();
24056
- const wrapper = this.renderer.createElement('div'); // Create a wrapper div
24057
- this.view.rootNodes.forEach((node) => {
24058
- this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
24059
- });
24060
- return wrapper;
24061
- }
24062
- return this.content;
24063
- }
24064
- ngAfterViewInit() {
24065
- this.tippyInstance = tippy(this.popoverContent.nativeElement, {
24066
- content: this.getContent(),
24067
- allowHTML: true,
24068
- theme: this.theme,
24069
- });
24070
- }
24071
- ngOnChanges(changes) {
24072
- if (changes['theme']) {
24073
- this.theme = changes['theme'].currentValue;
24074
- if (this.tippyInstance) {
24075
- this.tippyInstance.setProps({ theme: this.theme });
24076
- }
24077
- }
24078
- if (changes['content']) {
24079
- this.content = changes['content'].currentValue;
24080
- if (this.tippyInstance) {
24081
- this.tippyInstance.setContent(this.getContent());
24082
- }
24083
- }
24084
- }
24085
- ngOnDestroy() {
24086
- if (this.tippyInstance) {
24087
- this.tippyInstance.destroy();
24088
- }
24089
- if (this.view) {
24090
- this.view.destroy();
24091
- }
24092
- }
24093
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24094
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: PopoverComponent, isStandalone: true, selector: "gn-ui-popover", inputs: { content: "content", theme: "theme" }, viewQueries: [{ propertyName: "popoverContent", first: true, predicate: ["popoverContent"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n", styles: [""] }); }
24095
- }
24096
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
24097
- type: Component,
24098
- args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
24099
- }], propDecorators: { popoverContent: [{
24100
- type: ViewChild,
24101
- args: ['popoverContent', { static: false }]
24102
- }], content: [{
24103
- type: Input
24104
- }], theme: [{
24105
- type: Input
24106
- }] } });
24107
-
24108
- class LoadingMaskComponent {
24109
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24110
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: LoadingMaskComponent, isStandalone: true, selector: "gn-ui-loading-mask", inputs: { message: "message" }, ngImport: i0, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24111
- }
24112
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
24113
- type: Component,
24114
- args: [{ selector: 'gn-ui-loading-mask', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatProgressSpinnerModule], standalone: true, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"] }]
24115
- }], propDecorators: { message: [{
24116
- type: Input
24117
- }] } });
24118
-
24119
- class ColorScaleComponent {
24120
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24121
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: ColorScaleComponent, isStandalone: true, selector: "gn-ui-color-scale", ngImport: i0, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n", styles: [""] }); }
24122
- }
24123
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
24124
- type: Component,
24125
- args: [{ selector: 'gn-ui-color-scale', standalone: true, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n" }]
24126
- }] });
24127
-
24128
- class PopupAlertComponent {
24129
- constructor() {
24130
- this.changeDetector = inject(ChangeDetectorRef);
24131
- this.type = 'info';
24132
- this.position = 'top';
24133
- this.expanded = false;
24134
- this.timeout = null;
24135
- }
24136
- get showDuration() {
24137
- const chars = this.content.nativeElement.innerHTML.length;
24138
- return Math.max(3000, chars * 20);
24139
- }
24140
- ngOnInit() {
24141
- this.expandAndClose();
24142
- }
24143
- expand() {
24144
- this.expanded = true;
24145
- this.changeDetector.detectChanges();
24146
- clearTimeout(this.timeout);
24147
- }
24148
- expandAndClose() {
24149
- this.expanded = true;
24150
- this.changeDetector.detectChanges();
24151
- clearTimeout(this.timeout);
24152
- this.timeout = setTimeout(() => {
24153
- this.expanded = false;
24154
- this.changeDetector.detectChanges();
24155
- }, this.showDuration);
24156
- }
24157
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24158
- 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: [
24159
- provideIcons({ matErrorOutlineOutline }),
24160
- provideNgIconsConfig({
24161
- size: '1.5em',
24162
- }),
24163
- ], 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 }); }
24164
- }
24165
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, decorators: [{
24166
- type: Component,
24167
- args: [{ selector: 'gn-ui-popup-alert', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, NgIconComponent], providers: [
24168
- provideIcons({ matErrorOutlineOutline }),
24169
- provideNgIconsConfig({
24170
- size: '1.5em',
24171
- }),
24172
- ], 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"] }]
24173
- }], propDecorators: { icon: [{
24174
- type: Input
24175
- }], type: [{
24176
- type: Input
24177
- }], position: [{
24178
- type: Input
24179
- }], content: [{
24180
- type: ViewChild,
24181
- args: ['content']
24182
- }] } });
24183
-
24184
- class SpinningLoaderComponent {
24185
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24186
- 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: [""] }); }
24187
- }
24188
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, decorators: [{
24189
- type: Component,
24190
- 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" }]
24191
- }] });
24192
-
24193
- class ButtonComponent {
24194
- constructor() {
24195
- this.btnClass = 'gn-ui-btn-default';
23505
+ this.btnClass = 'gn-ui-btn-default';
24196
23506
  this.disabled = false;
24197
23507
  this.extraClass = '';
24198
23508
  this.buttonClick = new EventEmitter();
@@ -24453,7 +23763,7 @@ class AutocompleteComponent {
24453
23763
  this.enterBtnPosition = event.target['value'].length * 8 + 80;
24454
23764
  }
24455
23765
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24456
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
23766
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithTemplate: "displayWithTemplate", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
24457
23767
  provideIcons({
24458
23768
  iconoirSearch,
24459
23769
  matClose,
@@ -24462,7 +23772,7 @@ class AutocompleteComponent {
24462
23772
  provideNgIconsConfig({
24463
23773
  size: '1.75rem',
24464
23774
  }),
24465
- ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: MatAutocompleteTrigger, descendants: true }, { propertyName: "autocomplete", first: true, predicate: MatAutocomplete, descendants: true }, { propertyName: "inputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"], dependencies: [{ kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i1$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i1$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i1$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23775
+ ], 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 }); }
24466
23776
  }
24467
23777
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
24468
23778
  type: Component,
@@ -24483,7 +23793,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
24483
23793
  provideNgIconsConfig({
24484
23794
  size: '1.75rem',
24485
23795
  }),
24486
- ], template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"] }]
23796
+ ], 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"] }]
24487
23797
  }], propDecorators: { placeholder: [{
24488
23798
  type: Input
24489
23799
  }], enterButton: [{
@@ -24521,6 +23831,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
24521
23831
  }], inputRef: [{
24522
23832
  type: ViewChild,
24523
23833
  args: ['searchInput']
23834
+ }], displayWithTemplate: [{
23835
+ type: Input
24524
23836
  }], displayWithFn: [{
24525
23837
  type: Input
24526
23838
  }] } });
@@ -25005,7 +24317,7 @@ class DropdownMultiselectComponent {
25005
24317
  }
25006
24318
  setFocus() {
25007
24319
  setTimeout(() => {
25008
- this.searchFieldInput.nativeElement.focus();
24320
+ this.searchFieldInput?.nativeElement.focus();
25009
24321
  }, 0);
25010
24322
  }
25011
24323
  openOverlay() {
@@ -25111,7 +24423,10 @@ class DropdownMultiselectComponent {
25111
24423
  matExpandMore,
25112
24424
  matExpandLess,
25113
24425
  }),
25114
- ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24426
+ provideNgIconsConfig({
24427
+ size: '1.5rem',
24428
+ }),
24429
+ ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
25115
24430
  }
25116
24431
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
25117
24432
  type: Component,
@@ -25121,7 +24436,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
25121
24436
  matExpandMore,
25122
24437
  matExpandLess,
25123
24438
  }),
25124
- ], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
24439
+ provideNgIconsConfig({
24440
+ size: '1.5rem',
24441
+ }),
24442
+ ], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
25125
24443
  }], propDecorators: { title: [{
25126
24444
  type: Input
25127
24445
  }], choices: [{
@@ -26036,8 +25354,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26036
25354
  marker('search.filters.spatialExtent.import');
26037
25355
  marker('search.filters.spatialExtent.helpText');
26038
25356
  marker('search.filters.spatialExtent.error.title');
26039
- marker('search.filters.spatialExtent.bboxPrefix');
26040
- marker('search.filters.spatialExtent.bboxDelete');
25357
+ marker('search.filters.spatialExtent.error.outOfBounds');
25358
+ const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
25359
+ const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
25360
+ const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
25361
+ const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
26041
25362
  class SpatialExtentDropdownComponent {
26042
25363
  constructor() {
26043
25364
  this.cd = inject(ChangeDetectorRef);
@@ -26068,9 +25389,23 @@ class SpatialExtentDropdownComponent {
26068
25389
  this.overlayMinWidth = 'none';
26069
25390
  this.errorKey = null;
26070
25391
  }
25392
+ set initialBbox(value) {
25393
+ if (!this.bbox && value) {
25394
+ this.bbox = value;
25395
+ }
25396
+ }
26071
25397
  get hasSelection() {
26072
25398
  return !!this.bbox;
26073
25399
  }
25400
+ get selectionLabelKey() {
25401
+ return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
25402
+ }
25403
+ get selectionDeleteLabelKey() {
25404
+ return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
25405
+ }
25406
+ get selectionLabelParams() {
25407
+ return { fileName: this.fileName };
25408
+ }
26074
25409
  openOverlay() {
26075
25410
  this.overlayMinWidth =
26076
25411
  this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
@@ -26100,6 +25435,10 @@ class SpatialExtentDropdownComponent {
26100
25435
  return;
26101
25436
  }
26102
25437
  const bbox = getGeometryBoundingBox(geometry);
25438
+ if (!isBoundingBoxWithinWorldExtent(bbox)) {
25439
+ this.setError(marker('search.filters.spatialExtent.error.outOfBounds'));
25440
+ return;
25441
+ }
26103
25442
  this.bbox = bbox;
26104
25443
  this.fileName = file.name;
26105
25444
  this.bboxChange.emit(bbox);
@@ -26134,17 +25473,17 @@ class SpatialExtentDropdownComponent {
26134
25473
  propagateToDocumentOnly(event);
26135
25474
  }
26136
25475
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26137
- 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" }, outputs: { bboxChange: "bboxChange", errorChange: "errorChange" }, providers: [
25476
+ 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: [
26138
25477
  provideIcons({
26139
25478
  iconoirCheckCircle,
26140
- iconoirImport,
26141
25479
  iconoirSquareDashed,
26142
25480
  iconoirTrash,
25481
+ iconoirUpload,
26143
25482
  matClose,
26144
25483
  matExpandLess,
26145
25484
  matExpandMore,
26146
25485
  }),
26147
- ], 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]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\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 {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\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 }); }
25486
+ ], 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'\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 </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 }); }
26148
25487
  }
26149
25488
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
26150
25489
  type: Component,
@@ -26157,18 +25496,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26157
25496
  ], providers: [
26158
25497
  provideIcons({
26159
25498
  iconoirCheckCircle,
26160
- iconoirImport,
26161
25499
  iconoirSquareDashed,
26162
25500
  iconoirTrash,
25501
+ iconoirUpload,
26163
25502
  matClose,
26164
25503
  matExpandLess,
26165
25504
  matExpandMore,
26166
25505
  }),
26167
- ], 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]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\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 {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\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" }]
25506
+ ], 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'\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 </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" }]
26168
25507
  }], propDecorators: { title: [{
26169
25508
  type: Input
26170
25509
  }], maxFileSizeMb: [{
26171
25510
  type: Input
25511
+ }], initialBbox: [{
25512
+ type: Input
26172
25513
  }], bboxChange: [{
26173
25514
  type: Output
26174
25515
  }], errorChange: [{
@@ -26688,11 +26029,11 @@ class BlockListComponent {
26688
26029
  this.goToPage(this.currentPage + 1);
26689
26030
  }
26690
26031
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26691
- 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 }); }
26032
+ 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 }); }
26692
26033
  }
26693
26034
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, decorators: [{
26694
26035
  type: Component,
26695
- 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"] }]
26036
+ 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"] }]
26696
26037
  }], propDecorators: { containerClass: [{
26697
26038
  type: Input
26698
26039
  }], paginationContainerClass: [{
@@ -27431,9 +26772,7 @@ const initSearch = () => {
27431
26772
  },
27432
26773
  params: {
27433
26774
  filters: {},
27434
- pageSize: getOptionalSearchConfig()?.LIMIT
27435
- ? getOptionalSearchConfig().LIMIT
27436
- : DEFAULT_PAGE_SIZE,
26775
+ pageSize: DEFAULT_PAGE_SIZE,
27437
26776
  currentPage: 0,
27438
26777
  favoritesOnly: false,
27439
26778
  useSpatialFilter: true,
@@ -27882,6 +27221,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
27882
27221
  }]
27883
27222
  }] });
27884
27223
 
27224
+ const DEFAULT_GEOCODING_PROVIDER = [
27225
+ 'geonames',
27226
+ { maxRows: 5 },
27227
+ ];
27228
+ const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
27229
+ providedIn: 'root',
27230
+ factory: () => DEFAULT_GEOCODING_PROVIDER,
27231
+ });
27232
+ class GeocodingService {
27233
+ constructor() {
27234
+ this.provider = inject(GEOCODING_PROVIDER);
27235
+ }
27236
+ query(text) {
27237
+ let queryObservable;
27238
+ switch (this.provider[0]) {
27239
+ case 'geoadmin':
27240
+ queryObservable = from(queryGeoadmin(text, this.provider[1]));
27241
+ break;
27242
+ case 'geonames':
27243
+ queryObservable = from(queryGeonames(text, this.provider[1]));
27244
+ break;
27245
+ case 'geoplateforme':
27246
+ queryObservable = from(queryGeoplateforme(text, this.provider[1]));
27247
+ break;
27248
+ default:
27249
+ return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
27250
+ }
27251
+ return queryObservable.pipe(catchError((error) => throwError(error)));
27252
+ }
27253
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
27254
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
27255
+ }
27256
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
27257
+ type: Injectable,
27258
+ args: [{
27259
+ providedIn: 'root',
27260
+ }]
27261
+ }] });
27262
+
27263
+ class LocationSearchComponent {
27264
+ constructor() {
27265
+ this.geocodingService = inject(GeocodingService);
27266
+ this.placeholder = '';
27267
+ this.resultSelected = new EventEmitter();
27268
+ this.displayWithFn = (item) => item.label;
27269
+ this.searchAction = (text) => this.geocodingService.query(text);
27270
+ }
27271
+ handleItemSelected(item) {
27272
+ this.resultSelected.emit(item);
27273
+ }
27274
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27275
+ 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 }); }
27276
+ }
27277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
27278
+ type: Component,
27279
+ 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" }]
27280
+ }], propDecorators: { placeholder: [{
27281
+ type: Input
27282
+ }], displayWithTemplate: [{
27283
+ type: Input
27284
+ }], resultSelected: [{
27285
+ type: Output
27286
+ }] } });
27287
+
27885
27288
  // expects the replacement key ${uuid}
27886
27289
  const RECORD_DATASET_URL_TOKEN = new InjectionToken('record-dataset-url-token');
27887
27290
  const RECORD_SERVICE_URL_TOKEN = new InjectionToken('record-service-url-token');
@@ -28040,6 +27443,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28040
27443
  class AbstractSearchField {
28041
27444
  }
28042
27445
  class SimpleSearchField {
27446
+ get fieldIdentifier() {
27447
+ return this.customIdentifier ?? this.esFieldName;
27448
+ }
28043
27449
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
28044
27450
  this.esFieldName = esFieldName;
28045
27451
  this.injector = injector;
@@ -28048,14 +27454,26 @@ class SimpleSearchField {
28048
27454
  this.repository = this.injector.get(RecordsRepositoryInterface);
28049
27455
  // FIXME: this is required to register runtime fields; abstract this as well
28050
27456
  this.esService = this.injector.get(ElasticsearchService);
27457
+ this.includeValues = [];
27458
+ this.excludeValues = [];
27459
+ }
27460
+ setFieldIdentifier(fieldIdentifier) {
27461
+ this.customIdentifier = fieldIdentifier;
27462
+ this.esService.registerFieldAlias(fieldIdentifier, this.esFieldName);
28051
27463
  }
28052
27464
  getAggregations() {
28053
27465
  return {
28054
- [this.esFieldName]: {
27466
+ [this.fieldIdentifier]: {
28055
27467
  type: 'terms',
28056
27468
  field: this.esFieldName,
28057
27469
  limit: 1000,
28058
27470
  sort: [this.order, this.orderType],
27471
+ ...(this.includeValues?.length && {
27472
+ includeValues: this.includeValues,
27473
+ }),
27474
+ ...(this.excludeValues?.length && {
27475
+ excludeValues: this.excludeValues,
27476
+ }),
28059
27477
  },
28060
27478
  };
28061
27479
  }
@@ -28063,7 +27481,7 @@ class SimpleSearchField {
28063
27481
  return bucket.term.toString();
28064
27482
  }
28065
27483
  getAvailableValues() {
28066
- return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.esFieldName].buckets || []), switchMap((buckets) => {
27484
+ return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.fieldIdentifier].buckets || []), switchMap((buckets) => {
28067
27485
  const bucketPromises = buckets.map(async (bucket) => ({
28068
27486
  label: `${await this.getBucketLabel(bucket)} (${bucket.count})`,
28069
27487
  value: bucket.term.toString(),
@@ -28076,7 +27494,7 @@ class SimpleSearchField {
28076
27494
  // FieldValue[]
28077
27495
  if (this.getType() === 'values') {
28078
27496
  return of({
28079
- [this.esFieldName]: values.reduce((acc, val) => {
27497
+ [this.fieldIdentifier]: values.reduce((acc, val) => {
28080
27498
  const value = val.toString();
28081
27499
  if (value !== '') {
28082
27500
  return { ...acc, [value]: true };
@@ -28087,11 +27505,11 @@ class SimpleSearchField {
28087
27505
  }
28088
27506
  // DateRange
28089
27507
  return of({
28090
- [this.esFieldName]: values[0] !== '' ? values[0] : {},
27508
+ [this.fieldIdentifier]: values[0] !== '' ? values[0] : {},
28091
27509
  });
28092
27510
  }
28093
27511
  getValuesForFilter(filters) {
28094
- const filter = filters[this.esFieldName];
27512
+ const filter = filters[this.fieldIdentifier];
28095
27513
  if (!filter)
28096
27514
  return of([]);
28097
27515
  // filter by expression
@@ -28109,6 +27527,9 @@ class SimpleSearchField {
28109
27527
  getType() {
28110
27528
  return 'values';
28111
27529
  }
27530
+ clone() {
27531
+ return Object.create(this);
27532
+ }
28112
27533
  }
28113
27534
  class TranslatedSearchField extends SimpleSearchField {
28114
27535
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
@@ -28350,17 +27771,39 @@ class DateRangeSearchField extends SimpleSearchField {
28350
27771
  return 'dateRange';
28351
27772
  }
28352
27773
  }
27774
+ // treats a resource's creation/revision dates as an interval (its min and max), so a record matches
27775
+ // when that interval intersects the filter range, not just when a single date falls inside it
27776
+ class ResourceCreationRevisionDateSearchField extends DateRangeSearchField {
27777
+ constructor(injector, order = 'desc') {
27778
+ super('resourceCreationRevisionDate', injector, order);
27779
+ const dateSourceFields = [
27780
+ 'creationDateForResource',
27781
+ 'revisionDateForResource',
27782
+ ];
27783
+ const collectSortedDates = dateSourceFields
27784
+ .map((field) => `if (doc.containsKey('${field}')) {
27785
+ for (def date : doc['${field}']) { dates.add(date.millis); }
27786
+ }`)
27787
+ .join('\n');
27788
+ this.esService.registerRuntimeField('resourceCreationRevisionDateMin', `def dates = [];
27789
+ ${collectSortedDates}
27790
+ if (dates.length > 0) { dates.sort(null); emit(dates[0]); }`, 'date');
27791
+ this.esService.registerRuntimeField('resourceCreationRevisionDateMax', `def dates = [];
27792
+ ${collectSortedDates}
27793
+ if (dates.length > 0) { dates.sort(null); emit(dates[dates.length - 1]); }`, 'date');
27794
+ }
27795
+ }
28353
27796
  class BoundingBoxSearchField extends SimpleSearchField {
28354
27797
  getAvailableValues() {
28355
27798
  return of([]);
28356
27799
  }
28357
27800
  getFiltersForValues(values) {
28358
27801
  return of({
28359
- [this.esFieldName]: values.map(Number),
27802
+ [this.fieldIdentifier]: values.map(Number),
28360
27803
  });
28361
27804
  }
28362
27805
  getValuesForFilter(filters) {
28363
- const filter = filters[this.esFieldName];
27806
+ const filter = filters[this.fieldIdentifier];
28364
27807
  return of(isBoundingBox(filter) ? filter : []);
28365
27808
  }
28366
27809
  getType() {
@@ -28459,7 +27902,7 @@ class RecordKindField extends SimpleSearchField {
28459
27902
  }
28460
27903
  getFiltersForValues(values) {
28461
27904
  const filters = {
28462
- [this.esFieldName]: values.reduce((acc, value) => {
27905
+ [this.fieldIdentifier]: values.reduce((acc, value) => {
28463
27906
  if (value === '')
28464
27907
  return { ...acc, [value]: true };
28465
27908
  const keysToAdd = this.TYPE_MAPPING[value] || [value];
@@ -28482,7 +27925,7 @@ class RecordKindField extends SimpleSearchField {
28482
27925
  return of(filters);
28483
27926
  }
28484
27927
  getValuesForFilter(filters) {
28485
- const filter = filters[this.esFieldName];
27928
+ const filter = filters[this.fieldIdentifier];
28486
27929
  if (!filter)
28487
27930
  return of([]);
28488
27931
  const activeValues = Object.keys(filter).filter((v) => filter[v]);
@@ -28511,11 +27954,16 @@ marker('search.filters.producerOrg');
28511
27954
  marker('search.filters.publisherOrg');
28512
27955
  marker('search.filters.user');
28513
27956
  marker('search.filters.changeDate');
27957
+ marker('search.filters.resourceCreationRevisionDate');
27958
+ marker('search.filters.temporalExtent');
28514
27959
  marker('search.filters.spatialExtent');
27960
+ marker('search.filters.documentStandard');
27961
+ const CUSTOM_FIELDS = new InjectionToken('custom-fields');
28515
27962
  class FieldsService {
28516
27963
  constructor() {
28517
27964
  this.injector = inject(Injector);
28518
- this.fields = {
27965
+ this.customFields = inject(CUSTOM_FIELDS, { optional: true }) ?? [];
27966
+ this.baseFields = {
28519
27967
  organization: new OrganizationSearchField(this.injector),
28520
27968
  format: new SimpleSearchField('format', this.injector, 'asc'),
28521
27969
  resourceType: new ResourceTypeLegacyField(this.injector), // Deprecated, use `recordKind` instead
@@ -28534,9 +27982,28 @@ class FieldsService {
28534
27982
  publisherOrg: new MultilingualSearchField('distributorOrgForResourceObject', this.injector, 'asc', 'key'),
28535
27983
  user: new UserSearchField(this.injector),
28536
27984
  changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
27985
+ resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
27986
+ temporalExtent: new DateRangeSearchField('resourceTemporalExtentDateRange', this.injector, 'desc'),
28537
27987
  availableServices: new AvailableServicesField(this.injector),
28538
27988
  spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
28539
27989
  };
27990
+ this.fields = { ...this.baseFields };
27991
+ for (const customField of this.customFields) {
27992
+ const baseField = this.baseFields[customField.baseFilter];
27993
+ if (!(baseField instanceof SimpleSearchField)) {
27994
+ console.warn(`The custom field '${customField.name}' relies on a base field '${customField.baseFilter}' that is not supported. This field will be ignored.`);
27995
+ continue;
27996
+ }
27997
+ const newField = baseField.clone();
27998
+ newField.setFieldIdentifier(customField.name);
27999
+ if (customField.includeValues) {
28000
+ newField.includeValues = customField.includeValues;
28001
+ }
28002
+ if (customField.excludeValues) {
28003
+ newField.excludeValues = customField.excludeValues;
28004
+ }
28005
+ this.fields[customField.name] = newField;
28006
+ }
28540
28007
  }
28541
28008
  get supportedFields() {
28542
28009
  return Object.keys(this.fields);
@@ -28584,7 +28051,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28584
28051
  args: [{
28585
28052
  providedIn: 'root',
28586
28053
  }]
28587
- }] });
28054
+ }], ctorParameters: () => [] });
28588
28055
 
28589
28056
  class ApiCardComponent {
28590
28057
  constructor() {
@@ -30524,7 +29991,7 @@ class ServiceCapabilitiesComponent {
30524
29991
  if (this.apiLinks.length > 0 &&
30525
29992
  this.apiLinks[0].accessServiceProtocol !== 'ogcFeatures') {
30526
29993
  this.loading = true;
30527
- this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol);
29994
+ this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol, true);
30528
29995
  this.loading = false;
30529
29996
  this.cdr.detectChanges();
30530
29997
  this.filteredLayers = this.availableLayers;
@@ -31789,6 +31256,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31789
31256
  ], 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" }]
31790
31257
  }] });
31791
31258
 
31259
+ // in MB, null means no limit
31260
+ const SPATIAL_EXTENT_MAX_FILE_SIZE = new InjectionToken('spatialExtentMaxFileSize', { factory: () => null });
31792
31261
  class FilterDropdownComponent {
31793
31262
  constructor() {
31794
31263
  this.searchFacade = inject(SearchFacade);
@@ -31796,9 +31265,12 @@ class FilterDropdownComponent {
31796
31265
  this.fieldsService = inject(FieldsService);
31797
31266
  this.notificationsService = inject(NotificationsService);
31798
31267
  this.translateService = inject(TranslateService);
31799
- this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
31268
+ this.spatialExtentMaxFileSize = inject(SPATIAL_EXTENT_MAX_FILE_SIZE);
31800
31269
  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([])));
31801
31270
  this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
31271
+ this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
31272
+ ? selected
31273
+ : null));
31802
31274
  this.spatialExtentErrorNotificationId = null;
31803
31275
  }
31804
31276
  onSelectedValues(values) {
@@ -31807,7 +31279,11 @@ class FilterDropdownComponent {
31807
31279
  .subscribe((filters) => this.searchService.updateFilters(filters));
31808
31280
  }
31809
31281
  onBboxChange(bbox) {
31810
- console.log(bbox);
31282
+ this.fieldsService
31283
+ .buildFiltersFromFieldValues({
31284
+ [this.fieldName]: bbox,
31285
+ })
31286
+ .subscribe((filters) => this.searchService.updateFilters(filters));
31811
31287
  this.clearSpatialExtentErrorNotification();
31812
31288
  }
31813
31289
  onSpatialExtentError(error) {
@@ -31840,7 +31316,7 @@ class FilterDropdownComponent {
31840
31316
  .subscribe((filters) => this.searchService.updateFilters(filters));
31841
31317
  }
31842
31318
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
31843
- 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 ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\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"], outputs: ["bboxChange", "errorChange"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31319
+ 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 }); }
31844
31320
  }
31845
31321
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
31846
31322
  type: Component,
@@ -31849,7 +31325,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31849
31325
  DateRangeDropdownComponent,
31850
31326
  DropdownMultiselectComponent,
31851
31327
  SpatialExtentDropdownComponent,
31852
- ], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\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" }]
31328
+ ], 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" }]
31853
31329
  }], propDecorators: { fieldName: [{
31854
31330
  type: Input
31855
31331
  }], title: [{
@@ -31910,7 +31386,7 @@ class FuzzySearchComponent {
31910
31386
  this.isSearchActive.emit(event);
31911
31387
  }
31912
31388
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
31913
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31389
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31914
31390
  }
31915
31391
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, decorators: [{
31916
31392
  type: Component,
@@ -32469,6 +31945,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
32469
31945
 
32470
31946
  marker('search.filters.summaryLabel.user');
32471
31947
  marker('search.filters.summaryLabel.changeDate');
31948
+ marker('search.filters.summaryLabel.resourceCreationRevisionDate');
31949
+ marker('search.filters.summaryLabel.temporalExtent');
32472
31950
  const OPEN_BOUND = '…';
32473
31951
  class SearchFiltersSummaryItemComponent {
32474
31952
  constructor() {
@@ -32850,95 +32328,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
32850
32328
  ], template: "<div\n class=\"bg-white rounded shadow shadow-lg relative h-full w-[400px] overflow-hidden\"\n>\n <div class=\"p-3 border-b border-gray-300 flex items-center\">\n <ng-icon class=\"mr-2\" name=\"matLayersOutline\"></ng-icon>\n <span translate>map.layers.list</span>\n </div>\n <div class=\"flex flex-col px-4 divide-y divide-y-gray-50\">\n @for (layer of layers$ | async; track layer; let index = $index) {\n <div class=\"flex flex-row py-3\">\n <ng-icon class=\"-ml-2 mr-2 shrink-0\" name=\"matChevronRight\"></ng-icon>\n <span class=\"mr-2 grow\">{{ layer.label }}</span>\n <a\n href\n class=\"underline text-sm text-red-700 hover:text-red-900\"\n (click)=\"deleteLayer(index); $event.preventDefault()\"\n >\n delete\n </a>\n </div>\n }\n </div>\n <gn-ui-expandable-panel-button [titleTemplate]=\"addLayerTitle\">\n <mat-tab-group animationDuration=\"200ms\" class=\"h-full\">\n <mat-tab [label]=\"'map.add.layer.catalog' | translate\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-catalog></gn-ui-add-layer-from-catalog>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wms' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wms></gn-ui-add-layer-from-wms>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wfs' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wfs></gn-ui-add-layer-from-wfs>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.ogc.api' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-ogc-api\n [ogcUrl]=\"ogcUrl\"\n (layerAdded)=\"addLayer($event)\"\n ></gn-ui-add-layer-from-ogc-api>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.file' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-file></gn-ui-add-layer-from-file>\n </div>\n </mat-tab>\n </mat-tab-group>\n </gn-ui-expandable-panel-button>\n</div>\n\n<ng-template #addLayerTitle>\n <ng-icon class=\"mr-4\" name=\"matAddCircleOutlineOutline\"> </ng-icon>\n <span translate>map.add.layer</span>\n</ng-template>\n" }]
32851
32329
  }] });
32852
32330
 
32853
- class GeocodingComponent {
32854
- constructor() {
32855
- this.mapFacade = inject(MapFacade);
32856
- this.geocodingService = inject(GeocodingService);
32857
- this.searchText = '';
32858
- this.results = [];
32859
- this.searchTextChanged = new Subject();
32860
- this.destroy$ = new Subject();
32861
- this.errorMessage = null;
32862
- this.searchTextChanged
32863
- .pipe(debounceTime(300), switchMap$1((searchText) => {
32864
- return from(this.geocodingService.query(searchText)).pipe(catchError$1((error) => {
32865
- this.errorMessage =
32866
- 'An error occurred while searching. Please try again.';
32867
- console.error(error);
32868
- return [];
32869
- }));
32870
- }), takeUntil(this.destroy$))
32871
- .subscribe((results) => {
32872
- this.results = results;
32873
- });
32874
- }
32875
- ngOnDestroy() {
32876
- this.destroy$.next();
32877
- this.destroy$.complete();
32878
- }
32879
- onSearchChange(searchText) {
32880
- if (!searchText) {
32881
- this.clearSearch();
32882
- return;
32883
- }
32884
- else {
32885
- this.searchTextChanged.next(searchText);
32886
- }
32887
- }
32888
- clearSearch() {
32889
- this.searchText = '';
32890
- this.results = [];
32891
- this.errorMessage = null;
32892
- }
32893
- async zoomToLocation(result) {
32894
- const geometry = result.geom;
32895
- if (geometry.type === 'Point') {
32896
- await this.zoomToPoint(geometry.coordinates);
32897
- }
32898
- else if (geometry.type === 'Polygon') {
32899
- await this.zoomToPolygon(geometry.coordinates);
32900
- }
32901
- else {
32902
- console.error(`Unsupported geometry type: ${geometry.type}`);
32903
- }
32904
- }
32905
- async zoomToPoint(pointCoords) {
32906
- const context = await firstValueFrom(this.mapFacade.context$);
32907
- const view = {
32908
- center: pointCoords,
32909
- zoom: 10,
32910
- };
32911
- this.mapFacade.applyContext({
32912
- ...context,
32913
- view,
32914
- });
32915
- }
32916
- async zoomToPolygon(polygonCoords) {
32917
- const context = await firstValueFrom(this.mapFacade.context$);
32918
- const view = {
32919
- geometry: {
32920
- type: 'Polygon',
32921
- coordinates: polygonCoords,
32922
- },
32923
- };
32924
- this.mapFacade.applyContext({
32925
- ...context,
32926
- view,
32927
- });
32928
- }
32929
- onEnterPress() {
32930
- if (this.results && this.results.length > 0) {
32931
- this.zoomToLocation(this.results[0]);
32932
- }
32933
- }
32934
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32935
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GeocodingComponent, isStandalone: true, selector: "gn-ui-geocoding", ngImport: i0, template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n", styles: [""], dependencies: [{ kind: "component", type: SearchInputComponent, selector: "gn-ui-search-input", inputs: ["value", "placeholder"], outputs: ["valueChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
32936
- }
32937
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, decorators: [{
32938
- type: Component,
32939
- args: [{ selector: 'gn-ui-geocoding', standalone: true, imports: [SearchInputComponent, TranslatePipe], template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n" }]
32940
- }], ctorParameters: () => [] });
32941
-
32942
32331
  /*
32943
32332
  Metadata actions
32944
32333
  */
@@ -37983,7 +37372,7 @@ class GenericKeywordsComponent {
37983
37372
  this.deletedKeyword.emit(keyword);
37984
37373
  }
37985
37374
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
37986
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37375
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37987
37376
  }
37988
37377
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, decorators: [{
37989
37378
  type: Component,
@@ -38575,7 +37964,7 @@ class FormFieldContactsForResourceComponent {
38575
37964
  provideNgIconsConfig({
38576
37965
  size: '1.5rem',
38577
37966
  }),
38578
- ], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n &nbsp;\n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37967
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n &nbsp;\n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38579
37968
  }
38580
37969
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsForResourceComponent, decorators: [{
38581
37970
  type: Component,
@@ -38675,7 +38064,7 @@ class FormFieldContactsComponent {
38675
38064
  this.subscription.unsubscribe();
38676
38065
  }
38677
38066
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38678
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38067
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38679
38068
  }
38680
38069
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, decorators: [{
38681
38070
  type: Component,
@@ -39028,7 +38417,7 @@ class OnlineServiceResourceInputComponent {
39028
38417
  provideNgIconsConfig({
39029
38418
  size: '1.5em',
39030
38419
  }),
39031
- ], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38420
+ ], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39032
38421
  }
39033
38422
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: OnlineServiceResourceInputComponent, decorators: [{
39034
38423
  type: Component,
@@ -40903,6 +40292,625 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
40903
40292
  args: ['gnUiSearchRouterContainer']
40904
40293
  }] } });
40905
40294
 
40295
+ const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
40296
+ const path = base ? `${base}.${curr}` : curr;
40297
+ const val = obj[curr];
40298
+ if (keepLevel) {
40299
+ return { ...prev, [path]: flatten('', val) };
40300
+ }
40301
+ else if (typeof val === 'object' && !Array.isArray(val)) {
40302
+ return {
40303
+ ...prev,
40304
+ ...flatten(path, val),
40305
+ };
40306
+ }
40307
+ else {
40308
+ return { ...prev, [path]: val };
40309
+ }
40310
+ }, {});
40311
+ const checkKeys = (input, mandatory, optional) => {
40312
+ const keys = Object.keys(input);
40313
+ const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
40314
+ const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
40315
+ return {
40316
+ missing,
40317
+ unrecognized,
40318
+ };
40319
+ };
40320
+ /**
40321
+ * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
40322
+ * pushes warnings and errors to the given arrays; returns null in case of error
40323
+ */
40324
+ function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40325
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40326
+ if (mandatoryKeys.length === 0)
40327
+ return null;
40328
+ outErrors.push(`The [${sectionName}] mandatory section is missing.`);
40329
+ return null;
40330
+ }
40331
+ const sectionConf = fullConfigObj[sectionName];
40332
+ const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
40333
+ if (keysCheck.missing.length) {
40334
+ // note: this is not thrown to allow merging several Errors down the line
40335
+ outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
40336
+ return null;
40337
+ }
40338
+ else if (keysCheck.unrecognized.length) {
40339
+ outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
40340
+ keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
40341
+ }
40342
+ return sectionConf;
40343
+ }
40344
+ /**
40345
+ * Same as parseConfigSection but keeps all keys, recognized or not
40346
+ * Also the first level is the language code (e.g. 'en')
40347
+ * This is optional
40348
+ */
40349
+ function parseTranslationsConfigSection(fullConfigObj, sectionName) {
40350
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40351
+ return {};
40352
+ }
40353
+ return flatten('', fullConfigObj[sectionName], true);
40354
+ }
40355
+ /**
40356
+ * Same as parseConfigSection but handles an array of configs; this is
40357
+ * considered optional; returns null in case of error in at least one of
40358
+ * the sections
40359
+ */
40360
+ function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40361
+ const sections = fullConfigObj[sectionName];
40362
+ if (!sections) {
40363
+ return [];
40364
+ }
40365
+ if (!Array.isArray(sections)) {
40366
+ outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
40367
+ return null;
40368
+ }
40369
+ const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
40370
+ if (result.some((r) => r === null)) {
40371
+ return null;
40372
+ }
40373
+ return result;
40374
+ }
40375
+ function checkMetadataLanguage(parsedConfigSection, outWarnings) {
40376
+ const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
40377
+ if (lang2?.length !== 2) {
40378
+ outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
40379
+ }
40380
+ return parsedConfigSection;
40381
+ }
40382
+ function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
40383
+ const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
40384
+ if (!(lang2 in LANG_2_TO_3_MAPPER)) {
40385
+ outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
40386
+ return {
40387
+ ...parsedConfigSection,
40388
+ new_record_default_language: undefined,
40389
+ };
40390
+ }
40391
+ return {
40392
+ ...parsedConfigSection,
40393
+ new_record_default_language: lang2,
40394
+ };
40395
+ }
40396
+ function checkNewRecordStandard(parsedConfigSection, outWarnings) {
40397
+ const standard = parsedConfigSection.new_record_standard;
40398
+ const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
40399
+ if (normalizedStandard === 'iso19139' ||
40400
+ normalizedStandard === 'iso19115-3') {
40401
+ return {
40402
+ ...parsedConfigSection,
40403
+ new_record_standard: normalizedStandard,
40404
+ };
40405
+ }
40406
+ outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
40407
+ return {
40408
+ ...parsedConfigSection,
40409
+ new_record_standard: undefined,
40410
+ };
40411
+ }
40412
+
40413
+ /**
40414
+ * This loader extends the default one based on JSON files but also loads custom translations
40415
+ * defined in the app configuration
40416
+ * Implements a fallback on default lang if translated labels are empty
40417
+ */
40418
+ class FileWithOverridesTranslateLoader extends FileTranslateLoader {
40419
+ getTranslation(lang) {
40420
+ const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
40421
+ return super.getTranslation(baseLang).pipe(map$1((translations) => ({
40422
+ ...translations,
40423
+ ...getCustomTranslations(baseLang),
40424
+ })));
40425
+ }
40426
+ }
40427
+
40428
+ const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
40429
+ This error might show up in case of an invalid/malformed configuration file.
40430
+
40431
+ Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
40432
+ let globalConfig = null;
40433
+ function getGlobalConfig() {
40434
+ if (globalConfig === null)
40435
+ throw new Error(MISSING_CONFIG_ERROR);
40436
+ return globalConfig;
40437
+ }
40438
+ let themeConfig = null;
40439
+ function getThemeConfig() {
40440
+ if (themeConfig === null)
40441
+ throw new Error(MISSING_CONFIG_ERROR);
40442
+ return themeConfig;
40443
+ }
40444
+ let mapConfig = null;
40445
+ function getOptionalMapConfig() {
40446
+ return mapConfig;
40447
+ }
40448
+ let searchConfig = null;
40449
+ function getOptionalSearchConfig() {
40450
+ return searchConfig;
40451
+ }
40452
+ let editorConfig = null;
40453
+ function getOptionalEditorConfig() {
40454
+ return editorConfig;
40455
+ }
40456
+ let metadataQualityConfig = null;
40457
+ function getMetadataQualityConfig() {
40458
+ return (metadataQualityConfig ||
40459
+ {
40460
+ ENABLED: false,
40461
+ });
40462
+ }
40463
+ let customTranslations = null;
40464
+ function getCustomTranslations(langCode) {
40465
+ if (customTranslations === null)
40466
+ throw new Error(MISSING_CONFIG_ERROR);
40467
+ return langCode in customTranslations ? customTranslations[langCode] : {};
40468
+ }
40469
+ let appConfigLoaded = false;
40470
+ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
40471
+ console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
40472
+ return fetch(configUrl)
40473
+ .then((resp) => {
40474
+ if (!resp.ok)
40475
+ throw new Error('Configuration file could not be loaded');
40476
+ return resp.text();
40477
+ })
40478
+ .then((conf) => {
40479
+ let parsed;
40480
+ try {
40481
+ parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
40482
+ }
40483
+ catch (e) {
40484
+ throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
40485
+ }
40486
+ const errors = [];
40487
+ const warnings = [];
40488
+ let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
40489
+ 'datahub_url',
40490
+ 'edit_url_template',
40491
+ 'proxy_path',
40492
+ 'metadata_language',
40493
+ 'login_url',
40494
+ 'logout_url',
40495
+ 'settings_url',
40496
+ 'web_component_embedder_url',
40497
+ 'languages',
40498
+ 'contact_email',
40499
+ 'reuse_form_url',
40500
+ ], warnings, errors);
40501
+ if (parsedGlobalSection?.metadata_language) {
40502
+ parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
40503
+ }
40504
+ globalConfig =
40505
+ parsedGlobalSection === null
40506
+ ? null
40507
+ : {
40508
+ GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
40509
+ DATAHUB_URL: parsedGlobalSection.datahub_url,
40510
+ EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
40511
+ PROXY_PATH: parsedGlobalSection.proxy_path,
40512
+ METADATA_LANGUAGE: parsedGlobalSection.metadata_language
40513
+ ? parsedGlobalSection.metadata_language.toLowerCase()
40514
+ : undefined,
40515
+ LOGIN_URL: parsedGlobalSection.login_url,
40516
+ LOGOUT_URL: parsedGlobalSection.logout_url,
40517
+ SETTINGS_URL: parsedGlobalSection.settings_url,
40518
+ WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
40519
+ LANGUAGES: parsedGlobalSection.languages,
40520
+ CONTACT_EMAIL: parsedGlobalSection.contact_email,
40521
+ REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
40522
+ };
40523
+ const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
40524
+ const parsedMapSection = parseConfigSection(parsed, 'map', [], [
40525
+ 'max_zoom',
40526
+ 'do_not_tile_wms',
40527
+ 'max_extent',
40528
+ 'max_feature_count',
40529
+ 'baselayer',
40530
+ 'do_not_use_default_basemap',
40531
+ 'external_viewer_url_template',
40532
+ 'external_viewer_open_new_tab',
40533
+ ], warnings, errors);
40534
+ mapConfig =
40535
+ parsedMapSection === null || parsedLayersSections === null
40536
+ ? null
40537
+ : {
40538
+ MAX_ZOOM: parsedMapSection.max_zoom,
40539
+ DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
40540
+ MAX_EXTENT: parsedMapSection.max_extent,
40541
+ MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
40542
+ EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
40543
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
40544
+ DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
40545
+ MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
40546
+ TYPE: map_layer.type,
40547
+ URL: map_layer.url,
40548
+ NAME: map_layer.name,
40549
+ DATA: map_layer.data,
40550
+ STYLE_URL: map_layer.styleUrl,
40551
+ ACCESS_TOKEN: map_layer.accessToken,
40552
+ })),
40553
+ };
40554
+ const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
40555
+ 'header_foreground_color',
40556
+ 'main_font',
40557
+ 'title_font',
40558
+ 'fonts_stylesheet_url',
40559
+ 'thumbnail_placeholder',
40560
+ 'header_background',
40561
+ 'favicon',
40562
+ ], warnings, errors);
40563
+ themeConfig =
40564
+ parsedThemeSection === null
40565
+ ? null
40566
+ : {
40567
+ PRIMARY_COLOR: parsedThemeSection.primary_color,
40568
+ SECONDARY_COLOR: parsedThemeSection.secondary_color,
40569
+ MAIN_COLOR: parsedThemeSection.main_color,
40570
+ BACKGROUND_COLOR: parsedThemeSection.background_color,
40571
+ HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
40572
+ THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
40573
+ HEADER_BACKGROUND: parsedThemeSection.header_background,
40574
+ TITLE_FONT: parsedThemeSection.title_font,
40575
+ MAIN_FONT: parsedThemeSection.main_font,
40576
+ FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
40577
+ FAVICON: parsedThemeSection.favicon,
40578
+ };
40579
+ const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
40580
+ 'record_kind_quick_filter',
40581
+ 'filter_geometry_data',
40582
+ 'filter_geometry_url',
40583
+ 'do_not_use_default_search_preset',
40584
+ 'search_preset',
40585
+ 'advanced_filters',
40586
+ 'limit',
40587
+ 'spatial_extent_max_file_size',
40588
+ 'geocoding_provider',
40589
+ 'geocoding_provider_options',
40590
+ ], warnings, errors);
40591
+ const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
40592
+ const parsedCustomFilters = parseMultiConfigSection(parsed, 'custom_filter', ['name', 'base_filter'], ['exclude_values', 'include_values', 'label_key'], warnings, errors);
40593
+ searchConfig =
40594
+ parsedSearchSection === null
40595
+ ? null
40596
+ : {
40597
+ RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
40598
+ FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
40599
+ FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
40600
+ DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
40601
+ SEARCH_PRESET: parsedSearchParams.map((param) => ({
40602
+ sort: param.sort,
40603
+ name: param.name,
40604
+ filters: param.filters,
40605
+ })),
40606
+ ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
40607
+ CUSTOM_FILTERS: (parsedCustomFilters ?? []).map((customFilter) => ({
40608
+ name: customFilter.name,
40609
+ baseFilter: customFilter.base_filter,
40610
+ excludeValues: customFilter.exclude_values,
40611
+ includeValues: customFilter.include_values,
40612
+ labelKey: customFilter.label_key,
40613
+ })),
40614
+ LIMIT: parsedSearchSection.limit,
40615
+ SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
40616
+ GEOCODING_PROVIDER: parsedSearchSection.geocoding_provider,
40617
+ GEOCODING_PROVIDER_OPTIONS: parsedSearchSection.geocoding_provider_options,
40618
+ };
40619
+ const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
40620
+ metadataQualityConfig =
40621
+ parsedMetadataQualitySection === null
40622
+ ? null
40623
+ : {
40624
+ ENABLED: parsedMetadataQualitySection.enabled,
40625
+ SORTABLE: parsedMetadataQualitySection.sortable,
40626
+ };
40627
+ let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
40628
+ if (parsedEditingSection !== null &&
40629
+ parsedEditingSection.new_record_default_language !== undefined) {
40630
+ parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
40631
+ }
40632
+ if (parsedEditingSection !== null &&
40633
+ parsedEditingSection.new_record_standard !== undefined) {
40634
+ parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
40635
+ }
40636
+ editorConfig =
40637
+ parsedEditingSection === null
40638
+ ? null
40639
+ : {
40640
+ NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
40641
+ NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
40642
+ };
40643
+ customTranslations = parseTranslationsConfigSection(parsed, 'translations');
40644
+ if (errors.length) {
40645
+ throw new Error(`One or more mandatory settings were missing from the configuration file.
40646
+ ${errors.join('\n')}`);
40647
+ }
40648
+ else if (warnings.length) {
40649
+ console.warn(`One or more unexpected settings were encountered in the configuration file.
40650
+ ${warnings.join('\n')}`);
40651
+ }
40652
+ appConfigLoaded = true;
40653
+ });
40654
+ }
40655
+ function isConfigLoaded() {
40656
+ return appConfigLoaded;
40657
+ }
40658
+ function _reset() {
40659
+ globalConfig = null;
40660
+ themeConfig = null;
40661
+ editorConfig = null;
40662
+ customTranslations = null;
40663
+ }
40664
+ const TRANSLATE_WITH_OVERRIDES_CONFIG = {
40665
+ compiler: {
40666
+ provide: TranslateCompiler,
40667
+ useClass: TranslateMessageFormatCompiler,
40668
+ },
40669
+ loader: [
40670
+ {
40671
+ provide: TRANSLATE_HTTP_LOADER_CONFIG,
40672
+ useValue: {
40673
+ prefix: './assets/i18n/',
40674
+ suffix: '.json',
40675
+ },
40676
+ },
40677
+ {
40678
+ provide: TranslateLoader,
40679
+ useClass: FileWithOverridesTranslateLoader,
40680
+ deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
40681
+ },
40682
+ ],
40683
+ };
40684
+
40685
+ const okAppConfigFixture = () => `
40686
+ [global]
40687
+ geonetwork4_api_url = "/geonetwork/srv/api"
40688
+ proxy_path = "/proxy/?url="
40689
+ metadata_language = "fre"
40690
+ login_url = "/cas/login?service="
40691
+ logout_url = "/geonetwork/signout"
40692
+ settings_url = "/geonetwork/settings"
40693
+ web_component_embedder_url = "/datahub/wc-embedder.html"
40694
+
40695
+ [map]
40696
+ max_zoom = 10
40697
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
40698
+ do_not_use_default_basemap = false
40699
+ external_viewer_url_template = 'https://example.com/myviewer?'
40700
+ external_viewer_open_new_tab = true
40701
+ [[map_layer]]
40702
+ type = "wms"
40703
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40704
+ name = "masque_hdf_ign_carto_latin1"
40705
+ [[map_layer]]
40706
+ type = "wfs"
40707
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40708
+ name = "masque_hdf_ign_carto_latin1"
40709
+
40710
+ [theme]
40711
+ primary_color = "#093564"
40712
+ secondary_color = "#c2e9dc"
40713
+ main_color = "#212029" # All-purpose text color
40714
+ background_color = "#fdfbff"
40715
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
40716
+ header_background = 'teal'
40717
+ header_foreground_color = "#872e2e"
40718
+ main_font = 'sans-serif'
40719
+ title_font = 'serif'
40720
+ fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
40721
+
40722
+ [search]
40723
+ record_kind_quick_filter = false
40724
+ filter_geometry_url = 'https://my.domain.org/geom.json'
40725
+ do_not_use_default_search_preset = false
40726
+ geocoding_provider = "geoplateforme"
40727
+ geocoding_provider_options.category = "administratif"
40728
+ geocoding_provider_options.limit = 5
40729
+ advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license', 'myOrg:firstCustomFilter', 'myOrg:secondCustomFilter']
40730
+
40731
+ [[custom_filter]]
40732
+ name = 'myOrg:firstCustomFilter'
40733
+ base_filter = 'keyword'
40734
+ exclude_values = ['my keyword 1', 'my keyword 2']
40735
+ label_key = 'myOrg.firstCustomFilter'
40736
+
40737
+ [[custom_filter]]
40738
+ name = 'myOrg:secondCustomFilter'
40739
+ base_filter = 'keyword'
40740
+ include_values = ['my keyword 3', 'my keyword 4']
40741
+ label_key = 'myOrg.secondCustomFilter'
40742
+
40743
+ [[search_preset]]
40744
+ sort = "-createDate"
40745
+ name = 'filterByOrgs'
40746
+ filters.q = 'Carto'
40747
+ filters.organisation = ['Org1', 'Org2']
40748
+ filters.format = ['ESRI Shapefile']
40749
+ filters.topic = ['boundaries']
40750
+ filters.publicationYear = ['2023', '2022']
40751
+ filters.spatial = ['yes']
40752
+
40753
+ [translations.en]
40754
+ "my.first.key" = 'First label.'
40755
+ "my.second.key" = """
40756
+ Second label,
40757
+ on two lines."""
40758
+
40759
+ [translations.de]
40760
+ my.first.key = 'Erste Etikett.'
40761
+
40762
+ [translations.fr]
40763
+ my.sample.text = "Un bon exemple de texte."
40764
+ "my.quoted.text" = 'du texte entre guillements.'
40765
+ `;
40766
+ const appConfigWithTranslationFixture = () => okAppConfigFixture();
40767
+ const minimalAppConfigFixture = () => `
40768
+ [global]
40769
+ geonetwork4_api_url = "/geonetwork/srv/api"
40770
+ proxy_path = "/proxy/?url="
40771
+
40772
+ [theme]
40773
+ primary_color = "#093564"
40774
+ secondary_color = "#c2e9dc"
40775
+ main_color = "#212029" # All-purpose text color
40776
+ background_color = "#fdfbff"
40777
+ `;
40778
+ const customFilterMissingMandatoryConfigFixture = () => `
40779
+ [global]
40780
+ geonetwork4_api_url = "/geonetwork/srv/api"
40781
+
40782
+ [theme]
40783
+ primary_color = "#093564"
40784
+ secondary_color = "#c2e9dc"
40785
+ main_color = "#212029" # All-purpose text color
40786
+ background_color = "#fdfbff"
40787
+
40788
+ [search]
40789
+ advanced_filters = ['myOrg:firstCustomFilter']
40790
+
40791
+ [[custom_filter]]
40792
+ name = 'myOrg:firstCustomFilter'
40793
+ `;
40794
+ const mapConfigFixture = () => ({
40795
+ MAX_ZOOM: 10,
40796
+ MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
40797
+ DO_NOT_USE_DEFAULT_BASEMAP: false,
40798
+ DO_NOT_TILE_WMS: false,
40799
+ 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}"}]}]',
40800
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
40801
+ MAP_LAYERS: [
40802
+ {
40803
+ TYPE: 'xyz',
40804
+ URL: 'https://some-basemap-server',
40805
+ },
40806
+ {
40807
+ TYPE: 'wms',
40808
+ URL: 'https://some-wms-server',
40809
+ NAME: 'some_layername',
40810
+ },
40811
+ {
40812
+ TYPE: 'wfs',
40813
+ URL: 'https://some-wfs-server',
40814
+ NAME: 'some_layername',
40815
+ },
40816
+ ],
40817
+ });
40818
+ const malformedConfigFixture = () => `
40819
+ {
40820
+ "I thought": "we were still doing json"
40821
+ }
40822
+ `;
40823
+ const missingMandatoryConfigFixture = () => `
40824
+ [theme]
40825
+ primary_color = "#093564"
40826
+ secondary_color = "#c2e9dc"
40827
+ background_color = "#fdfbff"
40828
+ main_font = 'sans-serif'
40829
+ `;
40830
+ const wrongLanguageCodeConfigFixture = () => `
40831
+ [global]
40832
+ geonetwork4_api_url = "/geonetwork/srv/api"
40833
+ proxy_path = "/proxy/?url="
40834
+ metadata_language = "abc"
40835
+
40836
+ [map]
40837
+
40838
+ [theme]
40839
+ primary_color = "#093564"
40840
+ secondary_color = "#c2e9dc"
40841
+ main_color = "#212029" # All-purpose text color
40842
+ background_color = "#fdfbff"
40843
+ `;
40844
+ const unrecognizedKeysConfigFixture = () => `
40845
+ [global]
40846
+ geonetwork4_api_url = "/geonetwork/srv/api"
40847
+ proxy_path = "/proxy/?url="
40848
+ metadata_language = "fre"
40849
+ another_path = '/whatever'
40850
+
40851
+ [map]
40852
+ max_zoom = 10
40853
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
40854
+ do_not_use_default_basemap = false
40855
+ external_viewer_url_template = 'https://example.com/myviewer?'
40856
+ external_viewer_open_new_tab = true
40857
+ another_zoom = 15
40858
+ [[map_layer]]
40859
+ type = "wms"
40860
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40861
+ name = "masque_hdf_ign_carto_latin1"
40862
+ [[map_layer]]
40863
+ type = "wfs"
40864
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40865
+ name = "masque_hdf_ign_carto_latin1"
40866
+ another_layer = "wrong layer definition"
40867
+
40868
+ [theme]
40869
+ primary_color = "#093564"
40870
+ secondary_color = "#c2e9dc"
40871
+ main_color = "#212029" # All-purpose text color
40872
+ background_color = "#fdfbff"
40873
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
40874
+ header_background = 'teal'
40875
+ header_foreground_color = "#872e2e"
40876
+ main_font = 'sans-serif'
40877
+ title_font = 'serif'
40878
+ another_color = 'red'
40879
+ `;
40880
+
40881
+ function getMapContextLayerFromConfig(config) {
40882
+ switch (config.TYPE) {
40883
+ case 'wms':
40884
+ return {
40885
+ type: 'wms',
40886
+ url: config.URL,
40887
+ name: config.NAME,
40888
+ };
40889
+ case 'wfs':
40890
+ return {
40891
+ type: 'wfs',
40892
+ url: config.URL,
40893
+ featureType: config.NAME,
40894
+ };
40895
+ case 'xyz':
40896
+ return {
40897
+ type: config.TYPE,
40898
+ url: config.URL,
40899
+ };
40900
+ case 'geojson':
40901
+ return {
40902
+ type: config.TYPE,
40903
+ ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
40904
+ };
40905
+ case 'maplibre-style':
40906
+ return {
40907
+ type: config.TYPE,
40908
+ styleUrl: config.STYLE_URL,
40909
+ accessToken: config.ACCESS_TOKEN,
40910
+ };
40911
+ }
40912
+ }
40913
+
40906
40914
  const CHART_TYPE_VALUES = [
40907
40915
  'bar',
40908
40916
  'bar-horizontal',
@@ -40918,5 +40926,5 @@ const CHART_TYPE_VALUES = [
40918
40926
  * Generated bundle index. Do not edit.
40919
40927
  */
40920
40928
 
40921
- export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingComponent, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, 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 };
40929
+ 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, 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 };
40922
40930
  //# sourceMappingURL=geonetwork-ui.mjs.map