geonetwork-ui 2.11.0-dev.a83f0f51a → 2.11.0-dev.b7f9a229d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/geonetwork-ui.mjs +1513 -930
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +289 -124
- package/index.d.ts.map +1 -1
- package/package.json +12 -11
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +43 -13
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +108 -34
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +40 -16
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +12 -0
- package/src/libs/common/domain/src/lib/model/search/filter.model.ts +20 -1
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -2
- package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +3 -2
- package/src/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.ts +2 -1
- package/src/libs/feature/dataviz/src/lib/service/data.service.ts +22 -22
- package/src/libs/feature/map/src/index.ts +0 -1
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +1 -0
- package/src/libs/feature/map/src/lib/feature-map.module.ts +1 -8
- package/src/libs/feature/notifications/src/lib/notifications.service.ts +6 -4
- package/src/libs/feature/record/src/lib/state/mdview.actions.ts +4 -8
- package/src/libs/feature/record/src/lib/state/mdview.effects.ts +7 -16
- package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -3
- package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +4 -9
- package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +2 -7
- package/src/libs/feature/router/src/lib/default/state/query-params.utils.ts +1 -1
- package/src/libs/feature/search/src/index.ts +2 -0
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +12 -4
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +58 -19
- package/src/libs/feature/{map/src/lib → search/src/lib/geocoding}/geocoding.service.ts +16 -7
- package/src/libs/feature/search/src/lib/location-search/location-search.component.html +8 -0
- package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +40 -0
- package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +18 -8
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +9 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +61 -2
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +6 -7
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +31 -19
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.ts +2 -2
- package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.ts +2 -1
- package/src/libs/ui/inputs/src/index.ts +2 -0
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +10 -1
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +8 -0
- package/src/libs/ui/inputs/src/lib/date-adapter.providers.ts +30 -0
- package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +3 -24
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.css +37 -3
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.html +135 -16
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.ts +166 -29
- package/src/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.ts +3 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.css +1 -0
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.html +20 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.ts +46 -5
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +7 -4
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +12 -9
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.model.ts +2 -2
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +111 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +221 -0
- package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +1 -0
- package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +6 -5
- package/src/libs/util/app-config/src/lib/app-config.ts +8 -0
- package/src/libs/util/app-config/src/lib/fixtures.ts +3 -0
- package/src/libs/util/app-config/src/lib/model.ts +5 -0
- package/src/libs/util/data-fetcher/src/lib/data-fetcher.ts +19 -22
- package/src/libs/util/data-fetcher/src/lib/engine/duckdb.ts +185 -0
- package/src/libs/util/data-fetcher/src/lib/engine/results.ts +63 -0
- package/src/libs/util/data-fetcher/src/lib/{sql-utils.ts → engine/sql-utils.ts} +28 -13
- package/src/libs/util/data-fetcher/src/lib/model.ts +2 -1
- package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +53 -38
- package/src/libs/util/data-fetcher/src/lib/readers/base.ts +11 -0
- package/src/libs/util/data-fetcher/src/lib/readers/csv.ts +9 -47
- package/src/libs/util/data-fetcher/src/lib/readers/excel.ts +27 -27
- package/src/libs/util/data-fetcher/src/lib/readers/geojson.ts +5 -24
- package/src/libs/util/data-fetcher/src/lib/readers/gml.ts +5 -49
- package/src/libs/util/data-fetcher/src/lib/readers/json.ts +5 -23
- package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +184 -128
- package/src/libs/util/data-fetcher/src/lib/utils.ts +0 -143
- package/src/libs/util/shared/src/index.ts +1 -0
- package/src/libs/util/shared/src/lib/autofocus.directive.ts +26 -0
- package/src/libs/util/shared/src/lib/links/link-utils.ts +19 -10
- package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
- package/src/libs/util/shared/src/lib/utils/file.ts +15 -0
- package/src/libs/util/shared/src/lib/utils/geojson.ts +24 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/tailwind.base.css +5 -0
- package/translations/de.json +18 -3
- package/translations/en.json +17 -2
- package/translations/es.json +16 -1
- package/translations/fr.json +18 -3
- package/translations/it.json +16 -1
- package/translations/nl.json +16 -1
- package/translations/pt.json +16 -1
- package/translations/sk.json +16 -1
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +0 -41
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +0 -112
- package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +0 -14
- /package/src/libs/{feature/map/src/lib/geocoding/geocoding.component.css → ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.css} +0 -0
|
@@ -6,9 +6,9 @@ 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, combineLatest, from, exhaustMap, throwError,
|
|
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
|
-
import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef,
|
|
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';
|
|
13
13
|
import * as i4 from '@ngx-translate/core';
|
|
14
14
|
import { TranslateLoader, TranslateCompiler, TranslateDefaultParser, TranslateParser, TranslateService, provideTranslateService, TranslateDirective, TranslatePipe, TranslateModule } from '@ngx-translate/core';
|
|
@@ -18,7 +18,7 @@ import { map as map$1, shareReplay as shareReplay$1, catchError, tap as tap$1, f
|
|
|
18
18
|
import { lt, valid, coerce, satisfies, ltr } from 'semver';
|
|
19
19
|
import chroma from 'chroma-js';
|
|
20
20
|
import * as i1$1 from '@angular/common';
|
|
21
|
-
import { Location, CommonModule,
|
|
21
|
+
import { Location, CommonModule, NgTemplateOutlet, NgClass, AsyncPipe } from '@angular/common';
|
|
22
22
|
import { formatDistance } from 'date-fns/formatDistance';
|
|
23
23
|
import { Scroll, NavigationEnd, Router, RouteReuseStrategy } from '@angular/router';
|
|
24
24
|
import { WmtsEndpoint, WmsEndpoint, WfsEndpoint, OgcApiEndpoint, sharedFetch, useCache, StacEndpoint, TmsEndpoint } from '@camptocamp/ogc-client';
|
|
@@ -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';
|
|
@@ -41,10 +40,10 @@ import * as TOML from '@ltd/j-toml';
|
|
|
41
40
|
import { Style, Stroke, Fill, Circle } from 'ol/style.js';
|
|
42
41
|
import CircleStyle from 'ol/style/Circle.js';
|
|
43
42
|
import EmblaCarousel from 'embla-carousel';
|
|
44
|
-
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, 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,
|
|
43
|
+
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
44
|
import { MatButtonModule } from '@angular/material/button';
|
|
46
|
-
import * as i1$
|
|
47
|
-
import {
|
|
45
|
+
import * as i1$7 from '@angular/cdk/overlay';
|
|
46
|
+
import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
48
47
|
import * as i1$3 from '@angular/forms';
|
|
49
48
|
import { UntypedFormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
50
49
|
import * as i1$2 from '@angular/material/autocomplete';
|
|
@@ -52,16 +51,18 @@ import { MatAutocompleteModule, MatAutocompleteTrigger, MatAutocomplete } from '
|
|
|
52
51
|
import tippy from 'tippy.js';
|
|
53
52
|
import * as i2 from '@angular/material/progress-spinner';
|
|
54
53
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
55
|
-
import { matClose, matContentCopy,
|
|
54
|
+
import { matClose, matContentCopy, matExpandMore, matExpandLess, matSearch, matStarBorder, matStar, matRemove, matAdd, matChevronRight, matChevronLeft, matArrowForwardIos, matArrowBackIos, matMoodBad, matQuestionMark, matFace, matZoomOutMap, matOpenInNew, matPersonOutline, matMailOutline, matWarningAmber, matCheck, matCheckCircleOutline, matWarning, matMoreVert } from '@ng-icons/material-icons/baseline';
|
|
56
55
|
import * as i1$4 from '@angular/material/checkbox';
|
|
57
56
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
58
57
|
import * as i1$5 from '@angular/material/tooltip';
|
|
59
58
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
60
|
-
import {
|
|
59
|
+
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
|
|
60
|
+
import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
|
61
|
+
import { enUS } from 'date-fns/locale/en-US';
|
|
61
62
|
import * as i1$6 from '@angular/material/datepicker';
|
|
62
63
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
63
|
-
import * as i1$
|
|
64
|
-
import { NgxDropzoneModule } from 'ngx-dropzone';
|
|
64
|
+
import * as i1$8 from 'ngx-dropzone';
|
|
65
|
+
import { NgxDropzoneModule, NgxDropzoneComponent } from 'ngx-dropzone';
|
|
65
66
|
import * as i1$9 from '@angular/material/button-toggle';
|
|
66
67
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
67
68
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -72,6 +73,7 @@ import { MatTabsModule } from '@angular/material/tabs';
|
|
|
72
73
|
import * as i2$2 from '@ngrx/effects';
|
|
73
74
|
import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
|
|
74
75
|
import { valid as valid$1 } from 'geojson-validation';
|
|
76
|
+
import { queryGeoplateforme, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
|
|
75
77
|
import { TemplatePortal } from '@angular/cdk/portal';
|
|
76
78
|
import { parse as parse$3 } from 'marked';
|
|
77
79
|
import * as i2$3 from '@angular/cdk/scrolling';
|
|
@@ -79,10 +81,10 @@ import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
|
|
|
79
81
|
import Duration from 'duration-relativetimeformat';
|
|
80
82
|
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
|
|
81
83
|
import { trigger, transition, animate, keyframes, style } from '@angular/animations';
|
|
82
|
-
import * as
|
|
83
|
-
import {
|
|
84
|
-
import
|
|
85
|
-
import
|
|
84
|
+
import * as duckdb from '@duckdb/duckdb-wasm';
|
|
85
|
+
import { Vector, DataType } from 'apache-arrow';
|
|
86
|
+
import WFS from 'ol/format/WFS';
|
|
87
|
+
import GeoJSON$1 from 'ol/format/GeoJSON';
|
|
86
88
|
import { Chart, BarController, BarElement, CategoryScale, LinearScale, LineController, LineElement, PointElement, PieController, ArcElement, ScatterController, Tooltip, Colors, Legend } from 'chart.js';
|
|
87
89
|
import * as i2$4 from '@angular/material/sort';
|
|
88
90
|
import { MatSortModule, MatSort } from '@angular/material/sort';
|
|
@@ -90,7 +92,6 @@ import * as i1$b from '@angular/material/table';
|
|
|
90
92
|
import { MatTableModule } from '@angular/material/table';
|
|
91
93
|
import * as i3 from '@angular/material/paginator';
|
|
92
94
|
import { MatPaginatorIntl, MatPaginatorModule, MatPaginator } from '@angular/material/paginator';
|
|
93
|
-
import { LetDirective } from '@ngrx/component';
|
|
94
95
|
import { Meta } from '@angular/platform-browser';
|
|
95
96
|
import { tablerFolderOpen } from '@ng-icons/tabler-icons';
|
|
96
97
|
import * as i3$1 from '@angular/material/radio';
|
|
@@ -18907,14 +18908,29 @@ class Gn4FieldMapper {
|
|
|
18907
18908
|
featureTypes: selectField(source, 'featureTypes'),
|
|
18908
18909
|
}, output),
|
|
18909
18910
|
related: (output, source) => {
|
|
18910
|
-
const
|
|
18911
|
+
const related = selectField(source, 'related');
|
|
18912
|
+
const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
|
|
18911
18913
|
const featureCatalogIdentifier = selectField(fcatSource, 'uuid');
|
|
18912
|
-
const sourceOfLinks = getAsArray(selectField(
|
|
18914
|
+
const sourceOfLinks = getAsArray(selectField(related, 'hassources'));
|
|
18913
18915
|
const sourceOfIdentifiers = sourceOfLinks
|
|
18914
18916
|
.filter((link) => link['origin'] === 'catalog')
|
|
18915
18917
|
.map((link) => {
|
|
18916
18918
|
return selectField(selectField(link, '_source'), 'uuid');
|
|
18917
18919
|
});
|
|
18920
|
+
const siblingLinks = getAsArray(selectField(related, 'siblings'));
|
|
18921
|
+
const siblings = siblingLinks
|
|
18922
|
+
.filter((link) => link['origin'] === 'catalog')
|
|
18923
|
+
.map((link) => ({
|
|
18924
|
+
uniqueIdentifier: selectField(selectField(link, '_source'), 'uuid'),
|
|
18925
|
+
associationType: getAssociationTypeFromCode(selectField(selectField(link, 'properties'), 'associationType')),
|
|
18926
|
+
}));
|
|
18927
|
+
const associatedLinks = getAsArray(selectField(related, 'associated'));
|
|
18928
|
+
const associatedIdentifiers = associatedLinks
|
|
18929
|
+
.filter((link) => link['origin'] === 'catalog')
|
|
18930
|
+
.map((link) => {
|
|
18931
|
+
return selectField(selectField(link, '_source'), 'uuid');
|
|
18932
|
+
})
|
|
18933
|
+
.filter((uuid) => !siblings.some((sibling) => sibling.uniqueIdentifier === uuid));
|
|
18918
18934
|
const extraValues = {};
|
|
18919
18935
|
if (featureCatalogIdentifier) {
|
|
18920
18936
|
extraValues.featureCatalogIdentifier = featureCatalogIdentifier;
|
|
@@ -18922,6 +18938,12 @@ class Gn4FieldMapper {
|
|
|
18922
18938
|
if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
|
|
18923
18939
|
extraValues.sourceOfIdentifiers = sourceOfIdentifiers;
|
|
18924
18940
|
}
|
|
18941
|
+
if (associatedIdentifiers && associatedIdentifiers.length > 0) {
|
|
18942
|
+
extraValues.associatedIdentifiers = associatedIdentifiers;
|
|
18943
|
+
}
|
|
18944
|
+
if (siblings && siblings.length > 0) {
|
|
18945
|
+
extraValues.siblings = siblings;
|
|
18946
|
+
}
|
|
18925
18947
|
return Object.keys(extraValues).length > 0
|
|
18926
18948
|
? this.addExtra(extraValues, output)
|
|
18927
18949
|
: output;
|
|
@@ -19447,10 +19469,10 @@ class DateService {
|
|
|
19447
19469
|
const dateObj = this.getDateObject(date);
|
|
19448
19470
|
return { locale, dateObj };
|
|
19449
19471
|
}
|
|
19450
|
-
async
|
|
19472
|
+
async getDateFnsLocale() {
|
|
19451
19473
|
const lang = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE;
|
|
19452
19474
|
const locales = await this.dateLocales;
|
|
19453
|
-
return locales[lang];
|
|
19475
|
+
return locales[lang] ?? locales[DEFAULT_LANGUAGE];
|
|
19454
19476
|
}
|
|
19455
19477
|
formatDate(date, options) {
|
|
19456
19478
|
const { locale, dateObj } = this.getLocaleAndDate(date);
|
|
@@ -19463,7 +19485,7 @@ class DateService {
|
|
|
19463
19485
|
async formatRelativeDateTime(date) {
|
|
19464
19486
|
const dateObj = this.getDateObject(date);
|
|
19465
19487
|
const now = new Date();
|
|
19466
|
-
const locale = await this.
|
|
19488
|
+
const locale = await this.getDateFnsLocale();
|
|
19467
19489
|
return formatDistance(dateObj, now, {
|
|
19468
19490
|
addSuffix: true,
|
|
19469
19491
|
locale: locale,
|
|
@@ -19498,6 +19520,18 @@ function propagateToDocumentOnly(event) {
|
|
|
19498
19520
|
}, 0);
|
|
19499
19521
|
}
|
|
19500
19522
|
|
|
19523
|
+
function isFileExtensionValid(fileName, acceptedExtensions) {
|
|
19524
|
+
return acceptedExtensions.some((ext) => fileName.toLowerCase().endsWith(ext));
|
|
19525
|
+
}
|
|
19526
|
+
function readFileAsText(file) {
|
|
19527
|
+
return new Promise((resolve, reject) => {
|
|
19528
|
+
const reader = new FileReader();
|
|
19529
|
+
reader.onload = () => resolve(reader.result);
|
|
19530
|
+
reader.onerror = () => reject(reader.error);
|
|
19531
|
+
reader.readAsText(file);
|
|
19532
|
+
});
|
|
19533
|
+
}
|
|
19534
|
+
|
|
19501
19535
|
function formatUserInfo(userInfo, displayCount = false) {
|
|
19502
19536
|
const infos = (typeof userInfo === 'string' ? userInfo : '').split('|');
|
|
19503
19537
|
const count = displayCount ? ` ${infos[3].split(' ')[1]}` : '';
|
|
@@ -19557,6 +19591,24 @@ function getGeometryFromGeoJSON(data) {
|
|
|
19557
19591
|
}
|
|
19558
19592
|
return null;
|
|
19559
19593
|
}
|
|
19594
|
+
function isBoundingBox(value) {
|
|
19595
|
+
return (Array.isArray(value) &&
|
|
19596
|
+
value.length === 4 &&
|
|
19597
|
+
value.every((item) => typeof item === 'number'));
|
|
19598
|
+
}
|
|
19599
|
+
/**
|
|
19600
|
+
* Checks that a bounding box's coordinates stay within the valid
|
|
19601
|
+
* longitude (-180/180) and latitude (-90/90) ranges.
|
|
19602
|
+
*/
|
|
19603
|
+
function isBoundingBoxWithinWorldExtent(bbox) {
|
|
19604
|
+
const [minX, minY, maxX, maxY] = bbox;
|
|
19605
|
+
return (minX >= -180 &&
|
|
19606
|
+
maxX <= 180 &&
|
|
19607
|
+
minY >= -90 &&
|
|
19608
|
+
maxY <= 90 &&
|
|
19609
|
+
minX <= maxX &&
|
|
19610
|
+
minY <= maxY);
|
|
19611
|
+
}
|
|
19560
19612
|
function getGeometryBoundingBox(geometry) {
|
|
19561
19613
|
// use the bounding box if specified in the GeoJSON object
|
|
19562
19614
|
if (geometry.bbox) {
|
|
@@ -20225,7 +20277,7 @@ function getLinkLabel(link) {
|
|
|
20225
20277
|
const label = link.description || ('name' in link ? link.name : '');
|
|
20226
20278
|
return format ? `${label} (${format})` : label;
|
|
20227
20279
|
}
|
|
20228
|
-
async function getLayers(url, serviceProtocol) {
|
|
20280
|
+
async function getLayers(url, serviceProtocol, deep = false) {
|
|
20229
20281
|
switch (serviceProtocol) {
|
|
20230
20282
|
case 'ogcFeatures': {
|
|
20231
20283
|
const layers = await new OgcApiEndpoint(url).allCollections;
|
|
@@ -20233,7 +20285,10 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20233
20285
|
}
|
|
20234
20286
|
case 'wfs': {
|
|
20235
20287
|
const endpointWfs = await new WfsEndpoint(url).isReady();
|
|
20236
|
-
const featureTypes =
|
|
20288
|
+
const featureTypes = endpointWfs.getFeatureTypes();
|
|
20289
|
+
if (!deep) {
|
|
20290
|
+
return featureTypes;
|
|
20291
|
+
}
|
|
20237
20292
|
const layers = (await Promise.allSettled(featureTypes.map((collection) => {
|
|
20238
20293
|
return endpointWfs.getFeatureTypeFull(collection.name);
|
|
20239
20294
|
})))
|
|
@@ -20243,12 +20298,14 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20243
20298
|
}
|
|
20244
20299
|
case 'wms': {
|
|
20245
20300
|
const endpointWms = await new WmsEndpoint(url).isReady();
|
|
20246
|
-
const
|
|
20301
|
+
const layersSummary = endpointWms
|
|
20247
20302
|
.getLayers()
|
|
20248
20303
|
.flatMap(wmsLayerFlatten)
|
|
20249
|
-
.filter((l) => l.name)
|
|
20250
|
-
|
|
20251
|
-
|
|
20304
|
+
.filter((l) => l.name);
|
|
20305
|
+
if (!deep) {
|
|
20306
|
+
return layersSummary;
|
|
20307
|
+
}
|
|
20308
|
+
const layers = layersSummary.map((collection) => endpointWms.getLayerByName(collection.name));
|
|
20252
20309
|
return layers;
|
|
20253
20310
|
}
|
|
20254
20311
|
case 'wmts': {
|
|
@@ -20342,6 +20399,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20342
20399
|
}]
|
|
20343
20400
|
}] });
|
|
20344
20401
|
|
|
20402
|
+
class AutofocusDirective {
|
|
20403
|
+
constructor() {
|
|
20404
|
+
this.el = inject(ElementRef);
|
|
20405
|
+
this.injector = inject(Injector);
|
|
20406
|
+
}
|
|
20407
|
+
set autofocus(active) {
|
|
20408
|
+
if (!active)
|
|
20409
|
+
return;
|
|
20410
|
+
afterNextRender(() => this.el.nativeElement.focus(), {
|
|
20411
|
+
injector: this.injector,
|
|
20412
|
+
});
|
|
20413
|
+
}
|
|
20414
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
20415
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.19", type: AutofocusDirective, isStandalone: true, selector: "[gnUiAutofocus]", inputs: { autofocus: ["gnUiAutofocus", "autofocus", booleanAttribute] }, ngImport: i0 }); }
|
|
20416
|
+
}
|
|
20417
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, decorators: [{
|
|
20418
|
+
type: Directive,
|
|
20419
|
+
args: [{
|
|
20420
|
+
selector: '[gnUiAutofocus]',
|
|
20421
|
+
standalone: true,
|
|
20422
|
+
}]
|
|
20423
|
+
}], propDecorators: { autofocus: [{
|
|
20424
|
+
type: Input,
|
|
20425
|
+
args: [{ alias: 'gnUiAutofocus', transform: booleanAttribute }]
|
|
20426
|
+
}] } });
|
|
20427
|
+
|
|
20345
20428
|
class ImageFallbackDirective {
|
|
20346
20429
|
constructor() {
|
|
20347
20430
|
this.el = inject(ElementRef);
|
|
@@ -20369,7 +20452,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20369
20452
|
}] } });
|
|
20370
20453
|
|
|
20371
20454
|
var name = "geonetwork-ui";
|
|
20372
|
-
var version = "2.11.0-dev.
|
|
20455
|
+
var version = "2.11.0-dev.b7f9a229d";
|
|
20373
20456
|
var engines = {
|
|
20374
20457
|
node: ">=24"
|
|
20375
20458
|
};
|
|
@@ -20390,6 +20473,7 @@ var peerDependencies = {
|
|
|
20390
20473
|
"@angular/core": "19.x || 20.x || 21.x",
|
|
20391
20474
|
"@angular/forms": "19.x || 20.x || 21.x",
|
|
20392
20475
|
"@angular/material": "19.x || 20.x || 21.x",
|
|
20476
|
+
"@angular/material-date-fns-adapter": "19.x || 20.x",
|
|
20393
20477
|
"@angular/platform-browser": "19.x || 20.x || 21.x",
|
|
20394
20478
|
"@angular/platform-browser-dynamic": "19.x || 20.x || 21.x",
|
|
20395
20479
|
"@angular/router": "19.x || 20.x || 21.x",
|
|
@@ -20399,20 +20483,21 @@ var peerDependencies = {
|
|
|
20399
20483
|
"@ngrx/store": "19.x || 20.x || 21.x",
|
|
20400
20484
|
"@ngrx/store-devtools": "19.x || 20.x || 21.x",
|
|
20401
20485
|
"@ngrx/operators": "19.x || 20.x || 21.x",
|
|
20402
|
-
"@ngx-translate/core": "
|
|
20403
|
-
"@ngx-translate/http-loader": "
|
|
20404
|
-
"flag-icons": "
|
|
20486
|
+
"@ngx-translate/core": "17.x",
|
|
20487
|
+
"@ngx-translate/http-loader": "17.x",
|
|
20488
|
+
"flag-icons": "~7.5.0",
|
|
20405
20489
|
rxjs: "7.x",
|
|
20406
20490
|
"zone.js": "*",
|
|
20407
20491
|
tailwindcss: "3.x"
|
|
20408
20492
|
};
|
|
20409
20493
|
var dependencies = {
|
|
20410
20494
|
"@biesbjerg/ngx-translate-extract-marker": "~1.0.0",
|
|
20411
|
-
"@camptocamp/ogc-client": "1.3.1-dev.
|
|
20412
|
-
"@
|
|
20413
|
-
"@geospatial-sdk/
|
|
20414
|
-
"@geospatial-sdk/
|
|
20415
|
-
"@geospatial-sdk/
|
|
20495
|
+
"@camptocamp/ogc-client": "1.3.1-dev.200c02a",
|
|
20496
|
+
"@duckdb/duckdb-wasm": "~1.32.0",
|
|
20497
|
+
"@geospatial-sdk/core": "0.0.5-dev.78",
|
|
20498
|
+
"@geospatial-sdk/geocoding": "0.0.5-dev.78",
|
|
20499
|
+
"@geospatial-sdk/legend": "0.0.5-dev.78",
|
|
20500
|
+
"@geospatial-sdk/openlayers": "0.0.5-dev.78",
|
|
20416
20501
|
"@ltd/j-toml": "~1.38.0",
|
|
20417
20502
|
"@messageformat/core": "~3.4.0",
|
|
20418
20503
|
"@ng-icons/core": "~32.5.0",
|
|
@@ -20420,7 +20505,7 @@ var dependencies = {
|
|
|
20420
20505
|
"@ng-icons/material-icons": "~32.5.0",
|
|
20421
20506
|
"@ng-icons/tabler-icons": "~32.4.0",
|
|
20422
20507
|
"@rgrove/parse-xml": "4.2.0",
|
|
20423
|
-
|
|
20508
|
+
"apache-arrow": "~17.0.0",
|
|
20424
20509
|
"chart.js": "~4.5.1",
|
|
20425
20510
|
"chroma-js": "~3.2.0",
|
|
20426
20511
|
"date-fns": "4.1.0",
|
|
@@ -20433,7 +20518,6 @@ var dependencies = {
|
|
|
20433
20518
|
"ngx-dropzone": "~3.1.0",
|
|
20434
20519
|
"ngx-translate-messageformat-compiler": "~7.2.0",
|
|
20435
20520
|
ol: "~10.8.0",
|
|
20436
|
-
papaparse: "~5.5.3",
|
|
20437
20521
|
proj4: "~2.20.4",
|
|
20438
20522
|
rdflib: "~2.3.5",
|
|
20439
20523
|
semver: "~7.7.4",
|
|
@@ -20631,8 +20715,8 @@ class ElasticsearchService {
|
|
|
20631
20715
|
if (!payload.runtime_mappings)
|
|
20632
20716
|
payload.runtime_mappings = {};
|
|
20633
20717
|
payload.runtime_mappings[fieldName] = {
|
|
20634
|
-
type:
|
|
20635
|
-
script: this.runtimeFields[fieldName],
|
|
20718
|
+
type: this.runtimeFields[fieldName].type,
|
|
20719
|
+
script: this.runtimeFields[fieldName].script,
|
|
20636
20720
|
};
|
|
20637
20721
|
};
|
|
20638
20722
|
const lookForField = (node) => {
|
|
@@ -20652,6 +20736,12 @@ class ElasticsearchService {
|
|
|
20652
20736
|
(node[runtimeField] === 'asc' || node[runtimeField] === 'desc')) {
|
|
20653
20737
|
addMapping(runtimeField);
|
|
20654
20738
|
}
|
|
20739
|
+
if (runtimeField in node &&
|
|
20740
|
+
typeof node[runtimeField] === 'object' &&
|
|
20741
|
+
node[runtimeField] !== null &&
|
|
20742
|
+
('gte' in node[runtimeField] || 'lte' in node[runtimeField])) {
|
|
20743
|
+
addMapping(runtimeField);
|
|
20744
|
+
}
|
|
20655
20745
|
if ('query' in node &&
|
|
20656
20746
|
typeof node.query === 'string' &&
|
|
20657
20747
|
node.query.indexOf(runtimeField + ':') > -1) {
|
|
@@ -20668,8 +20758,8 @@ class ElasticsearchService {
|
|
|
20668
20758
|
lookForField(payload.query);
|
|
20669
20759
|
return payload;
|
|
20670
20760
|
}
|
|
20671
|
-
registerRuntimeField(fieldName, expression) {
|
|
20672
|
-
this.runtimeFields[fieldName] = expression;
|
|
20761
|
+
registerRuntimeField(fieldName, expression, type = 'keyword') {
|
|
20762
|
+
this.runtimeFields[fieldName] = { script: expression, type };
|
|
20673
20763
|
}
|
|
20674
20764
|
getMetadataByIdsPayload(uuids) {
|
|
20675
20765
|
return {
|
|
@@ -20678,6 +20768,7 @@ class ElasticsearchService {
|
|
|
20678
20768
|
values: uuids,
|
|
20679
20769
|
},
|
|
20680
20770
|
},
|
|
20771
|
+
size: uuids.length,
|
|
20681
20772
|
};
|
|
20682
20773
|
}
|
|
20683
20774
|
getRelatedRecordPayload(record, size = 6, _source = [...ES_SOURCE_SUMMARY, 'createDate']) {
|
|
@@ -20785,7 +20876,49 @@ class ElasticsearchService {
|
|
|
20785
20876
|
isCurrentSearchLang() {
|
|
20786
20877
|
return this.metadataLang === 'current';
|
|
20787
20878
|
}
|
|
20788
|
-
|
|
20879
|
+
findSpatialFilterExtent(filters) {
|
|
20880
|
+
if (typeof filters === 'string') {
|
|
20881
|
+
return undefined;
|
|
20882
|
+
}
|
|
20883
|
+
return Object.values(filters).find(isBoundingBox);
|
|
20884
|
+
}
|
|
20885
|
+
// if a field registered min/max runtime fields, its dates form an interval
|
|
20886
|
+
// the record matches if that interval intersects the filter range
|
|
20887
|
+
buildDateRangeQuery(searchField, dateRange) {
|
|
20888
|
+
const minField = `${searchField}Min`;
|
|
20889
|
+
const maxField = `${searchField}Max`;
|
|
20890
|
+
if (minField in this.runtimeFields && maxField in this.runtimeFields) {
|
|
20891
|
+
const filter = [
|
|
20892
|
+
dateRange.start && {
|
|
20893
|
+
range: {
|
|
20894
|
+
[maxField]: {
|
|
20895
|
+
gte: formatDate(dateRange.start),
|
|
20896
|
+
format: 'yyyy-MM-dd',
|
|
20897
|
+
},
|
|
20898
|
+
},
|
|
20899
|
+
},
|
|
20900
|
+
dateRange.end && {
|
|
20901
|
+
range: {
|
|
20902
|
+
[minField]: {
|
|
20903
|
+
lte: formatDate(dateRange.end),
|
|
20904
|
+
format: 'yyyy-MM-dd',
|
|
20905
|
+
},
|
|
20906
|
+
},
|
|
20907
|
+
},
|
|
20908
|
+
].filter(Boolean);
|
|
20909
|
+
return { bool: { filter } };
|
|
20910
|
+
}
|
|
20911
|
+
return {
|
|
20912
|
+
range: {
|
|
20913
|
+
[searchField]: {
|
|
20914
|
+
...(dateRange.start && { gte: formatDate(dateRange.start) }),
|
|
20915
|
+
...(dateRange.end && { lte: formatDate(dateRange.end) }),
|
|
20916
|
+
format: 'yyyy-MM-dd',
|
|
20917
|
+
},
|
|
20918
|
+
},
|
|
20919
|
+
};
|
|
20920
|
+
}
|
|
20921
|
+
filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
|
|
20789
20922
|
const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
|
|
20790
20923
|
const makeQuery = (filter) => {
|
|
20791
20924
|
if (typeof filter === 'string') {
|
|
@@ -20804,7 +20937,9 @@ class ElasticsearchService {
|
|
|
20804
20937
|
? filters
|
|
20805
20938
|
: Object.keys(filters)
|
|
20806
20939
|
.filter((fieldname) => fieldname !== 'gn-ui-crossFieldFilter')
|
|
20940
|
+
.filter((fieldname) => !isBoundingBox(filters[fieldname]))
|
|
20807
20941
|
.filter((fieldname) => !isDateRange(filters[fieldname]))
|
|
20942
|
+
.filter((fieldname) => !Array.isArray(filters[fieldname]))
|
|
20808
20943
|
.filter((fieldname) => filters[fieldname] &&
|
|
20809
20944
|
JSON.stringify(filters[fieldname]) !== '{}')
|
|
20810
20945
|
.map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
|
|
@@ -20812,31 +20947,26 @@ class ElasticsearchService {
|
|
|
20812
20947
|
if (filters['gn-ui-crossFieldFilter']) {
|
|
20813
20948
|
queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
|
|
20814
20949
|
}
|
|
20815
|
-
const
|
|
20816
|
-
.filter(([, value]) => isDateRange(value))
|
|
20817
|
-
.map(([searchField, dateRange]) => {
|
|
20818
|
-
return {
|
|
20819
|
-
searchField,
|
|
20820
|
-
dateRange,
|
|
20821
|
-
};
|
|
20822
|
-
})[0];
|
|
20950
|
+
const queryRanges = Object.entries(filters).filter(([, value]) => isDateRange(value));
|
|
20823
20951
|
const queryParts = [
|
|
20824
20952
|
queryString && {
|
|
20825
20953
|
query_string: {
|
|
20826
20954
|
query: queryString,
|
|
20827
20955
|
},
|
|
20828
20956
|
},
|
|
20829
|
-
|
|
20830
|
-
|
|
20831
|
-
|
|
20832
|
-
|
|
20833
|
-
|
|
20834
|
-
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
|
|
20839
|
-
|
|
20957
|
+
...queryRanges.map(([searchField, dateRange]) => this.buildDateRangeQuery(searchField, dateRange)),
|
|
20958
|
+
spatialFilterExtent && {
|
|
20959
|
+
geo_shape: {
|
|
20960
|
+
geom: {
|
|
20961
|
+
shape: {
|
|
20962
|
+
type: 'envelope',
|
|
20963
|
+
// spatialFilterExtent is [minX, minY, maxX, maxY]; envelope coordinates are [top-left, bottom-right]
|
|
20964
|
+
coordinates: [
|
|
20965
|
+
[spatialFilterExtent[0], spatialFilterExtent[3]],
|
|
20966
|
+
[spatialFilterExtent[2], spatialFilterExtent[1]],
|
|
20967
|
+
],
|
|
20968
|
+
},
|
|
20969
|
+
relation: 'intersects',
|
|
20840
20970
|
},
|
|
20841
20971
|
},
|
|
20842
20972
|
},
|
|
@@ -20866,7 +20996,9 @@ class ElasticsearchService {
|
|
|
20866
20996
|
},
|
|
20867
20997
|
});
|
|
20868
20998
|
}
|
|
20869
|
-
|
|
20999
|
+
// a spatial extent filter takes precedence over the preference geometry for boosting
|
|
21000
|
+
const spatialFilterExtent = this.findSpatialFilterExtent(fieldSearchFilters);
|
|
21001
|
+
const queryFilters = this.filtersToQuery(fieldSearchFilters, spatialFilterExtent);
|
|
20870
21002
|
if (queryFilters) {
|
|
20871
21003
|
filter.push(...queryFilters);
|
|
20872
21004
|
}
|
|
@@ -20877,7 +21009,10 @@ class ElasticsearchService {
|
|
|
20877
21009
|
},
|
|
20878
21010
|
});
|
|
20879
21011
|
}
|
|
20880
|
-
|
|
21012
|
+
const boostGeometry = spatialFilterExtent
|
|
21013
|
+
? bboxToPolygon(spatialFilterExtent)
|
|
21014
|
+
: geometry;
|
|
21015
|
+
if (boostGeometry) {
|
|
20881
21016
|
// boosts applied using the filter geometry:
|
|
20882
21017
|
// * records completely within the geometry receive a boost of 5
|
|
20883
21018
|
// * records intersecting the geometry receive a boost of 2
|
|
@@ -20886,7 +21021,7 @@ class ElasticsearchService {
|
|
|
20886
21021
|
should.push({
|
|
20887
21022
|
geo_shape: {
|
|
20888
21023
|
geom: {
|
|
20889
|
-
shape:
|
|
21024
|
+
shape: boostGeometry,
|
|
20890
21025
|
relation: 'within',
|
|
20891
21026
|
},
|
|
20892
21027
|
boost: 5.0,
|
|
@@ -20894,7 +21029,7 @@ class ElasticsearchService {
|
|
|
20894
21029
|
}, {
|
|
20895
21030
|
geo_shape: {
|
|
20896
21031
|
geom: {
|
|
20897
|
-
shape:
|
|
21032
|
+
shape: boostGeometry,
|
|
20898
21033
|
relation: 'intersects',
|
|
20899
21034
|
},
|
|
20900
21035
|
boost: 2.0,
|
|
@@ -20903,7 +21038,7 @@ class ElasticsearchService {
|
|
|
20903
21038
|
// this will boost the results variably depending on their distance from the given geometry
|
|
20904
21039
|
// note: this takes into account the `location` field of a record; this is generally the center of all spatial extents
|
|
20905
21040
|
// combined, and thus the actual size/coverage of the record spatial extent isn't relevant here
|
|
20906
|
-
const bbox = getGeometryBoundingBox(
|
|
21041
|
+
const bbox = getGeometryBoundingBox(boostGeometry);
|
|
20907
21042
|
const center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
|
20908
21043
|
const northToCenter = new LineString([
|
|
20909
21044
|
[center[0], bbox[3]],
|
|
@@ -21229,7 +21364,7 @@ class Gn4Repository {
|
|
|
21229
21364
|
}
|
|
21230
21365
|
getRecord(uniqueIdentifier) {
|
|
21231
21366
|
return this.gn4SearchApi
|
|
21232
|
-
.search('bucket', ['fcats', 'hassources'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21367
|
+
.search('bucket', ['fcats', 'hassources', 'siblings', 'associated'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21233
21368
|
.pipe(map$1((results) => results.hits.hits[0]), switchMap((record) => record ? this.gn4Mapper.readRecord(record) : of(null)));
|
|
21234
21369
|
}
|
|
21235
21370
|
getMultipleRecords(uniqueIdentifiers) {
|
|
@@ -21283,19 +21418,28 @@ class Gn4Repository {
|
|
|
21283
21418
|
.search('bucket', null, JSON.stringify(this.gn4SearchHelper.getRelatedRecordPayload(similarTo, 3)))
|
|
21284
21419
|
.pipe(switchMap((results) => this.gn4Mapper.readRecords(results.hits.hits)));
|
|
21285
21420
|
}
|
|
21286
|
-
|
|
21287
|
-
const
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21291
|
-
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21295
|
-
|
|
21296
|
-
|
|
21421
|
+
getLinkedRecords(record) {
|
|
21422
|
+
const siblings = (record.extras?.['siblings'] ?? []);
|
|
21423
|
+
const relations = [
|
|
21424
|
+
['source', (record.extras?.['sourcesIdentifiers'] ?? [])],
|
|
21425
|
+
['sourceOf', (record.extras?.['sourceOfIdentifiers'] ?? [])],
|
|
21426
|
+
['sibling', siblings.map(({ uniqueIdentifier }) => uniqueIdentifier)],
|
|
21427
|
+
[
|
|
21428
|
+
'associated',
|
|
21429
|
+
(record.extras?.['associatedIdentifiers'] ?? []),
|
|
21430
|
+
],
|
|
21431
|
+
];
|
|
21432
|
+
const requested = relations.filter(([, identifiers]) => identifiers.length > 0);
|
|
21433
|
+
if (requested.length === 0) {
|
|
21434
|
+
return of([]);
|
|
21297
21435
|
}
|
|
21298
|
-
return
|
|
21436
|
+
return forkJoin(requested.map(([relation, identifiers]) => this.getMultipleRecords(identifiers).pipe(map$1((records) => (records ?? []).map((record) => ({
|
|
21437
|
+
record,
|
|
21438
|
+
relation,
|
|
21439
|
+
associationType: relation === 'sibling'
|
|
21440
|
+
? siblings.find(({ uniqueIdentifier }) => uniqueIdentifier === record.uniqueIdentifier)?.associationType
|
|
21441
|
+
: undefined,
|
|
21442
|
+
}))), catchError(() => of([]))))).pipe(map$1((groups) => groups.flat()));
|
|
21299
21443
|
}
|
|
21300
21444
|
aggregate(params) {
|
|
21301
21445
|
// if aggregations are empty, return an empty object right away
|
|
@@ -22484,48 +22628,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22484
22628
|
type: Injectable
|
|
22485
22629
|
}] });
|
|
22486
22630
|
|
|
22487
|
-
const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider');
|
|
22488
|
-
class GeocodingService {
|
|
22489
|
-
constructor() {
|
|
22490
|
-
this.provider = inject(GEOCODING_PROVIDER);
|
|
22491
|
-
}
|
|
22492
|
-
query(text) {
|
|
22493
|
-
let queryObservable;
|
|
22494
|
-
switch (this.provider[0]) {
|
|
22495
|
-
case 'geoadmin':
|
|
22496
|
-
queryObservable = from(queryGeoadmin(text, this.provider[1]));
|
|
22497
|
-
break;
|
|
22498
|
-
case 'geonames':
|
|
22499
|
-
queryObservable = from(queryGeonames(text, this.provider[1]));
|
|
22500
|
-
break;
|
|
22501
|
-
case 'data-gouv-fr':
|
|
22502
|
-
queryObservable = from(queryDataGouvFr(text, this.provider[1]));
|
|
22503
|
-
break;
|
|
22504
|
-
default:
|
|
22505
|
-
return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
|
|
22506
|
-
}
|
|
22507
|
-
return queryObservable.pipe(catchError((error) => throwError(error)));
|
|
22508
|
-
}
|
|
22509
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
22510
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
|
|
22511
|
-
}
|
|
22512
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
|
|
22513
|
-
type: Injectable,
|
|
22514
|
-
args: [{
|
|
22515
|
-
providedIn: 'root',
|
|
22516
|
-
}]
|
|
22517
|
-
}] });
|
|
22518
|
-
|
|
22519
22631
|
class FeatureMapModule {
|
|
22520
22632
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
22521
22633
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, imports: [i1.StoreFeatureModule] }); }
|
|
22522
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [
|
|
22523
|
-
MapFacade,
|
|
22524
|
-
{
|
|
22525
|
-
provide: GEOCODING_PROVIDER,
|
|
22526
|
-
useValue: ['geonames', { maxRows: 5 }],
|
|
22527
|
-
},
|
|
22528
|
-
], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
|
|
22634
|
+
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)] }); }
|
|
22529
22635
|
}
|
|
22530
22636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, decorators: [{
|
|
22531
22637
|
type: NgModule,
|
|
@@ -22533,13 +22639,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22533
22639
|
imports: [
|
|
22534
22640
|
StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
|
|
22535
22641
|
],
|
|
22536
|
-
providers: [
|
|
22537
|
-
MapFacade,
|
|
22538
|
-
{
|
|
22539
|
-
provide: GEOCODING_PROVIDER,
|
|
22540
|
-
useValue: ['geonames', { maxRows: 5 }],
|
|
22541
|
-
},
|
|
22542
|
-
],
|
|
22642
|
+
providers: [MapFacade],
|
|
22543
22643
|
}]
|
|
22544
22644
|
}] });
|
|
22545
22645
|
|
|
@@ -22556,9 +22656,10 @@ const VECTOR_STYLE_DEFAULT = new InjectionToken('vectorStyleDefault', {
|
|
|
22556
22656
|
});
|
|
22557
22657
|
|
|
22558
22658
|
const DEFAULT_BASEMAP_LAYER = {
|
|
22559
|
-
type: '
|
|
22560
|
-
|
|
22561
|
-
|
|
22659
|
+
type: 'maplibre-style',
|
|
22660
|
+
styleUrl: `https://basemaps.cartocdn.com/gl/positron-gl-style/style.json`,
|
|
22661
|
+
clickable: false,
|
|
22662
|
+
hoverable: false,
|
|
22562
22663
|
};
|
|
22563
22664
|
const DEFAULT_VIEW = {
|
|
22564
22665
|
center: [0, 15],
|
|
@@ -23273,6 +23374,9 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23273
23374
|
'search_preset',
|
|
23274
23375
|
'advanced_filters',
|
|
23275
23376
|
'limit',
|
|
23377
|
+
'spatial_extent_max_file_size',
|
|
23378
|
+
'geocoding_provider',
|
|
23379
|
+
'geocoding_provider_options',
|
|
23276
23380
|
], warnings, errors);
|
|
23277
23381
|
const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
|
|
23278
23382
|
searchConfig =
|
|
@@ -23290,6 +23394,9 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23290
23394
|
})),
|
|
23291
23395
|
ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
|
|
23292
23396
|
LIMIT: parsedSearchSection.limit,
|
|
23397
|
+
SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
|
|
23398
|
+
GEOCODING_PROVIDER: parsedSearchSection.geocoding_provider,
|
|
23399
|
+
GEOCODING_PROVIDER_OPTIONS: parsedSearchSection.geocoding_provider_options,
|
|
23293
23400
|
};
|
|
23294
23401
|
const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
|
|
23295
23402
|
metadataQualityConfig =
|
|
@@ -23398,6 +23505,9 @@ fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
|
|
|
23398
23505
|
record_kind_quick_filter = false
|
|
23399
23506
|
filter_geometry_url = 'https://my.domain.org/geom.json'
|
|
23400
23507
|
do_not_use_default_search_preset = false
|
|
23508
|
+
geocoding_provider = "geoplateforme"
|
|
23509
|
+
geocoding_provider_options.category = "administratif"
|
|
23510
|
+
geocoding_provider_options.limit = 5
|
|
23401
23511
|
advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license']
|
|
23402
23512
|
|
|
23403
23513
|
[[search_preset]]
|
|
@@ -24347,7 +24457,7 @@ class AutocompleteComponent {
|
|
|
24347
24457
|
this.enterBtnPosition = event.target['value'].length * 8 + 80;
|
|
24348
24458
|
}
|
|
24349
24459
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24350
|
-
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: [
|
|
24460
|
+
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: [
|
|
24351
24461
|
provideIcons({
|
|
24352
24462
|
iconoirSearch,
|
|
24353
24463
|
matClose,
|
|
@@ -24356,7 +24466,7 @@ class AutocompleteComponent {
|
|
|
24356
24466
|
provideNgIconsConfig({
|
|
24357
24467
|
size: '1.75rem',
|
|
24358
24468
|
}),
|
|
24359
|
-
], 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 }); }
|
|
24469
|
+
], 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 }); }
|
|
24360
24470
|
}
|
|
24361
24471
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
|
|
24362
24472
|
type: Component,
|
|
@@ -24377,7 +24487,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24377
24487
|
provideNgIconsConfig({
|
|
24378
24488
|
size: '1.75rem',
|
|
24379
24489
|
}),
|
|
24380
|
-
], 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"] }]
|
|
24490
|
+
], 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"] }]
|
|
24381
24491
|
}], propDecorators: { placeholder: [{
|
|
24382
24492
|
type: Input
|
|
24383
24493
|
}], enterButton: [{
|
|
@@ -24415,6 +24525,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24415
24525
|
}], inputRef: [{
|
|
24416
24526
|
type: ViewChild,
|
|
24417
24527
|
args: ['searchInput']
|
|
24528
|
+
}], displayWithTemplate: [{
|
|
24529
|
+
type: Input
|
|
24418
24530
|
}], displayWithFn: [{
|
|
24419
24531
|
type: Input
|
|
24420
24532
|
}] } });
|
|
@@ -24547,12 +24659,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24547
24659
|
type: Input
|
|
24548
24660
|
}] } });
|
|
24549
24661
|
|
|
24662
|
+
function provideLocalizedDateAdapter() {
|
|
24663
|
+
return [
|
|
24664
|
+
{ provide: MAT_DATE_LOCALE, useValue: enUS },
|
|
24665
|
+
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
|
|
24666
|
+
{
|
|
24667
|
+
provide: DateAdapter,
|
|
24668
|
+
useFactory: () => {
|
|
24669
|
+
const dateService = inject(DateService);
|
|
24670
|
+
const adapter = new DateFnsAdapter();
|
|
24671
|
+
dateService
|
|
24672
|
+
.getDateFnsLocale()
|
|
24673
|
+
.then((locale) => adapter.setLocale(locale));
|
|
24674
|
+
return adapter;
|
|
24675
|
+
},
|
|
24676
|
+
},
|
|
24677
|
+
];
|
|
24678
|
+
}
|
|
24679
|
+
|
|
24550
24680
|
class DatePickerComponent {
|
|
24551
24681
|
constructor() {
|
|
24552
|
-
this.dateAdapter = inject(DateAdapter);
|
|
24553
|
-
this.translate = inject(TranslateService);
|
|
24554
24682
|
this.dateChange = new EventEmitter();
|
|
24555
|
-
this.dateAdapter.setLocale(this.translate.getCurrentLang());
|
|
24556
24683
|
}
|
|
24557
24684
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24558
24685
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: DatePickerComponent, isStandalone: true, selector: "gn-ui-date-picker", inputs: { date: "date" }, outputs: { dateChange: "dateChange" }, providers: [
|
|
@@ -24560,30 +24687,19 @@ class DatePickerComponent {
|
|
|
24560
24687
|
provideNgIconsConfig({
|
|
24561
24688
|
size: '1.5rem',
|
|
24562
24689
|
}),
|
|
24563
|
-
|
|
24564
|
-
|
|
24565
|
-
useFactory: (locale) => locale,
|
|
24566
|
-
},
|
|
24567
|
-
], ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n <input\n class=\"gn-ui-text-input pr-[var(--text-padding)]\"\n [matDatepicker]=\"picker\"\n [value]=\"date\"\n (dateChange)=\"dateChange.emit($event.value)\"\n />\n <gn-ui-button\n type=\"light\"\n class=\"absolute inset-y-[var(--side-padding)] right-[var(--side-padding)] z-10\"\n (buttonClick)=\"picker.open()\"\n data-cy=\"date-picker-button\"\n extraClass=\"h-full\"\n >\n <ng-icon name=\"iconoirCalendar\" class=\"text-primary\"></ng-icon>\n </gn-ui-button>\n</span>\n<mat-datepicker #picker></mat-datepicker>\n", styles: [":host{--gn-ui-button-rounded: 8px;--gn-ui-button-width: 32px;--gn-ui-button-padding: 0;--side-padding: calc(var(--gn-ui-text-input-padding, .6em) - 6px);--text-padding: calc(var(--side-padding) + 40px)}\n"], dependencies: [{ kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i1$6.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i1$6.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24690
|
+
provideLocalizedDateAdapter(),
|
|
24691
|
+
], ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n <input\n class=\"gn-ui-text-input pr-[var(--text-padding)]\"\n [matDatepicker]=\"picker\"\n [value]=\"date\"\n (dateChange)=\"dateChange.emit($event.value)\"\n />\n <gn-ui-button\n type=\"light\"\n class=\"absolute inset-y-[var(--side-padding)] right-[var(--side-padding)] z-10\"\n (buttonClick)=\"picker.open()\"\n data-cy=\"date-picker-button\"\n extraClass=\"h-full\"\n >\n <ng-icon name=\"iconoirCalendar\" class=\"text-primary\"></ng-icon>\n </gn-ui-button>\n</span>\n<mat-datepicker #picker></mat-datepicker>\n", styles: [":host{--gn-ui-button-rounded: 8px;--gn-ui-button-width: 32px;--gn-ui-button-padding: 0;--side-padding: calc(var(--gn-ui-text-input-padding, .6em) - 6px);--text-padding: calc(var(--side-padding) + 40px)}\n"], dependencies: [{ kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i1$6.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i1$6.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24568
24692
|
}
|
|
24569
24693
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
24570
24694
|
type: Component,
|
|
24571
|
-
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24572
|
-
MatNativeDateModule,
|
|
24573
|
-
MatDatepickerModule,
|
|
24574
|
-
ButtonComponent,
|
|
24575
|
-
NgIconComponent,
|
|
24576
|
-
], providers: [
|
|
24695
|
+
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24577
24696
|
provideIcons({ iconoirCalendar }),
|
|
24578
24697
|
provideNgIconsConfig({
|
|
24579
24698
|
size: '1.5rem',
|
|
24580
24699
|
}),
|
|
24581
|
-
|
|
24582
|
-
provide: MAT_DATE_LOCALE,
|
|
24583
|
-
useFactory: (locale) => locale,
|
|
24584
|
-
},
|
|
24700
|
+
provideLocalizedDateAdapter(),
|
|
24585
24701
|
], template: "<span class=\"w-full inline-block relative\">\n <input\n class=\"gn-ui-text-input pr-[var(--text-padding)]\"\n [matDatepicker]=\"picker\"\n [value]=\"date\"\n (dateChange)=\"dateChange.emit($event.value)\"\n />\n <gn-ui-button\n type=\"light\"\n class=\"absolute inset-y-[var(--side-padding)] right-[var(--side-padding)] z-10\"\n (buttonClick)=\"picker.open()\"\n data-cy=\"date-picker-button\"\n extraClass=\"h-full\"\n >\n <ng-icon name=\"iconoirCalendar\" class=\"text-primary\"></ng-icon>\n </gn-ui-button>\n</span>\n<mat-datepicker #picker></mat-datepicker>\n", styles: [":host{--gn-ui-button-rounded: 8px;--gn-ui-button-width: 32px;--gn-ui-button-padding: 0;--side-padding: calc(var(--gn-ui-text-input-padding, .6em) - 6px);--text-padding: calc(var(--side-padding) + 40px)}\n"] }]
|
|
24586
|
-
}],
|
|
24702
|
+
}], propDecorators: { date: [{
|
|
24587
24703
|
type: Input
|
|
24588
24704
|
}], dateChange: [{
|
|
24589
24705
|
type: Output
|
|
@@ -24591,58 +24707,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24591
24707
|
|
|
24592
24708
|
class DateRangeDropdownComponent {
|
|
24593
24709
|
constructor() {
|
|
24594
|
-
this.
|
|
24710
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
24711
|
+
this.dateAdapter = inject(DateAdapter);
|
|
24712
|
+
this.dateFormats = inject(MAT_DATE_FORMATS);
|
|
24595
24713
|
this.cdr = inject(ChangeDetectorRef);
|
|
24596
|
-
this.
|
|
24597
|
-
this.
|
|
24598
|
-
this.
|
|
24714
|
+
this.dateRange = {};
|
|
24715
|
+
this.dateRangeChange = new EventEmitter();
|
|
24716
|
+
this.overlayPositions = [
|
|
24717
|
+
{
|
|
24718
|
+
originX: 'start',
|
|
24719
|
+
originY: 'bottom',
|
|
24720
|
+
overlayX: 'start',
|
|
24721
|
+
overlayY: 'top',
|
|
24722
|
+
offsetY: 8,
|
|
24723
|
+
},
|
|
24724
|
+
{
|
|
24725
|
+
originX: 'start',
|
|
24726
|
+
originY: 'top',
|
|
24727
|
+
overlayX: 'start',
|
|
24728
|
+
overlayY: 'bottom',
|
|
24729
|
+
offsetY: -8,
|
|
24730
|
+
},
|
|
24731
|
+
];
|
|
24732
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
24733
|
+
this.overlayOpen = false;
|
|
24734
|
+
this.expandedBound = 'start';
|
|
24735
|
+
this.invalidBounds = { start: false, end: false };
|
|
24736
|
+
// redraw when the lazily loaded UI locale reaches the adapter
|
|
24737
|
+
this.dateAdapter.localeChanges
|
|
24738
|
+
.pipe(takeUntilDestroyed())
|
|
24739
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
24599
24740
|
}
|
|
24600
|
-
|
|
24601
|
-
this.
|
|
24741
|
+
get startDate() {
|
|
24742
|
+
return this.dateRange.start;
|
|
24602
24743
|
}
|
|
24603
|
-
|
|
24604
|
-
|
|
24605
|
-
|
|
24606
|
-
|
|
24607
|
-
|
|
24608
|
-
|
|
24609
|
-
|
|
24610
|
-
|
|
24744
|
+
get endDate() {
|
|
24745
|
+
return this.dateRange.end;
|
|
24746
|
+
}
|
|
24747
|
+
get selectedDatesCount() {
|
|
24748
|
+
return (this.startDate ? 1 : 0) + (this.endDate ? 1 : 0);
|
|
24749
|
+
}
|
|
24750
|
+
openOverlay() {
|
|
24751
|
+
this.expandedBound = 'start';
|
|
24752
|
+
this.overlayOpen = true;
|
|
24753
|
+
}
|
|
24754
|
+
closeOverlay() {
|
|
24755
|
+
this.overlayOpen = false;
|
|
24756
|
+
}
|
|
24757
|
+
toggleBound(bound) {
|
|
24758
|
+
this.expandedBound = this.expandedBound === bound ? null : bound;
|
|
24759
|
+
}
|
|
24760
|
+
formatDate(date) {
|
|
24761
|
+
return this.dateAdapter.format(date, this.dateFormats.display.dateInput);
|
|
24762
|
+
}
|
|
24763
|
+
onDateInput(bound, event) {
|
|
24764
|
+
const typedText = event.target.value.trim();
|
|
24765
|
+
const date = typedText
|
|
24766
|
+
? this.dateAdapter.parse(typedText, this.dateFormats.parse.dateInput)
|
|
24767
|
+
: null;
|
|
24768
|
+
if (!this.isAcceptable(bound, typedText, date)) {
|
|
24769
|
+
// keep the text as typed and flag it; the filter stays on its last value
|
|
24770
|
+
this.invalidBounds = { ...this.invalidBounds, [bound]: true };
|
|
24771
|
+
return;
|
|
24772
|
+
}
|
|
24773
|
+
if (bound === 'start')
|
|
24774
|
+
this.setStartDate(date);
|
|
24775
|
+
else
|
|
24776
|
+
this.setEndDate(date);
|
|
24777
|
+
}
|
|
24778
|
+
normalizeDateInput(bound, event) {
|
|
24779
|
+
if (this.invalidBounds[bound])
|
|
24780
|
+
return;
|
|
24781
|
+
const date = bound === 'start' ? this.startDate : this.endDate;
|
|
24782
|
+
const input = event.target;
|
|
24783
|
+
input.value = date ? this.formatDate(date) : '';
|
|
24784
|
+
}
|
|
24785
|
+
isAcceptable(bound, typedText, date) {
|
|
24786
|
+
if (!typedText)
|
|
24787
|
+
return true;
|
|
24788
|
+
if (!date || !this.dateAdapter.isValid(date))
|
|
24789
|
+
return false;
|
|
24790
|
+
return bound === 'start'
|
|
24791
|
+
? !this.endDate || date <= this.endDate
|
|
24792
|
+
: !this.startDate || date >= this.startDate;
|
|
24793
|
+
}
|
|
24794
|
+
setStartDate(date) {
|
|
24795
|
+
this.invalidBounds = { ...this.invalidBounds, start: false };
|
|
24796
|
+
this.applyDateRange({ ...this.dateRange, start: date });
|
|
24797
|
+
this.expandedBound = 'end';
|
|
24798
|
+
}
|
|
24799
|
+
setEndDate(date) {
|
|
24800
|
+
this.invalidBounds = { ...this.invalidBounds, end: false };
|
|
24801
|
+
this.applyDateRange({ ...this.dateRange, end: date });
|
|
24802
|
+
this.expandedBound = null;
|
|
24803
|
+
}
|
|
24804
|
+
clearDates(event) {
|
|
24805
|
+
this.invalidBounds = { start: false, end: false };
|
|
24806
|
+
this.expandedBound = 'start';
|
|
24807
|
+
this.applyDateRange({});
|
|
24808
|
+
propagateToDocumentOnly(event);
|
|
24809
|
+
}
|
|
24810
|
+
applyDateRange(dateRange) {
|
|
24811
|
+
this.dateRange = {
|
|
24812
|
+
...(dateRange.start && { start: dateRange.start }),
|
|
24813
|
+
...(dateRange.end && { end: dateRange.end }),
|
|
24814
|
+
};
|
|
24815
|
+
this.dateRangeChange.emit(this.dateRange);
|
|
24611
24816
|
}
|
|
24612
24817
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24613
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
24818
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: DateRangeDropdownComponent, isStandalone: true, selector: "gn-ui-date-range-dropdown", inputs: { title: "title", dateRange: "dateRange" }, outputs: { dateRangeChange: "dateRangeChange" }, providers: [
|
|
24614
24819
|
provideIcons({
|
|
24615
|
-
|
|
24820
|
+
iconoirCalendar,
|
|
24821
|
+
matClose,
|
|
24616
24822
|
matExpandLess,
|
|
24823
|
+
matExpandMore,
|
|
24617
24824
|
}),
|
|
24618
|
-
|
|
24825
|
+
provideNgIconsConfig({
|
|
24826
|
+
size: '1.5rem',
|
|
24827
|
+
}),
|
|
24828
|
+
provideLocalizedDateAdapter(),
|
|
24829
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], 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)=\"openOverlay()\"\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 (selectedDatesCount) {\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 {{ selectedDatesCount }}\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 (selectedDatesCount && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearDates($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n data-test=\"dropdown-toggle\"\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 (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"w-[296px] flex flex-col gap-2 bg-white border border-gray-400 rounded px-4 py-3 shadow-lg text-main text-[16px] leading-[24px]\"\n data-test=\"date-range-panel\"\n >\n <div class=\"flex flex-col justify-center border-b border-gray-300 pb-1\">\n <ng-container\n [ngTemplateOutlet]=\"boundRow\"\n [ngTemplateOutletContext]=\"{\n bound: 'start',\n label: 'daterange.filter.from',\n date: startDate,\n }\"\n ></ng-container>\n @if (expandedBound === 'start') {\n <div class=\"calendar\" animate.enter=\"expand\" animate.leave=\"collapse\">\n <mat-calendar\n data-test=\"start-date-calendar\"\n [selected]=\"startDate\"\n [startAt]=\"startDate ?? endDate\"\n [maxDate]=\"endDate\"\n (selectedChange)=\"setStartDate($event)\"\n ></mat-calendar>\n </div>\n }\n </div>\n <div class=\"flex flex-col justify-center\">\n <ng-container\n [ngTemplateOutlet]=\"boundRow\"\n [ngTemplateOutletContext]=\"{\n bound: 'end',\n label: 'daterange.filter.to',\n date: endDate,\n }\"\n ></ng-container>\n @if (expandedBound === 'end') {\n <div class=\"calendar\" animate.enter=\"expand\" animate.leave=\"collapse\">\n <mat-calendar\n data-test=\"end-date-calendar\"\n [selected]=\"endDate\"\n [startAt]=\"endDate ?? startDate\"\n [minDate]=\"startDate\"\n (selectedChange)=\"setEndDate($event)\"\n ></mat-calendar>\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #boundRow let-bound=\"bound\" let-label=\"label\" let-date=\"date\">\n <div class=\"flex items-center gap-1 w-full\">\n <span class=\"w-[80px] shrink-0\" [translate]=\"label\"></span>\n <div\n class=\"flex-1 min-w-0 flex items-center gap-1 border rounded-lg px-2 py-1 transition-colors\"\n [class]=\"\n invalidBounds[bound]\n ? 'border-red-400 text-red-800 focus-within:border-red-800 hover:border-red-800'\n : 'border-gray-400 focus-within:border-main hover:border-main'\n \"\n >\n <ng-icon\n name=\"iconoirCalendar\"\n class=\"shrink-0\"\n aria-hidden=\"true\"\n ></ng-icon>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n [gnUiAutofocus]=\"bound === expandedBound\"\n class=\"min-w-0 grow bg-transparent focus:outline-none\"\n [value]=\"date ? formatDate(date) : ''\"\n [placeholder]=\"'daterange.filter.datePlaceholder' | translate\"\n [attr.aria-label]=\"label | translate\"\n [attr.aria-invalid]=\"invalidBounds[bound] || null\"\n [attr.data-test]=\"bound + '-date-input'\"\n (change)=\"onDateInput(bound, $event)\"\n (blur)=\"normalizeDateInput(bound, $event)\"\n (click)=\"expandedBound !== bound && toggleBound(bound)\"\n />\n </div>\n <div class=\"shrink-0 flex items-center justify-end\">\n <gn-ui-button\n type=\"light\"\n [style.--gn-ui-button-padding]=\"0\"\n [style.--gn-ui-button-width]=\"'24px'\"\n [style.--gn-ui-button-height]=\"'24px'\"\n [attr.aria-expanded]=\"expandedBound === bound\"\n [attr.data-test]=\"bound + '-date-toggle'\"\n (buttonClick)=\"toggleBound(bound)\"\n >\n <ng-icon\n [name]=\"expandedBound === bound ? 'matExpandLess' : 'matExpandMore'\"\n ></ng-icon>\n </gn-ui-button>\n </div>\n </div>\n</ng-template>\n", styles: ["mat-calendar{width:100%}.calendar{display:grid;grid-template-rows:1fr}.calendar>mat-calendar{min-height:0;overflow:hidden}.calendar.expand{animation:open .2s ease-out}.calendar.collapse{animation:open .2s ease-in reverse}@keyframes open{0%{grid-template-rows:0fr;opacity:0}to{grid-template-rows:1fr;opacity:1}}@media (prefers-reduced-motion: reduce){.calendar.expand,.calendar.collapse{animation-duration:1ms}}\n"], dependencies: [{ kind: "directive", type: AutofocusDirective, selector: "[gnUiAutofocus]", inputs: ["gnUiAutofocus"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i1$6.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24619
24830
|
}
|
|
24620
24831
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, decorators: [{
|
|
24621
24832
|
type: Component,
|
|
24622
24833
|
args: [{ selector: 'gn-ui-date-range-dropdown', standalone: true, imports: [
|
|
24623
|
-
|
|
24624
|
-
MatNativeDateModule,
|
|
24625
|
-
MatDatepickerModule,
|
|
24834
|
+
AutofocusDirective,
|
|
24626
24835
|
ButtonComponent,
|
|
24836
|
+
MatDatepickerModule,
|
|
24837
|
+
NgIcon,
|
|
24838
|
+
NgTemplateOutlet,
|
|
24839
|
+
OverlayModule,
|
|
24840
|
+
TranslateDirective,
|
|
24841
|
+
TranslatePipe,
|
|
24627
24842
|
], providers: [
|
|
24628
24843
|
provideIcons({
|
|
24629
|
-
|
|
24844
|
+
iconoirCalendar,
|
|
24845
|
+
matClose,
|
|
24630
24846
|
matExpandLess,
|
|
24847
|
+
matExpandMore,
|
|
24631
24848
|
}),
|
|
24632
|
-
|
|
24633
|
-
|
|
24849
|
+
provideNgIconsConfig({
|
|
24850
|
+
size: '1.5rem',
|
|
24851
|
+
}),
|
|
24852
|
+
provideLocalizedDateAdapter(),
|
|
24853
|
+
], 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)=\"openOverlay()\"\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 (selectedDatesCount) {\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 {{ selectedDatesCount }}\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 (selectedDatesCount && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearDates($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n data-test=\"dropdown-toggle\"\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 (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"w-[296px] flex flex-col gap-2 bg-white border border-gray-400 rounded px-4 py-3 shadow-lg text-main text-[16px] leading-[24px]\"\n data-test=\"date-range-panel\"\n >\n <div class=\"flex flex-col justify-center border-b border-gray-300 pb-1\">\n <ng-container\n [ngTemplateOutlet]=\"boundRow\"\n [ngTemplateOutletContext]=\"{\n bound: 'start',\n label: 'daterange.filter.from',\n date: startDate,\n }\"\n ></ng-container>\n @if (expandedBound === 'start') {\n <div class=\"calendar\" animate.enter=\"expand\" animate.leave=\"collapse\">\n <mat-calendar\n data-test=\"start-date-calendar\"\n [selected]=\"startDate\"\n [startAt]=\"startDate ?? endDate\"\n [maxDate]=\"endDate\"\n (selectedChange)=\"setStartDate($event)\"\n ></mat-calendar>\n </div>\n }\n </div>\n <div class=\"flex flex-col justify-center\">\n <ng-container\n [ngTemplateOutlet]=\"boundRow\"\n [ngTemplateOutletContext]=\"{\n bound: 'end',\n label: 'daterange.filter.to',\n date: endDate,\n }\"\n ></ng-container>\n @if (expandedBound === 'end') {\n <div class=\"calendar\" animate.enter=\"expand\" animate.leave=\"collapse\">\n <mat-calendar\n data-test=\"end-date-calendar\"\n [selected]=\"endDate\"\n [startAt]=\"endDate ?? startDate\"\n [minDate]=\"startDate\"\n (selectedChange)=\"setEndDate($event)\"\n ></mat-calendar>\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #boundRow let-bound=\"bound\" let-label=\"label\" let-date=\"date\">\n <div class=\"flex items-center gap-1 w-full\">\n <span class=\"w-[80px] shrink-0\" [translate]=\"label\"></span>\n <div\n class=\"flex-1 min-w-0 flex items-center gap-1 border rounded-lg px-2 py-1 transition-colors\"\n [class]=\"\n invalidBounds[bound]\n ? 'border-red-400 text-red-800 focus-within:border-red-800 hover:border-red-800'\n : 'border-gray-400 focus-within:border-main hover:border-main'\n \"\n >\n <ng-icon\n name=\"iconoirCalendar\"\n class=\"shrink-0\"\n aria-hidden=\"true\"\n ></ng-icon>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n [gnUiAutofocus]=\"bound === expandedBound\"\n class=\"min-w-0 grow bg-transparent focus:outline-none\"\n [value]=\"date ? formatDate(date) : ''\"\n [placeholder]=\"'daterange.filter.datePlaceholder' | translate\"\n [attr.aria-label]=\"label | translate\"\n [attr.aria-invalid]=\"invalidBounds[bound] || null\"\n [attr.data-test]=\"bound + '-date-input'\"\n (change)=\"onDateInput(bound, $event)\"\n (blur)=\"normalizeDateInput(bound, $event)\"\n (click)=\"expandedBound !== bound && toggleBound(bound)\"\n />\n </div>\n <div class=\"shrink-0 flex items-center justify-end\">\n <gn-ui-button\n type=\"light\"\n [style.--gn-ui-button-padding]=\"0\"\n [style.--gn-ui-button-width]=\"'24px'\"\n [style.--gn-ui-button-height]=\"'24px'\"\n [attr.aria-expanded]=\"expandedBound === bound\"\n [attr.data-test]=\"bound + '-date-toggle'\"\n (buttonClick)=\"toggleBound(bound)\"\n >\n <ng-icon\n [name]=\"expandedBound === bound ? 'matExpandLess' : 'matExpandMore'\"\n ></ng-icon>\n </gn-ui-button>\n </div>\n </div>\n</ng-template>\n", styles: ["mat-calendar{width:100%}.calendar{display:grid;grid-template-rows:1fr}.calendar>mat-calendar{min-height:0;overflow:hidden}.calendar.expand{animation:open .2s ease-out}.calendar.collapse{animation:open .2s ease-in reverse}@keyframes open{0%{grid-template-rows:0fr;opacity:0}to{grid-template-rows:1fr;opacity:1}}@media (prefers-reduced-motion: reduce){.calendar.expand,.calendar.collapse{animation-duration:1ms}}\n"] }]
|
|
24854
|
+
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
24634
24855
|
type: Input
|
|
24635
|
-
}],
|
|
24856
|
+
}], dateRange: [{
|
|
24636
24857
|
type: Input
|
|
24637
|
-
}],
|
|
24638
|
-
type: Input
|
|
24639
|
-
}], startDateChange: [{
|
|
24640
|
-
type: Output
|
|
24641
|
-
}], endDateChange: [{
|
|
24858
|
+
}], dateRangeChange: [{
|
|
24642
24859
|
type: Output
|
|
24643
|
-
}],
|
|
24860
|
+
}], overlayOrigin: [{
|
|
24644
24861
|
type: ViewChild,
|
|
24645
|
-
args: ['
|
|
24862
|
+
args: ['overlayOrigin']
|
|
24646
24863
|
}] } });
|
|
24647
24864
|
|
|
24648
24865
|
class DateRangePickerComponent {
|
|
@@ -24656,20 +24873,17 @@ class DateRangePickerComponent {
|
|
|
24656
24873
|
provideNgIconsConfig({
|
|
24657
24874
|
size: '1.5rem',
|
|
24658
24875
|
}),
|
|
24659
|
-
|
|
24876
|
+
provideLocalizedDateAdapter(),
|
|
24877
|
+
], ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n <mat-date-range-input [rangePicker]=\"picker\" class=\"gn-ui-text-input\">\n <input\n matStartDate\n placeholder=\"Start date\"\n [value]=\"startDate\"\n (dateInput)=\"startDateChange.emit($event.value)\"\n />\n <input\n matEndDate\n placeholder=\"End date\"\n [value]=\"endDate\"\n (dateInput)=\"endDateChange.emit($event.value)\"\n />\n </mat-date-range-input>\n\n <gn-ui-button\n type=\"light\"\n class=\"absolute inset-y-[var(--side-padding)] right-[var(--side-padding)] z-10\"\n (buttonClick)=\"picker.open()\"\n extraClass=\"h-full\"\n data-cy=\"date-picker-button\"\n >\n <ng-icon name=\"iconoirCalendar\" class=\"text-primary\"></ng-icon>\n </gn-ui-button>\n</span>\n<mat-date-range-picker #picker></mat-date-range-picker>\n", styles: [":host{--gn-ui-button-rounded: 8px;--gn-ui-button-width: 32px;--gn-ui-button-padding: 0;--side-padding: calc(var(--gn-ui-text-input-padding, .6em) - 6px);--text-padding: calc(var(--side-padding) + 40px)}\n"], dependencies: [{ kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i1$6.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { kind: "directive", type: i1$6.MatStartDate, selector: "input[matStartDate]", outputs: ["dateChange", "dateInput"] }, { kind: "directive", type: i1$6.MatEndDate, selector: "input[matEndDate]", outputs: ["dateChange", "dateInput"] }, { kind: "component", type: i1$6.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24660
24878
|
}
|
|
24661
24879
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
24662
24880
|
type: Component,
|
|
24663
|
-
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24664
|
-
MatNativeDateModule,
|
|
24665
|
-
MatDatepickerModule,
|
|
24666
|
-
ButtonComponent,
|
|
24667
|
-
NgIconComponent,
|
|
24668
|
-
], providers: [
|
|
24881
|
+
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24669
24882
|
provideIcons({ iconoirCalendar }),
|
|
24670
24883
|
provideNgIconsConfig({
|
|
24671
24884
|
size: '1.5rem',
|
|
24672
24885
|
}),
|
|
24886
|
+
provideLocalizedDateAdapter(),
|
|
24673
24887
|
], template: "<span class=\"w-full inline-block relative\">\n <mat-date-range-input [rangePicker]=\"picker\" class=\"gn-ui-text-input\">\n <input\n matStartDate\n placeholder=\"Start date\"\n [value]=\"startDate\"\n (dateInput)=\"startDateChange.emit($event.value)\"\n />\n <input\n matEndDate\n placeholder=\"End date\"\n [value]=\"endDate\"\n (dateInput)=\"endDateChange.emit($event.value)\"\n />\n </mat-date-range-input>\n\n <gn-ui-button\n type=\"light\"\n class=\"absolute inset-y-[var(--side-padding)] right-[var(--side-padding)] z-10\"\n (buttonClick)=\"picker.open()\"\n extraClass=\"h-full\"\n data-cy=\"date-picker-button\"\n >\n <ng-icon name=\"iconoirCalendar\" class=\"text-primary\"></ng-icon>\n </gn-ui-button>\n</span>\n<mat-date-range-picker #picker></mat-date-range-picker>\n", styles: [":host{--gn-ui-button-rounded: 8px;--gn-ui-button-width: 32px;--gn-ui-button-padding: 0;--side-padding: calc(var(--gn-ui-text-input-padding, .6em) - 6px);--text-padding: calc(var(--side-padding) + 40px)}\n"] }]
|
|
24674
24888
|
}], propDecorators: { startDate: [{
|
|
24675
24889
|
type: Input
|
|
@@ -24687,28 +24901,68 @@ class DragAndDropFileInputComponent {
|
|
|
24687
24901
|
constructor() {
|
|
24688
24902
|
this.placeholder = placeholder;
|
|
24689
24903
|
this.accept = '*';
|
|
24904
|
+
this.maxFileSizeMb = null;
|
|
24905
|
+
this.icon = null;
|
|
24906
|
+
this.dropzoneBackgroundColor = null;
|
|
24907
|
+
this.textClass = '';
|
|
24908
|
+
this.extraClass = '';
|
|
24909
|
+
this.showFileName = true;
|
|
24690
24910
|
this.fileChange = new EventEmitter();
|
|
24911
|
+
this.errorChange = new EventEmitter();
|
|
24691
24912
|
this.selectedFile = null;
|
|
24692
24913
|
}
|
|
24693
24914
|
get fileName() {
|
|
24694
24915
|
return this.selectedFile && this.selectedFile.name;
|
|
24695
24916
|
}
|
|
24917
|
+
get maxFileSizeBytes() {
|
|
24918
|
+
return typeof this.maxFileSizeMb === 'number'
|
|
24919
|
+
? megabytesToBytes(this.maxFileSizeMb)
|
|
24920
|
+
: null;
|
|
24921
|
+
}
|
|
24696
24922
|
selectFile(event) {
|
|
24923
|
+
if (event.rejectedFiles?.length) {
|
|
24924
|
+
const reason = event.rejectedFiles[0].reason;
|
|
24925
|
+
this.errorChange.emit(reason === 'size' ? 'file-too-large' : 'invalid-extension');
|
|
24926
|
+
return;
|
|
24927
|
+
}
|
|
24697
24928
|
this.selectedFile = event.addedFiles[0];
|
|
24698
24929
|
this.fileChange.emit(this.selectedFile);
|
|
24699
24930
|
}
|
|
24931
|
+
openFileSelector() {
|
|
24932
|
+
this.dropzone.showFileSelector();
|
|
24933
|
+
}
|
|
24934
|
+
clear() {
|
|
24935
|
+
this.selectedFile = null;
|
|
24936
|
+
}
|
|
24700
24937
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24701
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: DragAndDropFileInputComponent, isStandalone: true, selector: "gn-ui-drag-and-drop-file-input", inputs: { placeholder: "placeholder", accept: "accept" }, outputs: { fileChange: "fileChange" }, ngImport: i0, template: "<div
|
|
24938
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: DragAndDropFileInputComponent, isStandalone: true, selector: "gn-ui-drag-and-drop-file-input", inputs: { placeholder: "placeholder", accept: "accept", maxFileSizeMb: "maxFileSizeMb", icon: "icon", dropzoneBackgroundColor: "dropzoneBackgroundColor", textClass: "textClass", extraClass: "extraClass", showFileName: "showFileName" }, outputs: { fileChange: "fileChange", errorChange: "errorChange" }, viewQueries: [{ propertyName: "dropzone", first: true, predicate: NgxDropzoneComponent, descendants: true }], ngImport: i0, template: "<div\n class=\"flex h-full items-center\"\n [class]=\"extraClass\"\n (click)=\"openFileSelector()\"\n>\n <ngx-dropzone\n class=\"flex-1 overflow-hidden\"\n [multiple]=\"false\"\n [disableClick]=\"true\"\n [accept]=\"accept\"\n [maxFileSize]=\"maxFileSizeBytes\"\n [style.background-color]=\"dropzoneBackgroundColor\"\n (change)=\"selectFile($event)\"\n >\n @if (!fileName || !showFileName) {\n <div [class]=\"textClass\">\n {{ placeholder }}\n </div>\n }\n\n @if (fileName && showFileName) {\n <div [class]=\"textClass\">\n {{ fileName }}\n </div>\n }\n </ngx-dropzone>\n\n @if (icon) {\n <ng-icon [name]=\"icon\" class=\"shrink-0 text-gray-950\"></ng-icon>\n }\n</div>\n", styles: ["ngx-dropzone{height:auto;border:none;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: NgxDropzoneModule }, { kind: "component", type: i1$8.NgxDropzoneComponent, selector: "ngx-dropzone, [ngx-dropzone]", inputs: ["accept", "disabled", "multiple", "maxFileSize", "expandable", "disableClick", "processDirectoryDrop", "id", "aria-label", "aria-labelledby", "aria-describedby"], outputs: ["change"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }] }); }
|
|
24702
24939
|
}
|
|
24703
24940
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, decorators: [{
|
|
24704
24941
|
type: Component,
|
|
24705
|
-
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule], template: "<div
|
|
24942
|
+
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule, NgIcon], template: "<div\n class=\"flex h-full items-center\"\n [class]=\"extraClass\"\n (click)=\"openFileSelector()\"\n>\n <ngx-dropzone\n class=\"flex-1 overflow-hidden\"\n [multiple]=\"false\"\n [disableClick]=\"true\"\n [accept]=\"accept\"\n [maxFileSize]=\"maxFileSizeBytes\"\n [style.background-color]=\"dropzoneBackgroundColor\"\n (change)=\"selectFile($event)\"\n >\n @if (!fileName || !showFileName) {\n <div [class]=\"textClass\">\n {{ placeholder }}\n </div>\n }\n\n @if (fileName && showFileName) {\n <div [class]=\"textClass\">\n {{ fileName }}\n </div>\n }\n </ngx-dropzone>\n\n @if (icon) {\n <ng-icon [name]=\"icon\" class=\"shrink-0 text-gray-950\"></ng-icon>\n }\n</div>\n", styles: ["ngx-dropzone{height:auto;border:none;overflow:hidden}\n"] }]
|
|
24706
24943
|
}], propDecorators: { placeholder: [{
|
|
24707
24944
|
type: Input
|
|
24708
24945
|
}], accept: [{
|
|
24709
24946
|
type: Input
|
|
24947
|
+
}], maxFileSizeMb: [{
|
|
24948
|
+
type: Input
|
|
24949
|
+
}], icon: [{
|
|
24950
|
+
type: Input
|
|
24951
|
+
}], dropzoneBackgroundColor: [{
|
|
24952
|
+
type: Input
|
|
24953
|
+
}], textClass: [{
|
|
24954
|
+
type: Input
|
|
24955
|
+
}], extraClass: [{
|
|
24956
|
+
type: Input
|
|
24957
|
+
}], showFileName: [{
|
|
24958
|
+
type: Input
|
|
24710
24959
|
}], fileChange: [{
|
|
24711
24960
|
type: Output
|
|
24961
|
+
}], errorChange: [{
|
|
24962
|
+
type: Output
|
|
24963
|
+
}], dropzone: [{
|
|
24964
|
+
type: ViewChild,
|
|
24965
|
+
args: [NgxDropzoneComponent]
|
|
24712
24966
|
}] } });
|
|
24713
24967
|
|
|
24714
24968
|
class DropdownMultiselectComponent {
|
|
@@ -24757,7 +25011,7 @@ class DropdownMultiselectComponent {
|
|
|
24757
25011
|
}
|
|
24758
25012
|
setFocus() {
|
|
24759
25013
|
setTimeout(() => {
|
|
24760
|
-
this.searchFieldInput
|
|
25014
|
+
this.searchFieldInput?.nativeElement.focus();
|
|
24761
25015
|
}, 0);
|
|
24762
25016
|
}
|
|
24763
25017
|
openOverlay() {
|
|
@@ -24863,7 +25117,10 @@ class DropdownMultiselectComponent {
|
|
|
24863
25117
|
matExpandMore,
|
|
24864
25118
|
matExpandLess,
|
|
24865
25119
|
}),
|
|
24866
|
-
|
|
25120
|
+
provideNgIconsConfig({
|
|
25121
|
+
size: '1.5rem',
|
|
25122
|
+
}),
|
|
25123
|
+
], 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 }); }
|
|
24867
25124
|
}
|
|
24868
25125
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
|
|
24869
25126
|
type: Component,
|
|
@@ -24873,7 +25130,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24873
25130
|
matExpandMore,
|
|
24874
25131
|
matExpandLess,
|
|
24875
25132
|
}),
|
|
24876
|
-
|
|
25133
|
+
provideNgIconsConfig({
|
|
25134
|
+
size: '1.5rem',
|
|
25135
|
+
}),
|
|
25136
|
+
], 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" }]
|
|
24877
25137
|
}], propDecorators: { title: [{
|
|
24878
25138
|
type: Input
|
|
24879
25139
|
}], choices: [{
|
|
@@ -25045,7 +25305,7 @@ class DropdownSelectorComponent {
|
|
|
25045
25305
|
provideNgIconsConfig({
|
|
25046
25306
|
size: '1.5em',
|
|
25047
25307
|
}),
|
|
25048
|
-
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "choiceInputs", predicate: ["choiceInputs"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"flex flex-col sm:flex-row sm:items-center relative w-full\">\n @if (showTitle) {\n <span\n class=\"tracking-wide text-sm mb-2 sm:mb-0 sm:mr-2 whitespace-nowrap\"\n [attr.for]=\"id\"\n >\n {{ title }}\n </span>\n }\n <gn-ui-button\n type=\"outline\"\n class=\"grow min-w-0\"\n [style.--gn-ui-button-padding]=\"'8px 8px 8px 16px'\"\n extraClass=\"bg-background flex flex-row w-full {{ extraBtnClass }}\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n (keydown)=\"handleTriggerKeydown($event)\"\n [disabled]=\"disabled\"\n >\n <div class=\"grow truncate py-1 mr-2 text-left\">\n {{ getChoiceLabel() | translate }}\n </div>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n </gn-ui-button>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\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]=\"overlayWidth\"\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 >\n @for (choice of choices; track choice) {\n <button\n #choiceInputs\n type=\"button\"\n [title]=\"choice.label | translate\"\n class=\"flex px-5 py-1 w-full text-start cursor-pointer transition-colors\"\n [ngClass]=\"\n isSelected(choice)\n ? 'text-white bg-primary hover:text-white hover:bg-primary-darker focus:text-white focus:bg-primary-darker'\n : 'text-gray-900 hover:text-primary-darkest hover:bg-gray-50 focus:text-primary-darkest focus:bg-gray-50'\n \"\n (click)=\"onSelectValue(choice)\"\n (keydown)=\"selectIfEnter($event, choice)\"\n [attr.data-cy-value]=\"choice.value.toString()\"\n [attr.data-cy-active]=\"isSelected(choice) ? 'true' : undefined\"\n >\n <span class=\"text-[14px]\">\n {{ choice.label | translate }}\n </span>\n </button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$
|
|
25308
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "choiceInputs", predicate: ["choiceInputs"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"flex flex-col sm:flex-row sm:items-center relative w-full\">\n @if (showTitle) {\n <span\n class=\"tracking-wide text-sm mb-2 sm:mb-0 sm:mr-2 whitespace-nowrap\"\n [attr.for]=\"id\"\n >\n {{ title }}\n </span>\n }\n <gn-ui-button\n type=\"outline\"\n class=\"grow min-w-0\"\n [style.--gn-ui-button-padding]=\"'8px 8px 8px 16px'\"\n extraClass=\"bg-background flex flex-row w-full {{ extraBtnClass }}\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n (keydown)=\"handleTriggerKeydown($event)\"\n [disabled]=\"disabled\"\n >\n <div class=\"grow truncate py-1 mr-2 text-left\">\n {{ getChoiceLabel() | translate }}\n </div>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n </gn-ui-button>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\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]=\"overlayWidth\"\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 >\n @for (choice of choices; track choice) {\n <button\n #choiceInputs\n type=\"button\"\n [title]=\"choice.label | translate\"\n class=\"flex px-5 py-1 w-full text-start cursor-pointer transition-colors\"\n [ngClass]=\"\n isSelected(choice)\n ? 'text-white bg-primary hover:text-white hover:bg-primary-darker focus:text-white focus:bg-primary-darker'\n : 'text-gray-900 hover:text-primary-darkest hover:bg-gray-50 focus:text-primary-darkest focus:bg-gray-50'\n \"\n (click)=\"onSelectValue(choice)\"\n (keydown)=\"selectIfEnter($event, choice)\"\n [attr.data-cy-value]=\"choice.value.toString()\"\n [attr.data-cy-active]=\"isSelected(choice) ? 'true' : undefined\"\n >\n <span class=\"text-[14px]\">\n {{ choice.label | translate }}\n </span>\n </button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { 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: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
25049
25309
|
}
|
|
25050
25310
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownSelectorComponent, decorators: [{
|
|
25051
25311
|
type: Component,
|
|
@@ -25785,6 +26045,180 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
25785
26045
|
type: Output
|
|
25786
26046
|
}] } });
|
|
25787
26047
|
|
|
26048
|
+
marker('search.filters.spatialExtent.import');
|
|
26049
|
+
marker('search.filters.spatialExtent.helpText');
|
|
26050
|
+
marker('search.filters.spatialExtent.error.title');
|
|
26051
|
+
marker('search.filters.spatialExtent.error.outOfBounds');
|
|
26052
|
+
const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
|
|
26053
|
+
const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
|
|
26054
|
+
const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
|
|
26055
|
+
const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
|
|
26056
|
+
class SpatialExtentDropdownComponent {
|
|
26057
|
+
constructor() {
|
|
26058
|
+
this.cd = inject(ChangeDetectorRef);
|
|
26059
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
26060
|
+
this.maxFileSizeMb = null;
|
|
26061
|
+
this.bboxChange = new EventEmitter();
|
|
26062
|
+
this.errorChange = new EventEmitter();
|
|
26063
|
+
this.bbox = null;
|
|
26064
|
+
this.fileName = '';
|
|
26065
|
+
this.overlayPositions = [
|
|
26066
|
+
{
|
|
26067
|
+
originX: 'start',
|
|
26068
|
+
originY: 'bottom',
|
|
26069
|
+
overlayX: 'start',
|
|
26070
|
+
overlayY: 'top',
|
|
26071
|
+
offsetY: 8,
|
|
26072
|
+
},
|
|
26073
|
+
{
|
|
26074
|
+
originX: 'start',
|
|
26075
|
+
originY: 'top',
|
|
26076
|
+
overlayX: 'start',
|
|
26077
|
+
overlayY: 'bottom',
|
|
26078
|
+
offsetY: -8,
|
|
26079
|
+
},
|
|
26080
|
+
];
|
|
26081
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
26082
|
+
this.overlayOpen = false;
|
|
26083
|
+
this.overlayMinWidth = 'none';
|
|
26084
|
+
this.errorKey = null;
|
|
26085
|
+
}
|
|
26086
|
+
set initialBbox(value) {
|
|
26087
|
+
if (!this.bbox && value) {
|
|
26088
|
+
this.bbox = value;
|
|
26089
|
+
}
|
|
26090
|
+
}
|
|
26091
|
+
get hasSelection() {
|
|
26092
|
+
return !!this.bbox;
|
|
26093
|
+
}
|
|
26094
|
+
get selectionLabelKey() {
|
|
26095
|
+
return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
|
|
26096
|
+
}
|
|
26097
|
+
get selectionDeleteLabelKey() {
|
|
26098
|
+
return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
|
|
26099
|
+
}
|
|
26100
|
+
get selectionLabelParams() {
|
|
26101
|
+
return { fileName: this.fileName };
|
|
26102
|
+
}
|
|
26103
|
+
openOverlay() {
|
|
26104
|
+
this.overlayMinWidth =
|
|
26105
|
+
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
|
|
26106
|
+
.width + 'px';
|
|
26107
|
+
this.overlayOpen = true;
|
|
26108
|
+
}
|
|
26109
|
+
closeOverlay() {
|
|
26110
|
+
this.overlayOpen = false;
|
|
26111
|
+
}
|
|
26112
|
+
toggleOverlay() {
|
|
26113
|
+
if (this.overlayOpen) {
|
|
26114
|
+
this.closeOverlay();
|
|
26115
|
+
}
|
|
26116
|
+
else {
|
|
26117
|
+
this.openOverlay();
|
|
26118
|
+
}
|
|
26119
|
+
}
|
|
26120
|
+
async handleFileSelected(file) {
|
|
26121
|
+
this.errorKey = null;
|
|
26122
|
+
let content;
|
|
26123
|
+
try {
|
|
26124
|
+
content = await readFileAsText(file);
|
|
26125
|
+
const parsed = JSON.parse(content);
|
|
26126
|
+
const geometry = getGeometryFromGeoJSON(parsed);
|
|
26127
|
+
if (!geometry) {
|
|
26128
|
+
this.setError(marker('search.filters.spatialExtent.error.noGeometry'));
|
|
26129
|
+
return;
|
|
26130
|
+
}
|
|
26131
|
+
const bbox = getGeometryBoundingBox(geometry);
|
|
26132
|
+
if (!isBoundingBoxWithinWorldExtent(bbox)) {
|
|
26133
|
+
this.setError(marker('search.filters.spatialExtent.error.outOfBounds'));
|
|
26134
|
+
return;
|
|
26135
|
+
}
|
|
26136
|
+
this.bbox = bbox;
|
|
26137
|
+
this.fileName = file.name;
|
|
26138
|
+
this.bboxChange.emit(bbox);
|
|
26139
|
+
this.cd.markForCheck();
|
|
26140
|
+
}
|
|
26141
|
+
catch {
|
|
26142
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26143
|
+
return;
|
|
26144
|
+
}
|
|
26145
|
+
}
|
|
26146
|
+
handleFileError(error) {
|
|
26147
|
+
if (error === 'file-too-large') {
|
|
26148
|
+
this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
|
|
26149
|
+
maxSize: this.maxFileSizeMb,
|
|
26150
|
+
});
|
|
26151
|
+
}
|
|
26152
|
+
else {
|
|
26153
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26154
|
+
}
|
|
26155
|
+
}
|
|
26156
|
+
setError(errorKey, params) {
|
|
26157
|
+
this.errorKey = errorKey;
|
|
26158
|
+
this.errorChange.emit({ key: errorKey, params });
|
|
26159
|
+
this.cd.markForCheck();
|
|
26160
|
+
}
|
|
26161
|
+
removeSelection(event) {
|
|
26162
|
+
this.bbox = null;
|
|
26163
|
+
this.fileName = '';
|
|
26164
|
+
this.errorKey = null;
|
|
26165
|
+
this.fileInput?.clear();
|
|
26166
|
+
this.bboxChange.emit(null);
|
|
26167
|
+
propagateToDocumentOnly(event);
|
|
26168
|
+
}
|
|
26169
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26170
|
+
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: [
|
|
26171
|
+
provideIcons({
|
|
26172
|
+
iconoirCheckCircle,
|
|
26173
|
+
iconoirSquareDashed,
|
|
26174
|
+
iconoirTrash,
|
|
26175
|
+
iconoirUpload,
|
|
26176
|
+
matClose,
|
|
26177
|
+
matExpandLess,
|
|
26178
|
+
matExpandMore,
|
|
26179
|
+
}),
|
|
26180
|
+
], 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 }); }
|
|
26181
|
+
}
|
|
26182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
|
|
26183
|
+
type: Component,
|
|
26184
|
+
args: [{ selector: 'gn-ui-spatial-extent-dropdown', standalone: true, imports: [
|
|
26185
|
+
ButtonComponent,
|
|
26186
|
+
NgIcon,
|
|
26187
|
+
OverlayModule,
|
|
26188
|
+
TranslatePipe,
|
|
26189
|
+
DragAndDropFileInputComponent,
|
|
26190
|
+
], providers: [
|
|
26191
|
+
provideIcons({
|
|
26192
|
+
iconoirCheckCircle,
|
|
26193
|
+
iconoirSquareDashed,
|
|
26194
|
+
iconoirTrash,
|
|
26195
|
+
iconoirUpload,
|
|
26196
|
+
matClose,
|
|
26197
|
+
matExpandLess,
|
|
26198
|
+
matExpandMore,
|
|
26199
|
+
}),
|
|
26200
|
+
], 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" }]
|
|
26201
|
+
}], propDecorators: { title: [{
|
|
26202
|
+
type: Input
|
|
26203
|
+
}], maxFileSizeMb: [{
|
|
26204
|
+
type: Input
|
|
26205
|
+
}], initialBbox: [{
|
|
26206
|
+
type: Input
|
|
26207
|
+
}], bboxChange: [{
|
|
26208
|
+
type: Output
|
|
26209
|
+
}], errorChange: [{
|
|
26210
|
+
type: Output
|
|
26211
|
+
}], overlayOrigin: [{
|
|
26212
|
+
type: ViewChild,
|
|
26213
|
+
args: ['overlayOrigin']
|
|
26214
|
+
}], overlay: [{
|
|
26215
|
+
type: ViewChild,
|
|
26216
|
+
args: [CdkConnectedOverlay]
|
|
26217
|
+
}], fileInput: [{
|
|
26218
|
+
type: ViewChild,
|
|
26219
|
+
args: [DragAndDropFileInputComponent]
|
|
26220
|
+
}] } });
|
|
26221
|
+
|
|
25788
26222
|
class CellPopinComponent {
|
|
25789
26223
|
constructor() {
|
|
25790
26224
|
this.scrollDispatcher = inject(ScrollDispatcher);
|
|
@@ -25861,7 +26295,7 @@ class CellPopinComponent {
|
|
|
25861
26295
|
this.isOpen = false;
|
|
25862
26296
|
}
|
|
25863
26297
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25864
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: CellPopinComponent, isStandalone: true, selector: "gn-ui-cell-popin", inputs: { extraClass: "extraClass", cdkScrollContainer: "cdkScrollContainer", scrollContainer: "scrollContainer", activePopin: "activePopin" }, providers: [provideIcons({ iconoirReduce })], viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchorRef"], descendants: true }], ngImport: i0, template: "<div\n class=\"h-full flex items-center justify-center\"\n cdkOverlayOrigin\n #anchorRef\n #trigger=\"cdkOverlayOrigin\"\n [class]=\"extraClass\"\n data-cy=\"cell-popin\"\n>\n <ng-content select=\"[cellContent]\"></ng-content>\n @if (activePopin) {\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayPush]=\"false\"\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayWidth]=\"'auto'\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayGrowAfterOpen]=\"true\"\n (detach)=\"closeOverlay()\"\n >\n @if (activePopin && isVisible) {\n <div\n class=\"bg-white shadow-lg border border-gray-300 relative\"\n data-cy=\"cell-popin-content\"\n >\n <ng-content select=\"[popinContent]\"></ng-content>\n <gn-ui-button\n data-cy=\"cell-popin-close\"\n [style.--gn-ui-button-background]=\"'bg-transparent'\"\n class=\"absolute top-2 right-2\"\n type=\"light\"\n (buttonClick)=\"closeOverlay()\"\n extraClass=\"w-10 h-8 px-1\"\n >\n <ng-icon name=\"iconoirReduce\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n }\n </ng-template>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$
|
|
26298
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: CellPopinComponent, isStandalone: true, selector: "gn-ui-cell-popin", inputs: { extraClass: "extraClass", cdkScrollContainer: "cdkScrollContainer", scrollContainer: "scrollContainer", activePopin: "activePopin" }, providers: [provideIcons({ iconoirReduce })], viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchorRef"], descendants: true }], ngImport: i0, template: "<div\n class=\"h-full flex items-center justify-center\"\n cdkOverlayOrigin\n #anchorRef\n #trigger=\"cdkOverlayOrigin\"\n [class]=\"extraClass\"\n data-cy=\"cell-popin\"\n>\n <ng-content select=\"[cellContent]\"></ng-content>\n @if (activePopin) {\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayPush]=\"false\"\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayWidth]=\"'auto'\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayGrowAfterOpen]=\"true\"\n (detach)=\"closeOverlay()\"\n >\n @if (activePopin && isVisible) {\n <div\n class=\"bg-white shadow-lg border border-gray-300 relative\"\n data-cy=\"cell-popin-content\"\n >\n <ng-content select=\"[popinContent]\"></ng-content>\n <gn-ui-button\n data-cy=\"cell-popin-close\"\n [style.--gn-ui-button-background]=\"'bg-transparent'\"\n class=\"absolute top-2 right-2\"\n type=\"light\"\n (buttonClick)=\"closeOverlay()\"\n extraClass=\"w-10 h-8 px-1\"\n >\n <ng-icon name=\"iconoirReduce\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n }\n </ng-template>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { 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: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }] }); }
|
|
25865
26299
|
}
|
|
25866
26300
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, decorators: [{
|
|
25867
26301
|
type: Component,
|
|
@@ -26289,11 +26723,11 @@ class BlockListComponent {
|
|
|
26289
26723
|
this.goToPage(this.currentPage + 1);
|
|
26290
26724
|
}
|
|
26291
26725
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26292
|
-
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 }); }
|
|
26726
|
+
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 }); }
|
|
26293
26727
|
}
|
|
26294
26728
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, decorators: [{
|
|
26295
26729
|
type: Component,
|
|
26296
|
-
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"] }]
|
|
26730
|
+
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"] }]
|
|
26297
26731
|
}], propDecorators: { containerClass: [{
|
|
26298
26732
|
type: Input
|
|
26299
26733
|
}], paginationContainerClass: [{
|
|
@@ -27483,6 +27917,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
27483
27917
|
}]
|
|
27484
27918
|
}] });
|
|
27485
27919
|
|
|
27920
|
+
const DEFAULT_GEOCODING_PROVIDER = [
|
|
27921
|
+
'geonames',
|
|
27922
|
+
{ maxRows: 5 },
|
|
27923
|
+
];
|
|
27924
|
+
const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
|
|
27925
|
+
providedIn: 'root',
|
|
27926
|
+
factory: () => DEFAULT_GEOCODING_PROVIDER,
|
|
27927
|
+
});
|
|
27928
|
+
class GeocodingService {
|
|
27929
|
+
constructor() {
|
|
27930
|
+
this.provider = inject(GEOCODING_PROVIDER);
|
|
27931
|
+
}
|
|
27932
|
+
query(text) {
|
|
27933
|
+
let queryObservable;
|
|
27934
|
+
switch (this.provider[0]) {
|
|
27935
|
+
case 'geoadmin':
|
|
27936
|
+
queryObservable = from(queryGeoadmin(text, this.provider[1]));
|
|
27937
|
+
break;
|
|
27938
|
+
case 'geonames':
|
|
27939
|
+
queryObservable = from(queryGeonames(text, this.provider[1]));
|
|
27940
|
+
break;
|
|
27941
|
+
case 'geoplateforme':
|
|
27942
|
+
queryObservable = from(queryGeoplateforme(text, this.provider[1]));
|
|
27943
|
+
break;
|
|
27944
|
+
default:
|
|
27945
|
+
return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
|
|
27946
|
+
}
|
|
27947
|
+
return queryObservable.pipe(catchError((error) => throwError(error)));
|
|
27948
|
+
}
|
|
27949
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
27950
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
|
|
27951
|
+
}
|
|
27952
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
|
|
27953
|
+
type: Injectable,
|
|
27954
|
+
args: [{
|
|
27955
|
+
providedIn: 'root',
|
|
27956
|
+
}]
|
|
27957
|
+
}] });
|
|
27958
|
+
|
|
27959
|
+
class LocationSearchComponent {
|
|
27960
|
+
constructor() {
|
|
27961
|
+
this.geocodingService = inject(GeocodingService);
|
|
27962
|
+
this.placeholder = '';
|
|
27963
|
+
this.resultSelected = new EventEmitter();
|
|
27964
|
+
this.displayWithFn = (item) => item.label;
|
|
27965
|
+
this.searchAction = (text) => this.geocodingService.query(text);
|
|
27966
|
+
}
|
|
27967
|
+
handleItemSelected(item) {
|
|
27968
|
+
this.resultSelected.emit(item);
|
|
27969
|
+
}
|
|
27970
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
27971
|
+
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 }); }
|
|
27972
|
+
}
|
|
27973
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
|
|
27974
|
+
type: Component,
|
|
27975
|
+
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" }]
|
|
27976
|
+
}], propDecorators: { placeholder: [{
|
|
27977
|
+
type: Input
|
|
27978
|
+
}], displayWithTemplate: [{
|
|
27979
|
+
type: Input
|
|
27980
|
+
}], resultSelected: [{
|
|
27981
|
+
type: Output
|
|
27982
|
+
}] } });
|
|
27983
|
+
|
|
27486
27984
|
// expects the replacement key ${uuid}
|
|
27487
27985
|
const RECORD_DATASET_URL_TOKEN = new InjectionToken('record-dataset-url-token');
|
|
27488
27986
|
const RECORD_SERVICE_URL_TOKEN = new InjectionToken('record-service-url-token');
|
|
@@ -27951,6 +28449,45 @@ class DateRangeSearchField extends SimpleSearchField {
|
|
|
27951
28449
|
return 'dateRange';
|
|
27952
28450
|
}
|
|
27953
28451
|
}
|
|
28452
|
+
// treats a resource's creation/revision dates as an interval (its min and max), so a record matches
|
|
28453
|
+
// when that interval intersects the filter range, not just when a single date falls inside it
|
|
28454
|
+
class ResourceCreationRevisionDateSearchField extends DateRangeSearchField {
|
|
28455
|
+
constructor(injector, order = 'desc') {
|
|
28456
|
+
super('resourceCreationRevisionDate', injector, order);
|
|
28457
|
+
const dateSourceFields = [
|
|
28458
|
+
'creationDateForResource',
|
|
28459
|
+
'revisionDateForResource',
|
|
28460
|
+
];
|
|
28461
|
+
const collectSortedDates = dateSourceFields
|
|
28462
|
+
.map((field) => `if (doc.containsKey('${field}')) {
|
|
28463
|
+
for (def date : doc['${field}']) { dates.add(date.millis); }
|
|
28464
|
+
}`)
|
|
28465
|
+
.join('\n');
|
|
28466
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMin', `def dates = [];
|
|
28467
|
+
${collectSortedDates}
|
|
28468
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[0]); }`, 'date');
|
|
28469
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMax', `def dates = [];
|
|
28470
|
+
${collectSortedDates}
|
|
28471
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[dates.length - 1]); }`, 'date');
|
|
28472
|
+
}
|
|
28473
|
+
}
|
|
28474
|
+
class BoundingBoxSearchField extends SimpleSearchField {
|
|
28475
|
+
getAvailableValues() {
|
|
28476
|
+
return of([]);
|
|
28477
|
+
}
|
|
28478
|
+
getFiltersForValues(values) {
|
|
28479
|
+
return of({
|
|
28480
|
+
[this.esFieldName]: values.map(Number),
|
|
28481
|
+
});
|
|
28482
|
+
}
|
|
28483
|
+
getValuesForFilter(filters) {
|
|
28484
|
+
const filter = filters[this.esFieldName];
|
|
28485
|
+
return of(isBoundingBox(filter) ? filter : []);
|
|
28486
|
+
}
|
|
28487
|
+
getType() {
|
|
28488
|
+
return 'spatialExtent';
|
|
28489
|
+
}
|
|
28490
|
+
}
|
|
27954
28491
|
marker('search.filters.availableServices.view');
|
|
27955
28492
|
marker('search.filters.availableServices.download');
|
|
27956
28493
|
class AvailableServicesField extends SimpleSearchField {
|
|
@@ -28095,6 +28632,8 @@ marker('search.filters.producerOrg');
|
|
|
28095
28632
|
marker('search.filters.publisherOrg');
|
|
28096
28633
|
marker('search.filters.user');
|
|
28097
28634
|
marker('search.filters.changeDate');
|
|
28635
|
+
marker('search.filters.resourceCreationRevisionDate');
|
|
28636
|
+
marker('search.filters.spatialExtent');
|
|
28098
28637
|
class FieldsService {
|
|
28099
28638
|
constructor() {
|
|
28100
28639
|
this.injector = inject(Injector);
|
|
@@ -28117,7 +28656,9 @@ class FieldsService {
|
|
|
28117
28656
|
publisherOrg: new MultilingualSearchField('distributorOrgForResourceObject', this.injector, 'asc', 'key'),
|
|
28118
28657
|
user: new UserSearchField(this.injector),
|
|
28119
28658
|
changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
|
|
28659
|
+
resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
|
|
28120
28660
|
availableServices: new AvailableServicesField(this.injector),
|
|
28661
|
+
spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
|
|
28121
28662
|
};
|
|
28122
28663
|
}
|
|
28123
28664
|
get supportedFields() {
|
|
@@ -29380,7 +29921,7 @@ class ContactPillComponent {
|
|
|
29380
29921
|
this.overlayOpen = false;
|
|
29381
29922
|
}
|
|
29382
29923
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29383
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ContactPillComponent, isStandalone: true, selector: "gn-ui-contact-pill", inputs: { contact: "contact" }, ngImport: i0, template: "<gn-ui-button\n [type]=\"overlayOpen ? 'gray-light' : 'primary-light'\"\n extraClass=\"group w-full min-h-12 gap-3 justify-between py-2 pl-5 pr-4 rounded\"\n data-test=\"contact-pill\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <span\n class=\"font-title font-medium text-base leading-tight truncate\"\n [class]=\"!overlayOpen ? 'text-primary-black group-hover:text-white' : ''\"\n [title]=\"displayName\"\n >{{ displayName }}</span\n >\n <div\n class=\"gn-ui-card-icon items-center justify-center w-10 h-8\"\n [class]=\"\n !overlayOpen ? 'group-hover:border-white group-hover:text-white' : ''\n \"\n >\n @if (overlayOpen) {\n <ng-icon class=\"!w-6 !h-6 !text-[24px]\" name=\"matClose\"></ng-icon>\n } @else {\n <ng-icon class=\"!w-6 !h-6 !text-[24px]\" name=\"matInfoOutline\"></ng-icon>\n }\n </div>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayOffsetX]=\"overlayOffsetX\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div [style.width.px]=\"overlayWidth\">\n <gn-ui-contact-details [contact]=\"contact\"></gn-ui-contact-details>\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$
|
|
29924
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ContactPillComponent, isStandalone: true, selector: "gn-ui-contact-pill", inputs: { contact: "contact" }, ngImport: i0, template: "<gn-ui-button\n [type]=\"overlayOpen ? 'gray-light' : 'primary-light'\"\n extraClass=\"group w-full min-h-12 gap-3 justify-between py-2 pl-5 pr-4 rounded\"\n data-test=\"contact-pill\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <span\n class=\"font-title font-medium text-base leading-tight truncate\"\n [class]=\"!overlayOpen ? 'text-primary-black group-hover:text-white' : ''\"\n [title]=\"displayName\"\n >{{ displayName }}</span\n >\n <div\n class=\"gn-ui-card-icon items-center justify-center w-10 h-8\"\n [class]=\"\n !overlayOpen ? 'group-hover:border-white group-hover:text-white' : ''\n \"\n >\n @if (overlayOpen) {\n <ng-icon class=\"!w-6 !h-6 !text-[24px]\" name=\"matClose\"></ng-icon>\n } @else {\n <ng-icon class=\"!w-6 !h-6 !text-[24px]\" name=\"matInfoOutline\"></ng-icon>\n }\n </div>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayOffsetX]=\"overlayOffsetX\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div [style.width.px]=\"overlayWidth\">\n <gn-ui-contact-details [contact]=\"contact\"></gn-ui-contact-details>\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { 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: ContactDetailsComponent, selector: "gn-ui-contact-details", inputs: ["contact"] }], viewProviders: [provideIcons({ matClose, matInfoOutline })], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
29384
29925
|
}
|
|
29385
29926
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, decorators: [{
|
|
29386
29927
|
type: Component,
|
|
@@ -30106,7 +30647,7 @@ class ServiceCapabilitiesComponent {
|
|
|
30106
30647
|
if (this.apiLinks.length > 0 &&
|
|
30107
30648
|
this.apiLinks[0].accessServiceProtocol !== 'ogcFeatures') {
|
|
30108
30649
|
this.loading = true;
|
|
30109
|
-
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol);
|
|
30650
|
+
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol, true);
|
|
30110
30651
|
this.loading = false;
|
|
30111
30652
|
this.cdr.detectChanges();
|
|
30112
30653
|
this.filteredLayers = this.availableLayers;
|
|
@@ -31302,19 +31843,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31302
31843
|
type: Output
|
|
31303
31844
|
}] } });
|
|
31304
31845
|
|
|
31846
|
+
class NotificationsService {
|
|
31847
|
+
constructor() {
|
|
31848
|
+
this.notifications$ = new BehaviorSubject([]);
|
|
31849
|
+
}
|
|
31850
|
+
showNotification(content, timeoutMs, error) {
|
|
31851
|
+
error && console.error(error);
|
|
31852
|
+
const id = Math.floor(Math.random() * 1000000);
|
|
31853
|
+
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31854
|
+
if (typeof timeoutMs !== 'undefined') {
|
|
31855
|
+
setTimeout(() => {
|
|
31856
|
+
this.removeNotificationById(id);
|
|
31857
|
+
}, timeoutMs);
|
|
31858
|
+
}
|
|
31859
|
+
return id;
|
|
31860
|
+
}
|
|
31861
|
+
removeNotificationById(id) {
|
|
31862
|
+
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31863
|
+
}
|
|
31864
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31865
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31866
|
+
}
|
|
31867
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31868
|
+
type: Injectable,
|
|
31869
|
+
args: [{
|
|
31870
|
+
providedIn: 'root',
|
|
31871
|
+
}]
|
|
31872
|
+
}] });
|
|
31873
|
+
|
|
31874
|
+
class NotificationsContainerComponent {
|
|
31875
|
+
constructor() {
|
|
31876
|
+
this.notificationsService = inject(NotificationsService);
|
|
31877
|
+
}
|
|
31878
|
+
trackById(index, notification) {
|
|
31879
|
+
return notification.id;
|
|
31880
|
+
}
|
|
31881
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31882
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NotificationsContainerComponent, isStandalone: true, selector: "gn-ui-notifications-container", ngImport: i0, 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", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NotificationComponent, selector: "gn-ui-notification", inputs: ["type", "title", "text", "closeMessage"], outputs: ["notificationClose"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], animations: [
|
|
31883
|
+
trigger('enterExit', [
|
|
31884
|
+
transition(':enter', [
|
|
31885
|
+
animate('150ms', keyframes([
|
|
31886
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31887
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31888
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31889
|
+
])),
|
|
31890
|
+
]),
|
|
31891
|
+
transition(':leave', [
|
|
31892
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31893
|
+
]),
|
|
31894
|
+
]),
|
|
31895
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31896
|
+
}
|
|
31897
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31898
|
+
type: Component,
|
|
31899
|
+
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31900
|
+
trigger('enterExit', [
|
|
31901
|
+
transition(':enter', [
|
|
31902
|
+
animate('150ms', keyframes([
|
|
31903
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31904
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31905
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31906
|
+
])),
|
|
31907
|
+
]),
|
|
31908
|
+
transition(':leave', [
|
|
31909
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31910
|
+
]),
|
|
31911
|
+
]),
|
|
31912
|
+
], 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" }]
|
|
31913
|
+
}] });
|
|
31914
|
+
|
|
31305
31915
|
class FilterDropdownComponent {
|
|
31306
31916
|
constructor() {
|
|
31307
31917
|
this.searchFacade = inject(SearchFacade);
|
|
31308
31918
|
this.searchService = inject(SearchService);
|
|
31309
31919
|
this.fieldsService = inject(FieldsService);
|
|
31920
|
+
this.notificationsService = inject(NotificationsService);
|
|
31921
|
+
this.translateService = inject(TranslateService);
|
|
31922
|
+
this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
|
|
31310
31923
|
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([])));
|
|
31311
|
-
this.selectedDateRange$ = this.selected$.pipe(map$1((
|
|
31924
|
+
this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
|
|
31925
|
+
this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
|
|
31926
|
+
? selected
|
|
31927
|
+
: null));
|
|
31928
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31312
31929
|
}
|
|
31313
31930
|
onSelectedValues(values) {
|
|
31314
31931
|
this.fieldsService
|
|
31315
31932
|
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
31316
31933
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31317
31934
|
}
|
|
31935
|
+
onBboxChange(bbox) {
|
|
31936
|
+
this.fieldsService
|
|
31937
|
+
.buildFiltersFromFieldValues({
|
|
31938
|
+
[this.fieldName]: bbox,
|
|
31939
|
+
})
|
|
31940
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31941
|
+
this.clearSpatialExtentErrorNotification();
|
|
31942
|
+
}
|
|
31943
|
+
onSpatialExtentError(error) {
|
|
31944
|
+
this.clearSpatialExtentErrorNotification();
|
|
31945
|
+
this.spatialExtentErrorNotificationId =
|
|
31946
|
+
this.notificationsService.showNotification({
|
|
31947
|
+
type: 'error',
|
|
31948
|
+
title: this.translateService.instant('search.filters.spatialExtent.error.title'),
|
|
31949
|
+
text: this.translateService.instant(error.key, error.params),
|
|
31950
|
+
});
|
|
31951
|
+
}
|
|
31952
|
+
clearSpatialExtentErrorNotification() {
|
|
31953
|
+
if (this.spatialExtentErrorNotificationId === null)
|
|
31954
|
+
return;
|
|
31955
|
+
this.notificationsService.removeNotificationById(this.spatialExtentErrorNotificationId);
|
|
31956
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31957
|
+
}
|
|
31318
31958
|
ngOnInit() {
|
|
31319
31959
|
this.fieldType = this.fieldsService.getFieldType(this.fieldName);
|
|
31320
31960
|
this.choices$ = this.fieldsService.getAvailableValues(this.fieldName).pipe(startWith$1([]), map$1((values) => values.map((v) => ({
|
|
@@ -31322,27 +31962,15 @@ class FilterDropdownComponent {
|
|
|
31322
31962
|
value: v.value.toString(), // converting to string for the dropdown
|
|
31323
31963
|
}))), catchError(() => of([])));
|
|
31324
31964
|
}
|
|
31325
|
-
|
|
31326
|
-
|
|
31327
|
-
|
|
31328
|
-
|
|
31329
|
-
|
|
31330
|
-
|
|
31331
|
-
if (!end)
|
|
31332
|
-
return;
|
|
31333
|
-
this.dateRange = { ...this.dateRange, end };
|
|
31334
|
-
if (this.dateRange.start && this.dateRange.end) {
|
|
31335
|
-
this.fieldsService
|
|
31336
|
-
.buildFiltersFromFieldValues({
|
|
31337
|
-
[this.fieldName]: this.dateRange,
|
|
31338
|
-
})
|
|
31339
|
-
.subscribe((filters) => {
|
|
31340
|
-
return this.searchService.updateFilters(filters);
|
|
31341
|
-
});
|
|
31342
|
-
}
|
|
31965
|
+
onDateRangeChange(dateRange) {
|
|
31966
|
+
this.fieldsService
|
|
31967
|
+
.buildFiltersFromFieldValues({
|
|
31968
|
+
[this.fieldName]: dateRange,
|
|
31969
|
+
})
|
|
31970
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31343
31971
|
}
|
|
31344
31972
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31345
|
-
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 [
|
|
31973
|
+
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 }); }
|
|
31346
31974
|
}
|
|
31347
31975
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
|
|
31348
31976
|
type: Component,
|
|
@@ -31350,7 +31978,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31350
31978
|
CommonModule,
|
|
31351
31979
|
DateRangeDropdownComponent,
|
|
31352
31980
|
DropdownMultiselectComponent,
|
|
31353
|
-
|
|
31981
|
+
SpatialExtentDropdownComponent,
|
|
31982
|
+
], 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" }]
|
|
31354
31983
|
}], propDecorators: { fieldName: [{
|
|
31355
31984
|
type: Input
|
|
31356
31985
|
}], title: [{
|
|
@@ -31411,7 +32040,7 @@ class FuzzySearchComponent {
|
|
|
31411
32040
|
this.isSearchActive.emit(event);
|
|
31412
32041
|
}
|
|
31413
32042
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31414
|
-
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 }); }
|
|
32043
|
+
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 }); }
|
|
31415
32044
|
}
|
|
31416
32045
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, decorators: [{
|
|
31417
32046
|
type: Component,
|
|
@@ -31886,74 +32515,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31886
32515
|
args: ['gnUiSearchStateContainer']
|
|
31887
32516
|
}] } });
|
|
31888
32517
|
|
|
31889
|
-
class NotificationsService {
|
|
31890
|
-
constructor() {
|
|
31891
|
-
this.notifications$ = new BehaviorSubject([]);
|
|
31892
|
-
}
|
|
31893
|
-
showNotification(content, timeoutMs, error) {
|
|
31894
|
-
error && console.error(error);
|
|
31895
|
-
const id = Math.floor(Math.random() * 1000000);
|
|
31896
|
-
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31897
|
-
if (typeof timeoutMs === 'undefined')
|
|
31898
|
-
return;
|
|
31899
|
-
setTimeout(() => {
|
|
31900
|
-
this.removeNotificationById(id);
|
|
31901
|
-
}, timeoutMs);
|
|
31902
|
-
}
|
|
31903
|
-
removeNotificationById(id) {
|
|
31904
|
-
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31905
|
-
}
|
|
31906
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31907
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31908
|
-
}
|
|
31909
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31910
|
-
type: Injectable,
|
|
31911
|
-
args: [{
|
|
31912
|
-
providedIn: 'root',
|
|
31913
|
-
}]
|
|
31914
|
-
}] });
|
|
31915
|
-
|
|
31916
|
-
class NotificationsContainerComponent {
|
|
31917
|
-
constructor() {
|
|
31918
|
-
this.notificationsService = inject(NotificationsService);
|
|
31919
|
-
}
|
|
31920
|
-
trackById(index, notification) {
|
|
31921
|
-
return notification.id;
|
|
31922
|
-
}
|
|
31923
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31924
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NotificationsContainerComponent, isStandalone: true, selector: "gn-ui-notifications-container", ngImport: i0, 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", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NotificationComponent, selector: "gn-ui-notification", inputs: ["type", "title", "text", "closeMessage"], outputs: ["notificationClose"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], animations: [
|
|
31925
|
-
trigger('enterExit', [
|
|
31926
|
-
transition(':enter', [
|
|
31927
|
-
animate('150ms', keyframes([
|
|
31928
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31929
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31930
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31931
|
-
])),
|
|
31932
|
-
]),
|
|
31933
|
-
transition(':leave', [
|
|
31934
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31935
|
-
]),
|
|
31936
|
-
]),
|
|
31937
|
-
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31938
|
-
}
|
|
31939
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31940
|
-
type: Component,
|
|
31941
|
-
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31942
|
-
trigger('enterExit', [
|
|
31943
|
-
transition(':enter', [
|
|
31944
|
-
animate('150ms', keyframes([
|
|
31945
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31946
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31947
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31948
|
-
])),
|
|
31949
|
-
]),
|
|
31950
|
-
transition(':leave', [
|
|
31951
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31952
|
-
]),
|
|
31953
|
-
]),
|
|
31954
|
-
], 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" }]
|
|
31955
|
-
}] });
|
|
31956
|
-
|
|
31957
32518
|
class ResultsTableContainerComponent {
|
|
31958
32519
|
constructor() {
|
|
31959
32520
|
this.searchFacade = inject(SearchFacade);
|
|
@@ -32038,12 +32599,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
32038
32599
|
|
|
32039
32600
|
marker('search.filters.summaryLabel.user');
|
|
32040
32601
|
marker('search.filters.summaryLabel.changeDate');
|
|
32602
|
+
marker('search.filters.summaryLabel.resourceCreationRevisionDate');
|
|
32603
|
+
const OPEN_BOUND = '…';
|
|
32041
32604
|
class SearchFiltersSummaryItemComponent {
|
|
32042
32605
|
constructor() {
|
|
32043
32606
|
this.searchFacade = inject(SearchFacade);
|
|
32044
32607
|
this.searchService = inject(SearchService);
|
|
32045
32608
|
this.fieldsService = inject(FieldsService);
|
|
32046
|
-
this.
|
|
32609
|
+
this.dateService = inject(DateService);
|
|
32047
32610
|
this.translate = inject(TranslateService);
|
|
32048
32611
|
this.fieldValues$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$2((fieldValues) => Array.isArray(fieldValues[this.fieldName])
|
|
32049
32612
|
? fieldValues[this.fieldName]
|
|
@@ -32070,9 +32633,10 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32070
32633
|
getReadableValues(fieldValues) {
|
|
32071
32634
|
return fieldValues.map((value) => {
|
|
32072
32635
|
if (this.fieldType === 'dateRange') {
|
|
32636
|
+
const { start, end } = value;
|
|
32073
32637
|
return {
|
|
32074
32638
|
value,
|
|
32075
|
-
label: `${this.
|
|
32639
|
+
label: `${this.formatBound(start)} - ${this.formatBound(end)}`,
|
|
32076
32640
|
};
|
|
32077
32641
|
}
|
|
32078
32642
|
else if (this.fieldName === 'user') {
|
|
@@ -32083,6 +32647,15 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32083
32647
|
}
|
|
32084
32648
|
});
|
|
32085
32649
|
}
|
|
32650
|
+
formatBound(date) {
|
|
32651
|
+
return date
|
|
32652
|
+
? this.dateService.formatDate(date, {
|
|
32653
|
+
day: '2-digit',
|
|
32654
|
+
month: '2-digit',
|
|
32655
|
+
year: 'numeric',
|
|
32656
|
+
})
|
|
32657
|
+
: OPEN_BOUND;
|
|
32658
|
+
}
|
|
32086
32659
|
async removeFilterValue(fieldValue) {
|
|
32087
32660
|
const currentFieldValues = await firstValueFrom(this.fieldValues$);
|
|
32088
32661
|
const updatedFieldValues = currentFieldValues
|
|
@@ -32095,11 +32668,11 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32095
32668
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
32096
32669
|
}
|
|
32097
32670
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32098
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SearchFiltersSummaryItemComponent, isStandalone: true, selector: "gn-ui-search-filters-summary-item", inputs: { fieldName: "fieldName" },
|
|
32671
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SearchFiltersSummaryItemComponent, isStandalone: true, selector: "gn-ui-search-filters-summary-item", inputs: { fieldName: "fieldName" }, ngImport: i0, template: "@if ((fieldValues$ | async)?.length > 0) {\n <div class=\"flex flex-row items-center gap-2\">\n <span class=\"text-gray-800\" data-cy=\"filterSummaryLabel\">{{\n translatedLabel\n }}</span>\n @for (fieldValue of fieldValues$ | async; track fieldValue) {\n <gn-ui-badge\n class=\"gn-ui-badge\"\n [style.--gn-ui-badge-rounded]=\"'8px'\"\n [style.--gn-ui-badge-padding]=\"'3px 4px'\"\n [style.--gn-ui-badge-text-color]=\"'black'\"\n [style.--gn-ui-badge-background-color]=\"'#F2F2F2'\"\n [style.--gn-ui-badge-font-weight]=\"'700'\"\n [removable]=\"true\"\n (badgeRemoveClicked)=\"removeFilterValue(fieldValue.value)\"\n >{{ fieldValue.label }}</gn-ui-badge\n >\n }\n </div>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BadgeComponent, selector: "gn-ui-badge", inputs: ["clickable", "removable"], outputs: ["badgeRemoveClicked", "badgeClicked"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
32099
32672
|
}
|
|
32100
32673
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, decorators: [{
|
|
32101
32674
|
type: Component,
|
|
32102
|
-
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent],
|
|
32675
|
+
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent], template: "@if ((fieldValues$ | async)?.length > 0) {\n <div class=\"flex flex-row items-center gap-2\">\n <span class=\"text-gray-800\" data-cy=\"filterSummaryLabel\">{{\n translatedLabel\n }}</span>\n @for (fieldValue of fieldValues$ | async; track fieldValue) {\n <gn-ui-badge\n class=\"gn-ui-badge\"\n [style.--gn-ui-badge-rounded]=\"'8px'\"\n [style.--gn-ui-badge-padding]=\"'3px 4px'\"\n [style.--gn-ui-badge-text-color]=\"'black'\"\n [style.--gn-ui-badge-background-color]=\"'#F2F2F2'\"\n [style.--gn-ui-badge-font-weight]=\"'700'\"\n [removable]=\"true\"\n (badgeRemoveClicked)=\"removeFilterValue(fieldValue.value)\"\n >{{ fieldValue.label }}</gn-ui-badge\n >\n }\n </div>\n}\n" }]
|
|
32103
32676
|
}], propDecorators: { fieldName: [{
|
|
32104
32677
|
type: Input
|
|
32105
32678
|
}] } });
|
|
@@ -32343,11 +32916,11 @@ class AddLayerFromFileComponent {
|
|
|
32343
32916
|
}, 5000);
|
|
32344
32917
|
}
|
|
32345
32918
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32346
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AddLayerFromFileComponent, isStandalone: true, selector: "gn-ui-add-layer-from-file", ngImport: i0, template: "<div class=\"flex flex-col gap-2 my-2\">\n <div class=\"flex items-center gap-4\">\n <div class=\"grow rounded-md border-2 border-gray-200\">\n <gn-ui-drag-and-drop-file-input\n (fileChange)=\"handleFileChange($event)\"\n [accept]=\"acceptedMimeType.join(',')\"\n [placeholder]=\"'map.addFromFile.placeholder' | translate\"\n class=\"placeholder-grey\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n </div>\n <p class=\"text-sm text-gray-600\" translate>map.help.addFromFile</p>\n</div>\n\n@if (errorMessage) {\n <div class=\"text-red-500 mt-2\">\n {{ errorMessage }}\n </div>\n}\n\n@if (successMessage) {\n <div class=\"text-green-500 mt-2\">\n {{ successMessage }}\n </div>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept"], outputs: ["fileChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
32919
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AddLayerFromFileComponent, isStandalone: true, selector: "gn-ui-add-layer-from-file", ngImport: i0, template: "<div class=\"flex flex-col gap-2 my-2\">\n <div class=\"flex items-center gap-4\">\n <div class=\"grow rounded-md border-2 border-gray-200\">\n <gn-ui-drag-and-drop-file-input\n (fileChange)=\"handleFileChange($event)\"\n [accept]=\"acceptedMimeType.join(',')\"\n [placeholder]=\"'map.addFromFile.placeholder' | translate\"\n textClass=\"text-gray-900 pl-2 py-2\"\n class=\"placeholder-grey\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n </div>\n <p class=\"text-sm text-gray-600\" translate>map.help.addFromFile</p>\n</div>\n\n@if (errorMessage) {\n <div class=\"text-red-500 mt-2\">\n {{ errorMessage }}\n </div>\n}\n\n@if (successMessage) {\n <div class=\"text-green-500 mt-2\">\n {{ successMessage }}\n </div>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { 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" }] }); }
|
|
32347
32920
|
}
|
|
32348
32921
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, decorators: [{
|
|
32349
32922
|
type: Component,
|
|
32350
|
-
args: [{ selector: 'gn-ui-add-layer-from-file', standalone: true, imports: [TranslateDirective, TranslatePipe, DragAndDropFileInputComponent], template: "<div class=\"flex flex-col gap-2 my-2\">\n <div class=\"flex items-center gap-4\">\n <div class=\"grow rounded-md border-2 border-gray-200\">\n <gn-ui-drag-and-drop-file-input\n (fileChange)=\"handleFileChange($event)\"\n [accept]=\"acceptedMimeType.join(',')\"\n [placeholder]=\"'map.addFromFile.placeholder' | translate\"\n class=\"placeholder-grey\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n </div>\n <p class=\"text-sm text-gray-600\" translate>map.help.addFromFile</p>\n</div>\n\n@if (errorMessage) {\n <div class=\"text-red-500 mt-2\">\n {{ errorMessage }}\n </div>\n}\n\n@if (successMessage) {\n <div class=\"text-green-500 mt-2\">\n {{ successMessage }}\n </div>\n}\n" }]
|
|
32923
|
+
args: [{ selector: 'gn-ui-add-layer-from-file', standalone: true, imports: [TranslateDirective, TranslatePipe, DragAndDropFileInputComponent], template: "<div class=\"flex flex-col gap-2 my-2\">\n <div class=\"flex items-center gap-4\">\n <div class=\"grow rounded-md border-2 border-gray-200\">\n <gn-ui-drag-and-drop-file-input\n (fileChange)=\"handleFileChange($event)\"\n [accept]=\"acceptedMimeType.join(',')\"\n [placeholder]=\"'map.addFromFile.placeholder' | translate\"\n textClass=\"text-gray-900 pl-2 py-2\"\n class=\"placeholder-grey\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n </div>\n <p class=\"text-sm text-gray-600\" translate>map.help.addFromFile</p>\n</div>\n\n@if (errorMessage) {\n <div class=\"text-red-500 mt-2\">\n {{ errorMessage }}\n </div>\n}\n\n@if (successMessage) {\n <div class=\"text-green-500 mt-2\">\n {{ successMessage }}\n </div>\n}\n" }]
|
|
32351
32924
|
}] });
|
|
32352
32925
|
|
|
32353
32926
|
class LayersPanelComponent {
|
|
@@ -32408,95 +32981,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
32408
32981
|
], 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" }]
|
|
32409
32982
|
}] });
|
|
32410
32983
|
|
|
32411
|
-
class GeocodingComponent {
|
|
32412
|
-
constructor() {
|
|
32413
|
-
this.mapFacade = inject(MapFacade);
|
|
32414
|
-
this.geocodingService = inject(GeocodingService);
|
|
32415
|
-
this.searchText = '';
|
|
32416
|
-
this.results = [];
|
|
32417
|
-
this.searchTextChanged = new Subject();
|
|
32418
|
-
this.destroy$ = new Subject();
|
|
32419
|
-
this.errorMessage = null;
|
|
32420
|
-
this.searchTextChanged
|
|
32421
|
-
.pipe(debounceTime(300), switchMap$1((searchText) => {
|
|
32422
|
-
return from(this.geocodingService.query(searchText)).pipe(catchError$1((error) => {
|
|
32423
|
-
this.errorMessage =
|
|
32424
|
-
'An error occurred while searching. Please try again.';
|
|
32425
|
-
console.error(error);
|
|
32426
|
-
return [];
|
|
32427
|
-
}));
|
|
32428
|
-
}), takeUntil(this.destroy$))
|
|
32429
|
-
.subscribe((results) => {
|
|
32430
|
-
this.results = results;
|
|
32431
|
-
});
|
|
32432
|
-
}
|
|
32433
|
-
ngOnDestroy() {
|
|
32434
|
-
this.destroy$.next();
|
|
32435
|
-
this.destroy$.complete();
|
|
32436
|
-
}
|
|
32437
|
-
onSearchChange(searchText) {
|
|
32438
|
-
if (!searchText) {
|
|
32439
|
-
this.clearSearch();
|
|
32440
|
-
return;
|
|
32441
|
-
}
|
|
32442
|
-
else {
|
|
32443
|
-
this.searchTextChanged.next(searchText);
|
|
32444
|
-
}
|
|
32445
|
-
}
|
|
32446
|
-
clearSearch() {
|
|
32447
|
-
this.searchText = '';
|
|
32448
|
-
this.results = [];
|
|
32449
|
-
this.errorMessage = null;
|
|
32450
|
-
}
|
|
32451
|
-
async zoomToLocation(result) {
|
|
32452
|
-
const geometry = result.geom;
|
|
32453
|
-
if (geometry.type === 'Point') {
|
|
32454
|
-
await this.zoomToPoint(geometry.coordinates);
|
|
32455
|
-
}
|
|
32456
|
-
else if (geometry.type === 'Polygon') {
|
|
32457
|
-
await this.zoomToPolygon(geometry.coordinates);
|
|
32458
|
-
}
|
|
32459
|
-
else {
|
|
32460
|
-
console.error(`Unsupported geometry type: ${geometry.type}`);
|
|
32461
|
-
}
|
|
32462
|
-
}
|
|
32463
|
-
async zoomToPoint(pointCoords) {
|
|
32464
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32465
|
-
const view = {
|
|
32466
|
-
center: pointCoords,
|
|
32467
|
-
zoom: 10,
|
|
32468
|
-
};
|
|
32469
|
-
this.mapFacade.applyContext({
|
|
32470
|
-
...context,
|
|
32471
|
-
view,
|
|
32472
|
-
});
|
|
32473
|
-
}
|
|
32474
|
-
async zoomToPolygon(polygonCoords) {
|
|
32475
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32476
|
-
const view = {
|
|
32477
|
-
geometry: {
|
|
32478
|
-
type: 'Polygon',
|
|
32479
|
-
coordinates: polygonCoords,
|
|
32480
|
-
},
|
|
32481
|
-
};
|
|
32482
|
-
this.mapFacade.applyContext({
|
|
32483
|
-
...context,
|
|
32484
|
-
view,
|
|
32485
|
-
});
|
|
32486
|
-
}
|
|
32487
|
-
onEnterPress() {
|
|
32488
|
-
if (this.results && this.results.length > 0) {
|
|
32489
|
-
this.zoomToLocation(this.results[0]);
|
|
32490
|
-
}
|
|
32491
|
-
}
|
|
32492
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32493
|
-
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" }] }); }
|
|
32494
|
-
}
|
|
32495
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, decorators: [{
|
|
32496
|
-
type: Component,
|
|
32497
|
-
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" }]
|
|
32498
|
-
}], ctorParameters: () => [] });
|
|
32499
|
-
|
|
32500
32984
|
/*
|
|
32501
32985
|
Metadata actions
|
|
32502
32986
|
*/
|
|
@@ -32512,8 +32996,7 @@ const closeMetadata = createAction('[Metadata view] close');
|
|
|
32512
32996
|
Related actions
|
|
32513
32997
|
*/
|
|
32514
32998
|
const setRelated = createAction('[Metadata view] Set related records', props());
|
|
32515
|
-
const
|
|
32516
|
-
const setSourceOf = createAction('[Metadata view] Set has sources', props());
|
|
32999
|
+
const setLinkedRecords = createAction('[Metadata view] Set associated records', props());
|
|
32517
33000
|
/*
|
|
32518
33001
|
ChartConfig actions
|
|
32519
33002
|
*/
|
|
@@ -32545,9 +33028,8 @@ var mdview_actions = /*#__PURE__*/Object.freeze({
|
|
|
32545
33028
|
loadUserFeedbacksSuccess: loadUserFeedbacksSuccess,
|
|
32546
33029
|
setChartConfig: setChartConfig,
|
|
32547
33030
|
setIncompleteMetadata: setIncompleteMetadata,
|
|
32548
|
-
|
|
32549
|
-
|
|
32550
|
-
setSources: setSources
|
|
33031
|
+
setLinkedRecords: setLinkedRecords,
|
|
33032
|
+
setRelated: setRelated
|
|
32551
33033
|
});
|
|
32552
33034
|
|
|
32553
33035
|
const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView';
|
|
@@ -32590,12 +33072,9 @@ on(loadFullMetadata, (state) => ({
|
|
|
32590
33072
|
on(setRelated, (state, { related }) => ({
|
|
32591
33073
|
...state,
|
|
32592
33074
|
related,
|
|
32593
|
-
})), on(
|
|
32594
|
-
...state,
|
|
32595
|
-
sources,
|
|
32596
|
-
})), on(setSourceOf, (state, { sourceOf }) => ({
|
|
33075
|
+
})), on(setLinkedRecords, (state, { linkedRecords }) => ({
|
|
32597
33076
|
...state,
|
|
32598
|
-
|
|
33077
|
+
linkedRecords,
|
|
32599
33078
|
})),
|
|
32600
33079
|
/*
|
|
32601
33080
|
ChartConfig reducers
|
|
@@ -32657,8 +33136,7 @@ const getMetadataError = createSelector(getMdViewState, (state) => state.error);
|
|
|
32657
33136
|
Related selectors
|
|
32658
33137
|
*/
|
|
32659
33138
|
const getRelated = createSelector(getMdViewState, (state) => state.related);
|
|
32660
|
-
const
|
|
32661
|
-
const getSourceOf = createSelector(getMdViewState, (state) => state.sourceOf);
|
|
33139
|
+
const getLinkedRecords = createSelector(getMdViewState, (state) => state.linkedRecords);
|
|
32662
33140
|
/*
|
|
32663
33141
|
Metadata selectors
|
|
32664
33142
|
*/
|
|
@@ -32759,6 +33237,453 @@ function parseHeaders(httpHeaders) {
|
|
|
32759
33237
|
return result;
|
|
32760
33238
|
}
|
|
32761
33239
|
|
|
33240
|
+
const GEOMETRY_COLUMN_ALIAS = '__geometry__';
|
|
33241
|
+
function fieldToSql(name) {
|
|
33242
|
+
return `"${name.replace(/"/g, '""')}"`; // escape double quotes in field names
|
|
33243
|
+
}
|
|
33244
|
+
function filterToSql(filter) {
|
|
33245
|
+
const operator = filter[0];
|
|
33246
|
+
const args = filter.slice(1);
|
|
33247
|
+
function valueToSql(value) {
|
|
33248
|
+
return typeof value === 'number' ? value : `'${value}'`;
|
|
33249
|
+
}
|
|
33250
|
+
switch (operator) {
|
|
33251
|
+
case '<':
|
|
33252
|
+
case '<=':
|
|
33253
|
+
case '>':
|
|
33254
|
+
case '>=':
|
|
33255
|
+
case '=':
|
|
33256
|
+
case '!=':
|
|
33257
|
+
case 'like':
|
|
33258
|
+
return `${fieldToSql(args[0])} ${operator.toUpperCase()} ${valueToSql(args[1])}`;
|
|
33259
|
+
case 'in': {
|
|
33260
|
+
const values = args.slice(1);
|
|
33261
|
+
return `${fieldToSql(args[0])} IN (${values.map(valueToSql).join(', ')})`;
|
|
33262
|
+
}
|
|
33263
|
+
case 'and':
|
|
33264
|
+
case 'or': {
|
|
33265
|
+
const children = args
|
|
33266
|
+
.map(filterToSql)
|
|
33267
|
+
.join(` ${operator.toUpperCase()} `);
|
|
33268
|
+
return `(${children})`;
|
|
33269
|
+
}
|
|
33270
|
+
case 'not':
|
|
33271
|
+
return `NOT (${filterToSql(args[0])})`;
|
|
33272
|
+
}
|
|
33273
|
+
throw new Error(`Could not generate SQL query, operator not recognized: ${operator}`);
|
|
33274
|
+
}
|
|
33275
|
+
function aggregationToSql(aggregation) {
|
|
33276
|
+
const operation = aggregation[0];
|
|
33277
|
+
const field = aggregation[1];
|
|
33278
|
+
switch (operation) {
|
|
33279
|
+
case 'average':
|
|
33280
|
+
return `CAST(AVG(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`average(${field})`)}`;
|
|
33281
|
+
case 'sum':
|
|
33282
|
+
case 'max':
|
|
33283
|
+
case 'min':
|
|
33284
|
+
return `CAST(${operation.toUpperCase()}(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`${operation}(${field})`)}`;
|
|
33285
|
+
case 'count':
|
|
33286
|
+
return 'CAST(COUNT(*) AS INTEGER) as "count()"'; // we don't need Bigint precision here
|
|
33287
|
+
}
|
|
33288
|
+
}
|
|
33289
|
+
/**
|
|
33290
|
+
* Leave arguments at null if not used
|
|
33291
|
+
* @param tableName
|
|
33292
|
+
* @param selected
|
|
33293
|
+
* @param filter
|
|
33294
|
+
* @param sort
|
|
33295
|
+
* @param startIndex
|
|
33296
|
+
* @param count
|
|
33297
|
+
* @param groupBy
|
|
33298
|
+
* @param aggregations
|
|
33299
|
+
*/
|
|
33300
|
+
function generateSqlQuery(tableName, selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null, geometryColumn = null) {
|
|
33301
|
+
let sqlSelect = 'SELECT *';
|
|
33302
|
+
const sqlFrom = ` FROM ${tableName}`;
|
|
33303
|
+
let sqlOrderBy = '';
|
|
33304
|
+
let sqlWhere = '';
|
|
33305
|
+
let sqlLimit = '';
|
|
33306
|
+
let sqlGroupBy = '';
|
|
33307
|
+
if (selected !== null) {
|
|
33308
|
+
sqlSelect = `SELECT ${selected.map(fieldToSql).join(', ')}`;
|
|
33309
|
+
}
|
|
33310
|
+
if (geometryColumn !== null) {
|
|
33311
|
+
sqlSelect += `, ST_AsGeoJSON(${fieldToSql(geometryColumn)}) as ${GEOMETRY_COLUMN_ALIAS}`;
|
|
33312
|
+
}
|
|
33313
|
+
if (filter !== null) {
|
|
33314
|
+
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
33315
|
+
}
|
|
33316
|
+
if (sort?.length) {
|
|
33317
|
+
sqlOrderBy = ` ORDER BY ${sort
|
|
33318
|
+
.map((sort) => `${fieldToSql(sort[1])} ${sort[0].toUpperCase()}`)
|
|
33319
|
+
.join(', ')}`;
|
|
33320
|
+
}
|
|
33321
|
+
if (startIndex !== null && count !== null) {
|
|
33322
|
+
sqlLimit = ` LIMIT ${count} OFFSET ${startIndex}`;
|
|
33323
|
+
}
|
|
33324
|
+
if (groupBy !== null && aggregations !== null) {
|
|
33325
|
+
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33326
|
+
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33327
|
+
const sqlGroupByFields = groupedByDistinct
|
|
33328
|
+
.map((group) => fieldToSql(group[1]))
|
|
33329
|
+
.join(', ');
|
|
33330
|
+
const sqlGroupBySelect = groupedByDistinct
|
|
33331
|
+
.map((group) => `${fieldToSql(group[1])} as ${fieldToSql(`distinct(${group[1]})`)}`)
|
|
33332
|
+
.join(', ');
|
|
33333
|
+
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33334
|
+
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33335
|
+
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33336
|
+
}
|
|
33337
|
+
}
|
|
33338
|
+
return sqlSelect + sqlFrom + sqlGroupBy + sqlWhere + sqlOrderBy + sqlLimit;
|
|
33339
|
+
}
|
|
33340
|
+
|
|
33341
|
+
function arrowTableToDataItems(table) {
|
|
33342
|
+
const fields = table.schema.fields;
|
|
33343
|
+
return table.toArray().map((row) => {
|
|
33344
|
+
const rowJson = row.toJSON();
|
|
33345
|
+
const feature = {
|
|
33346
|
+
type: 'Feature',
|
|
33347
|
+
geometry: null,
|
|
33348
|
+
properties: {},
|
|
33349
|
+
};
|
|
33350
|
+
const keys = Object.keys(rowJson);
|
|
33351
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33352
|
+
const key = keys[i];
|
|
33353
|
+
const dataType = fields[i].type;
|
|
33354
|
+
let value = rowJson[key];
|
|
33355
|
+
// this might happen if we get an array inside a field
|
|
33356
|
+
if (value instanceof Vector) {
|
|
33357
|
+
value = Array.from(value);
|
|
33358
|
+
}
|
|
33359
|
+
// cast bigints to ints
|
|
33360
|
+
if (typeof value === 'bigint') {
|
|
33361
|
+
value = Number(value);
|
|
33362
|
+
}
|
|
33363
|
+
// rename columns with empty name
|
|
33364
|
+
if (!key) {
|
|
33365
|
+
feature.properties['unknown'] = value;
|
|
33366
|
+
continue;
|
|
33367
|
+
}
|
|
33368
|
+
// assign properties that look like an id to the geojson `id` field
|
|
33369
|
+
if (/^(object|feature)?_?id$/.test(key.toLowerCase()) &&
|
|
33370
|
+
(typeof value == 'string' || typeof value === 'number')) {
|
|
33371
|
+
feature.id = value;
|
|
33372
|
+
}
|
|
33373
|
+
// if a date is in timestamp (number) format, convert it to native
|
|
33374
|
+
if (typeof value === 'number' &&
|
|
33375
|
+
(DataType.isTimestamp(dataType) || DataType.isDate(dataType))) {
|
|
33376
|
+
value = new Date(value);
|
|
33377
|
+
}
|
|
33378
|
+
// if a binary field (most likely a geometry column): skip
|
|
33379
|
+
if (DataType.isBinary(dataType)) {
|
|
33380
|
+
continue;
|
|
33381
|
+
}
|
|
33382
|
+
// geometry column
|
|
33383
|
+
if (key === GEOMETRY_COLUMN_ALIAS && DataType.isUtf8(dataType)) {
|
|
33384
|
+
feature.geometry = JSON.parse(value);
|
|
33385
|
+
continue;
|
|
33386
|
+
}
|
|
33387
|
+
feature.properties[key] = value;
|
|
33388
|
+
}
|
|
33389
|
+
return feature;
|
|
33390
|
+
});
|
|
33391
|
+
}
|
|
33392
|
+
|
|
33393
|
+
// init code taken from https://github.com/duckdb/duckdb-wasm/blob/main/packages/duckdb-wasm/README.md
|
|
33394
|
+
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
|
33395
|
+
// from https://duckdb.org/docs/current/sql/data_types/overview
|
|
33396
|
+
const typesMapping = {
|
|
33397
|
+
INTEGER: 'number',
|
|
33398
|
+
SMALLINT: 'number',
|
|
33399
|
+
TINYINT: 'number',
|
|
33400
|
+
BIGINT: 'number',
|
|
33401
|
+
HUGEINT: 'number',
|
|
33402
|
+
UINTEGER: 'number',
|
|
33403
|
+
USMALLINT: 'number',
|
|
33404
|
+
UTINYINT: 'number',
|
|
33405
|
+
UBIGINT: 'number',
|
|
33406
|
+
UHUGEINT: 'number',
|
|
33407
|
+
DOUBLE: 'number',
|
|
33408
|
+
BIGNUM: 'number',
|
|
33409
|
+
DECIMAL: 'number',
|
|
33410
|
+
NUMERIC: 'number',
|
|
33411
|
+
FLOAT: 'number',
|
|
33412
|
+
REAL: 'number',
|
|
33413
|
+
'TIMESTAMP WITH TIME ZONE': 'date',
|
|
33414
|
+
TIMESTAMP: 'date',
|
|
33415
|
+
DATE: 'date',
|
|
33416
|
+
CHAR: 'string',
|
|
33417
|
+
VARCHAR: 'string',
|
|
33418
|
+
TEXT: 'string',
|
|
33419
|
+
UUID: 'string',
|
|
33420
|
+
BLOB: 'string',
|
|
33421
|
+
BIT: 'string',
|
|
33422
|
+
INTERVAL: 'string',
|
|
33423
|
+
LIST: 'string',
|
|
33424
|
+
BOOLEAN: 'boolean',
|
|
33425
|
+
};
|
|
33426
|
+
class Engine {
|
|
33427
|
+
async makeInit() {
|
|
33428
|
+
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
|
|
33429
|
+
let worker_url = bundle.mainWorker;
|
|
33430
|
+
// this is necessary to let browsers execute WASM code coming from a cross-origin host
|
|
33431
|
+
if (worker_url.startsWith('https://')) {
|
|
33432
|
+
worker_url = URL.createObjectURL(new Blob([`importScripts("${worker_url}");`], {
|
|
33433
|
+
type: 'text/javascript',
|
|
33434
|
+
}));
|
|
33435
|
+
}
|
|
33436
|
+
const worker = new Worker(worker_url);
|
|
33437
|
+
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
|
|
33438
|
+
this.db = new duckdb.AsyncDuckDB(logger, worker);
|
|
33439
|
+
await this.db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
33440
|
+
// setup duckdb options
|
|
33441
|
+
const conn = await this.db.connect();
|
|
33442
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33443
|
+
await conn.query(`INSTALL spatial; LOAD spatial;`);
|
|
33444
|
+
await conn.query(`SET TimeZone = '${timezone}';`);
|
|
33445
|
+
await conn.query(`SET threads = 1;`);
|
|
33446
|
+
// await conn.query(`SET memory_limit = '2GB';`) // used for experimenting when we encounter memory issues
|
|
33447
|
+
await conn.query(`SET preserve_insertion_order = false;`); // this reduces memory usage when loading a dataset
|
|
33448
|
+
conn.close();
|
|
33449
|
+
return this;
|
|
33450
|
+
}
|
|
33451
|
+
isReady() {
|
|
33452
|
+
if (!this.init_) {
|
|
33453
|
+
this.init_ = this.makeInit();
|
|
33454
|
+
}
|
|
33455
|
+
return this.init_;
|
|
33456
|
+
}
|
|
33457
|
+
/**
|
|
33458
|
+
* Returns information about a dataset once it's loaded:
|
|
33459
|
+
* - a list of properties description
|
|
33460
|
+
* - the name of the dataset geometry column (null if no geometry present)
|
|
33461
|
+
* @param datasetId name of the table under which the dataset will be stored
|
|
33462
|
+
* @param loadQuery duckdb-specific query for creating a table out of the data
|
|
33463
|
+
* @param forceReload if true, any existing data will be dropped and redownloaded
|
|
33464
|
+
*/
|
|
33465
|
+
async loadFile(datasetId, loadQuery, forceReload = false) {
|
|
33466
|
+
const conn = await this.db.connect();
|
|
33467
|
+
let results;
|
|
33468
|
+
// either we want to recreate the table, or we keep it if it already exists
|
|
33469
|
+
const safeLoadQuery = forceReload
|
|
33470
|
+
? `DROP TABLE IF EXISTS ${datasetId};
|
|
33471
|
+
${loadQuery}`
|
|
33472
|
+
: loadQuery.replace(/CREATE TABLE(?! IF NOT EXISTS)/gi, 'CREATE TABLE IF NOT EXISTS');
|
|
33473
|
+
// create the table
|
|
33474
|
+
try {
|
|
33475
|
+
results = await conn.query(safeLoadQuery);
|
|
33476
|
+
}
|
|
33477
|
+
catch (e) {
|
|
33478
|
+
throw new FetchError('parse', `DuckDB encountered an error when loading the data: ${e.message}`);
|
|
33479
|
+
}
|
|
33480
|
+
// read rows count
|
|
33481
|
+
results = await conn.query(`SELECT count(*) FROM ${datasetId}`);
|
|
33482
|
+
const { 'count_star()': recordsCount } = results.toArray()[0].toJSON();
|
|
33483
|
+
// read columns
|
|
33484
|
+
results = await conn.query(`SELECT * FROM information_schema.columns WHERE table_name = '${datasetId}';`);
|
|
33485
|
+
let geometryColumn = null;
|
|
33486
|
+
const properties = results
|
|
33487
|
+
.toArray()
|
|
33488
|
+
.map((row) => {
|
|
33489
|
+
const rowObj = row.toJSON();
|
|
33490
|
+
if (rowObj['data_type'] === 'GEOMETRY') {
|
|
33491
|
+
// the geometry is not part of the properties
|
|
33492
|
+
// note: right now we only keep one geometry column name, but if there are multiple they will
|
|
33493
|
+
// all get discarded
|
|
33494
|
+
geometryColumn = rowObj['column_name'];
|
|
33495
|
+
return null;
|
|
33496
|
+
}
|
|
33497
|
+
return {
|
|
33498
|
+
name: rowObj['column_name'],
|
|
33499
|
+
label: rowObj['column_name'],
|
|
33500
|
+
type: typesMapping[rowObj['data_type']] ?? 'other',
|
|
33501
|
+
};
|
|
33502
|
+
})
|
|
33503
|
+
.filter((prop) => prop !== null);
|
|
33504
|
+
conn.close();
|
|
33505
|
+
return {
|
|
33506
|
+
properties,
|
|
33507
|
+
geometryColumn,
|
|
33508
|
+
rowsCount: Number(recordsCount),
|
|
33509
|
+
};
|
|
33510
|
+
}
|
|
33511
|
+
// register a Uint8 buffer using a handle in the duckdb instance
|
|
33512
|
+
async registerData(name, buffer) {
|
|
33513
|
+
return this.db.registerFileBuffer(name, buffer);
|
|
33514
|
+
}
|
|
33515
|
+
/**
|
|
33516
|
+
* @param query duckdb-specific query for fetching items
|
|
33517
|
+
*/
|
|
33518
|
+
async queryItems(query) {
|
|
33519
|
+
const conn = await this.db.connect();
|
|
33520
|
+
const results = await conn.query(query);
|
|
33521
|
+
conn.close();
|
|
33522
|
+
return arrowTableToDataItems(results);
|
|
33523
|
+
}
|
|
33524
|
+
close() {
|
|
33525
|
+
this.db?.terminate();
|
|
33526
|
+
}
|
|
33527
|
+
}
|
|
33528
|
+
let engine = null;
|
|
33529
|
+
async function getEngine() {
|
|
33530
|
+
if (!engine) {
|
|
33531
|
+
engine = new Engine();
|
|
33532
|
+
}
|
|
33533
|
+
return engine.isReady();
|
|
33534
|
+
}
|
|
33535
|
+
|
|
33536
|
+
class BaseReader {
|
|
33537
|
+
constructor(url) {
|
|
33538
|
+
this.url = url;
|
|
33539
|
+
this.selected = null;
|
|
33540
|
+
this.groupedBy = null;
|
|
33541
|
+
this.aggregations = null;
|
|
33542
|
+
this.filter = null;
|
|
33543
|
+
this.sort = null;
|
|
33544
|
+
this.startIndex = null;
|
|
33545
|
+
this.count = null;
|
|
33546
|
+
this.loadPromise_ = Promise.resolve();
|
|
33547
|
+
this.cacheEnabled = false;
|
|
33548
|
+
}
|
|
33549
|
+
enableCache(enabled) {
|
|
33550
|
+
this.cacheEnabled = enabled;
|
|
33551
|
+
}
|
|
33552
|
+
load() {
|
|
33553
|
+
throw new Error('not implemented');
|
|
33554
|
+
}
|
|
33555
|
+
get isLoaded() {
|
|
33556
|
+
return this.loadPromise_;
|
|
33557
|
+
}
|
|
33558
|
+
get properties() {
|
|
33559
|
+
throw new Error('not implemented');
|
|
33560
|
+
}
|
|
33561
|
+
get info() {
|
|
33562
|
+
throw new Error('not implemented');
|
|
33563
|
+
}
|
|
33564
|
+
read() {
|
|
33565
|
+
throw new Error('not implemented');
|
|
33566
|
+
}
|
|
33567
|
+
selectAll() {
|
|
33568
|
+
this.groupedBy = null;
|
|
33569
|
+
this.aggregations = null;
|
|
33570
|
+
this.selected = null;
|
|
33571
|
+
this.filter = null;
|
|
33572
|
+
this.startIndex = null;
|
|
33573
|
+
this.count = null;
|
|
33574
|
+
return this;
|
|
33575
|
+
}
|
|
33576
|
+
select(...selectedFields) {
|
|
33577
|
+
this.selected = selectedFields;
|
|
33578
|
+
this.aggregations = null; // clear aggregations & groups when selecting fields
|
|
33579
|
+
this.groupedBy = null;
|
|
33580
|
+
return this;
|
|
33581
|
+
}
|
|
33582
|
+
groupBy(...groupBy) {
|
|
33583
|
+
this.groupedBy = groupBy;
|
|
33584
|
+
this.selected = null; // clear normal field selection when aggregating
|
|
33585
|
+
return this;
|
|
33586
|
+
}
|
|
33587
|
+
aggregate(...aggregations) {
|
|
33588
|
+
this.aggregations = aggregations;
|
|
33589
|
+
return this;
|
|
33590
|
+
}
|
|
33591
|
+
where(filter) {
|
|
33592
|
+
this.filter = filter;
|
|
33593
|
+
return this;
|
|
33594
|
+
}
|
|
33595
|
+
orderBy(...fieldSorts) {
|
|
33596
|
+
this.sort = fieldSorts;
|
|
33597
|
+
return this;
|
|
33598
|
+
}
|
|
33599
|
+
limit(startIndex, count) {
|
|
33600
|
+
this.startIndex = startIndex;
|
|
33601
|
+
this.count = count;
|
|
33602
|
+
return this;
|
|
33603
|
+
}
|
|
33604
|
+
}
|
|
33605
|
+
|
|
33606
|
+
/**
|
|
33607
|
+
* This reader handles file formats supported natively by DuckDB
|
|
33608
|
+
*/
|
|
33609
|
+
class BaseFileReader extends BaseReader {
|
|
33610
|
+
// a table id should not exceed 63 chars
|
|
33611
|
+
generateDatasetId() {
|
|
33612
|
+
// generate a hash out of the url
|
|
33613
|
+
let hash = 0;
|
|
33614
|
+
for (const char of this.url) {
|
|
33615
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
33616
|
+
hash = hash >>> 0; // make it unsigned
|
|
33617
|
+
}
|
|
33618
|
+
return `datafetcher_${hash.toString(16)}`;
|
|
33619
|
+
}
|
|
33620
|
+
async getLoadQuery() {
|
|
33621
|
+
throw new Error('not implemented');
|
|
33622
|
+
}
|
|
33623
|
+
async load() {
|
|
33624
|
+
this.datasetId = this.generateDatasetId();
|
|
33625
|
+
this.loadPromise_ = getEngine()
|
|
33626
|
+
.then((engine) => {
|
|
33627
|
+
this.engine = engine;
|
|
33628
|
+
return this.getLoadQuery();
|
|
33629
|
+
})
|
|
33630
|
+
.then((loadQuery) => this.engine.loadFile(this.datasetId, loadQuery, !this.cacheEnabled))
|
|
33631
|
+
.then((datasetInfo) => {
|
|
33632
|
+
this.properties_ = datasetInfo.properties;
|
|
33633
|
+
this.geometryColumn = datasetInfo.geometryColumn;
|
|
33634
|
+
this.rowsCount = datasetInfo.rowsCount;
|
|
33635
|
+
// returns void for the loaded promise
|
|
33636
|
+
});
|
|
33637
|
+
}
|
|
33638
|
+
get properties() {
|
|
33639
|
+
return this.isLoaded.then(() => this.properties_);
|
|
33640
|
+
}
|
|
33641
|
+
get info() {
|
|
33642
|
+
return this.isLoaded.then(() => ({
|
|
33643
|
+
itemsCount: this.rowsCount,
|
|
33644
|
+
hasGeometry: !!this.geometryColumn,
|
|
33645
|
+
}));
|
|
33646
|
+
}
|
|
33647
|
+
async read() {
|
|
33648
|
+
await this.isLoaded;
|
|
33649
|
+
// if only certain fields are selected, omit the geometry
|
|
33650
|
+
const geometryColumn = this.selected === null ? this.geometryColumn : null;
|
|
33651
|
+
const query = generateSqlQuery(this.datasetId, this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations, geometryColumn);
|
|
33652
|
+
return this.engine.queryItems(query);
|
|
33653
|
+
}
|
|
33654
|
+
}
|
|
33655
|
+
|
|
33656
|
+
class CsvReader extends BaseFileReader {
|
|
33657
|
+
async getLoadQuery() {
|
|
33658
|
+
// first we get a list of columns hich have a detected type of VARCHAR
|
|
33659
|
+
// then we make sure that for those columns, we don't cast an empty string to null; instead we want to keep the empty string
|
|
33660
|
+
return `
|
|
33661
|
+
SET VARIABLE strColumns = (SELECT list(name) FROM (SELECT unnest(Columns, recursive := true) FROM sniff_csv("${this.url}")) WHERE type = 'VARCHAR');
|
|
33662
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_csv("${this.url}",
|
|
33663
|
+
force_not_null = getvariable('strColumns'),
|
|
33664
|
+
auto_type_candidates = ['NULL', 'BOOLEAN', 'INTEGER', 'DOUBLE', 'DATE', 'VARCHAR']
|
|
33665
|
+
);`;
|
|
33666
|
+
}
|
|
33667
|
+
}
|
|
33668
|
+
|
|
33669
|
+
class JsonReader extends BaseFileReader {
|
|
33670
|
+
async getLoadQuery() {
|
|
33671
|
+
return `
|
|
33672
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_json("${this.url}",
|
|
33673
|
+
maximum_object_size = 536870912 -- 500MB
|
|
33674
|
+
);`;
|
|
33675
|
+
}
|
|
33676
|
+
}
|
|
33677
|
+
|
|
33678
|
+
class GeojsonReader extends BaseFileReader {
|
|
33679
|
+
async getLoadQuery() {
|
|
33680
|
+
return `
|
|
33681
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33682
|
+
allowed_drivers = ['GeoJSON']
|
|
33683
|
+
);`;
|
|
33684
|
+
}
|
|
33685
|
+
}
|
|
33686
|
+
|
|
32762
33687
|
async function inferDatasetType(url, typeHint) {
|
|
32763
33688
|
const fileExtensionMatches = new URL(url, typeof window !== 'undefined' ? window.location.toString() : undefined).pathname.match(/\.(.+)$/);
|
|
32764
33689
|
const fileExtension = fileExtensionMatches && fileExtensionMatches.length
|
|
@@ -32823,127 +33748,6 @@ function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
|
32823
33748
|
return new Uint8Array(array).buffer;
|
|
32824
33749
|
});
|
|
32825
33750
|
}
|
|
32826
|
-
function tryParseDate(input) {
|
|
32827
|
-
if (typeof input !== 'string')
|
|
32828
|
-
return null;
|
|
32829
|
-
function tryIso(value) {
|
|
32830
|
-
const parsed = parseISO(value);
|
|
32831
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32832
|
-
}
|
|
32833
|
-
function tryFormat(value, format) {
|
|
32834
|
-
const parsed = parse$4(value, format, new Date());
|
|
32835
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32836
|
-
}
|
|
32837
|
-
return (tryIso(input) ||
|
|
32838
|
-
tryFormat(input, 'dd/MM/yyyy') ||
|
|
32839
|
-
tryFormat(input, 'dd.MM.yyyy') ||
|
|
32840
|
-
tryFormat(input, 'MM/dd/yyyy') ||
|
|
32841
|
-
null);
|
|
32842
|
-
}
|
|
32843
|
-
function tryParseNumber(input) {
|
|
32844
|
-
if (isNaN(input))
|
|
32845
|
-
return null;
|
|
32846
|
-
const parsed = parseFloat(input);
|
|
32847
|
-
return isNaN(parsed) ? null : parsed;
|
|
32848
|
-
}
|
|
32849
|
-
function jsonToGeojsonFeature(object) {
|
|
32850
|
-
const { id, properties } = Object.keys(object)
|
|
32851
|
-
.map((property) => (property ? property : 'unknown')) //prevent empty strings
|
|
32852
|
-
.reduce((prev, curr) => curr.toLowerCase().endsWith('id')
|
|
32853
|
-
? {
|
|
32854
|
-
...prev,
|
|
32855
|
-
id: object[curr],
|
|
32856
|
-
}
|
|
32857
|
-
: {
|
|
32858
|
-
...prev,
|
|
32859
|
-
properties: { ...prev.properties, [curr]: object[curr] },
|
|
32860
|
-
}, { id: undefined, properties: {} });
|
|
32861
|
-
return {
|
|
32862
|
-
type: 'Feature',
|
|
32863
|
-
geometry: null,
|
|
32864
|
-
properties,
|
|
32865
|
-
...(id !== undefined && { id }),
|
|
32866
|
-
};
|
|
32867
|
-
}
|
|
32868
|
-
function mutateProperties(items, mutators) {
|
|
32869
|
-
const mutatorKeys = Object.keys(mutators);
|
|
32870
|
-
for (let i = 0, ii = items.length; i < ii; i++) {
|
|
32871
|
-
const item = items[i];
|
|
32872
|
-
for (const mutatorField of mutatorKeys) {
|
|
32873
|
-
if (!(mutatorField in item.properties))
|
|
32874
|
-
continue;
|
|
32875
|
-
item.properties[mutatorField] = mutators[mutatorField](item.properties[mutatorField]);
|
|
32876
|
-
}
|
|
32877
|
-
}
|
|
32878
|
-
return items;
|
|
32879
|
-
}
|
|
32880
|
-
const SAMPLE_SIZE = 20;
|
|
32881
|
-
/**
|
|
32882
|
-
* This will infer field types from a list of data items and cast the values accordingly
|
|
32883
|
-
* @param items
|
|
32884
|
-
* @param inferTypes
|
|
32885
|
-
*/
|
|
32886
|
-
function processItemProperties(items, inferTypes = false) {
|
|
32887
|
-
const foundFields = {};
|
|
32888
|
-
for (let i = 0, ii = Math.min(SAMPLE_SIZE, items.length); i < ii; i++) {
|
|
32889
|
-
const item = items[i];
|
|
32890
|
-
const fields = Object.keys(item.properties);
|
|
32891
|
-
for (const field of fields) {
|
|
32892
|
-
if (!(field in foundFields)) {
|
|
32893
|
-
foundFields[field] = {
|
|
32894
|
-
label: field,
|
|
32895
|
-
name: field,
|
|
32896
|
-
type: null,
|
|
32897
|
-
};
|
|
32898
|
-
}
|
|
32899
|
-
const value = item.properties[field];
|
|
32900
|
-
const info = foundFields[field];
|
|
32901
|
-
if (value === undefined || value === '' || value === null)
|
|
32902
|
-
continue;
|
|
32903
|
-
if (!inferTypes) {
|
|
32904
|
-
if (info.type === null && typeof value === 'number') {
|
|
32905
|
-
info.type = 'number';
|
|
32906
|
-
}
|
|
32907
|
-
else if (info.type === 'number' && typeof value !== 'number') {
|
|
32908
|
-
info.type = 'string';
|
|
32909
|
-
}
|
|
32910
|
-
continue;
|
|
32911
|
-
}
|
|
32912
|
-
const parsedNumber = tryParseNumber(value);
|
|
32913
|
-
if (info.type === null && parsedNumber !== null) {
|
|
32914
|
-
info.type = 'number';
|
|
32915
|
-
continue;
|
|
32916
|
-
}
|
|
32917
|
-
else if (info.type === 'number' && parsedNumber === null) {
|
|
32918
|
-
info.type = 'string';
|
|
32919
|
-
continue;
|
|
32920
|
-
}
|
|
32921
|
-
const parsedDate = tryParseDate(value);
|
|
32922
|
-
if (info.type === null && parsedDate !== null) {
|
|
32923
|
-
info.type = 'date';
|
|
32924
|
-
}
|
|
32925
|
-
else if (info.type === 'date' && parsedDate === null) {
|
|
32926
|
-
info.type = 'string';
|
|
32927
|
-
}
|
|
32928
|
-
}
|
|
32929
|
-
}
|
|
32930
|
-
const properties = [];
|
|
32931
|
-
const mutators = {};
|
|
32932
|
-
for (const field in foundFields) {
|
|
32933
|
-
const info = foundFields[field];
|
|
32934
|
-
if (info.type === 'number') {
|
|
32935
|
-
mutators[field] = tryParseNumber;
|
|
32936
|
-
}
|
|
32937
|
-
else if (info.type === 'date') {
|
|
32938
|
-
mutators[field] = tryParseDate;
|
|
32939
|
-
}
|
|
32940
|
-
properties.push({ ...info, type: info.type || 'string' });
|
|
32941
|
-
}
|
|
32942
|
-
if (inferTypes) {
|
|
32943
|
-
mutateProperties(items, mutators);
|
|
32944
|
-
}
|
|
32945
|
-
return { items, properties };
|
|
32946
|
-
}
|
|
32947
33751
|
/**
|
|
32948
33752
|
* This creates a Proxy that allows reading and writing to the data item properties
|
|
32949
33753
|
* as if it was a simple array of JSON objects
|
|
@@ -32965,333 +33769,71 @@ function getJsonDataItemsProxy(items) {
|
|
|
32965
33769
|
});
|
|
32966
33770
|
}
|
|
32967
33771
|
|
|
32968
|
-
|
|
32969
|
-
|
|
32970
|
-
|
|
32971
|
-
|
|
32972
|
-
|
|
32973
|
-
|
|
32974
|
-
|
|
32975
|
-
|
|
32976
|
-
|
|
32977
|
-
|
|
32978
|
-
|
|
32979
|
-
|
|
32980
|
-
|
|
32981
|
-
|
|
32982
|
-
|
|
32983
|
-
|
|
32984
|
-
|
|
32985
|
-
return `[${args[0]}] IN (${values.map(valueToSql).join(', ')})`;
|
|
32986
|
-
}
|
|
32987
|
-
case 'and':
|
|
32988
|
-
case 'or': {
|
|
32989
|
-
const children = args
|
|
32990
|
-
.map(filterToSql)
|
|
32991
|
-
.join(` ${operator.toUpperCase()} `);
|
|
32992
|
-
return `(${children})`;
|
|
32993
|
-
}
|
|
32994
|
-
case 'not':
|
|
32995
|
-
return `NOT (${filterToSql(args[0])})`;
|
|
32996
|
-
}
|
|
32997
|
-
throw new Error(`Could not generate SQL query, operator not recognized: ${operator}`);
|
|
32998
|
-
}
|
|
32999
|
-
function aggregationToSql(aggregation) {
|
|
33000
|
-
const operation = aggregation[0];
|
|
33001
|
-
const field = aggregation[1];
|
|
33002
|
-
switch (operation) {
|
|
33003
|
-
case 'average':
|
|
33004
|
-
return `AVG([${field}]) as [average(${field})]`;
|
|
33005
|
-
case 'sum':
|
|
33006
|
-
case 'max':
|
|
33007
|
-
case 'min':
|
|
33008
|
-
return `${operation.toUpperCase()}([${field}]) as [${operation}(${field})]`;
|
|
33009
|
-
case 'count':
|
|
33010
|
-
return 'COUNT(*) as [count()]';
|
|
33011
|
-
}
|
|
33012
|
-
}
|
|
33013
|
-
/**
|
|
33014
|
-
* Leave arguments at null if not used
|
|
33015
|
-
* @param selected
|
|
33016
|
-
* @param filter
|
|
33017
|
-
* @param sort
|
|
33018
|
-
* @param startIndex
|
|
33019
|
-
* @param count
|
|
33020
|
-
* @param groupBy
|
|
33021
|
-
* @param aggregations
|
|
33022
|
-
*/
|
|
33023
|
-
function generateSqlQuery(selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null) {
|
|
33024
|
-
let sqlSelect = 'SELECT *';
|
|
33025
|
-
const sqlFrom = ' FROM ?';
|
|
33026
|
-
let sqlOrderBy = '';
|
|
33027
|
-
let sqlWhere = '';
|
|
33028
|
-
let sqlLimit = '';
|
|
33029
|
-
let sqlGroupBy = '';
|
|
33030
|
-
if (selected !== null) {
|
|
33031
|
-
sqlSelect = `SELECT ${selected.map((name) => `[${name}]`).join(', ')}`;
|
|
33032
|
-
}
|
|
33033
|
-
if (filter !== null) {
|
|
33034
|
-
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
33035
|
-
}
|
|
33036
|
-
if (sort?.length) {
|
|
33037
|
-
sqlOrderBy = ` ORDER BY ${sort
|
|
33038
|
-
.map((sort) => `[${sort[1]}] ${sort[0].toUpperCase()}`)
|
|
33039
|
-
.join(', ')}`;
|
|
33040
|
-
}
|
|
33041
|
-
if (startIndex !== null && count !== null) {
|
|
33042
|
-
sqlLimit = ` LIMIT ${count} OFFSET ${startIndex}`;
|
|
33043
|
-
}
|
|
33044
|
-
if (groupBy !== null && aggregations !== null) {
|
|
33045
|
-
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33046
|
-
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33047
|
-
const sqlGroupByFields = groupedByDistinct
|
|
33048
|
-
.map((group) => `[${group[1]}]`)
|
|
33049
|
-
.join(', ');
|
|
33050
|
-
const sqlGroupBySelect = groupedByDistinct
|
|
33051
|
-
.map((group) => `[${group[1]}] as [distinct(${group[1]})]`)
|
|
33052
|
-
.join(', ');
|
|
33053
|
-
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33054
|
-
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33055
|
-
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33772
|
+
class ExcelReader extends BaseFileReader {
|
|
33773
|
+
async getLoadQuery() {
|
|
33774
|
+
// we download the file as an array buffer first, in order to be able to check if it's an XLS file
|
|
33775
|
+
let buffer = await fetchDataAsArrayBuffer(this.url, this.cacheEnabled);
|
|
33776
|
+
const bufferHandle = `B${this.datasetId}`;
|
|
33777
|
+
// checking against the magic number at the beginning of XLS files, see https://en.wikipedia.org/wiki/List_of_file_signatures
|
|
33778
|
+
const magicNumber = new Uint8Array(buffer, 0, 8); // first 8 bytes
|
|
33779
|
+
const isXls = Array.from(magicNumber)
|
|
33780
|
+
.map((n) => n.toString(16).toUpperCase())
|
|
33781
|
+
.join(' ') === 'D0 CF 11 E0 A1 B1 1A E1';
|
|
33782
|
+
// uh oh, this is an XLS file (not supported by duckdb); convert it to CSV using the xlsx package
|
|
33783
|
+
if (isXls) {
|
|
33784
|
+
buffer = await import('xlsx').then(({ read, utils }) => {
|
|
33785
|
+
const workbook = read(buffer);
|
|
33786
|
+
const json = utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
|
|
33787
|
+
return new TextEncoder().encode(JSON.stringify(json)).buffer;
|
|
33788
|
+
});
|
|
33056
33789
|
}
|
|
33057
|
-
|
|
33058
|
-
|
|
33059
|
-
|
|
33060
|
-
|
|
33061
|
-
class BaseReader {
|
|
33062
|
-
constructor(url) {
|
|
33063
|
-
this.url = url;
|
|
33064
|
-
this.selected = null;
|
|
33065
|
-
this.groupedBy = null;
|
|
33066
|
-
this.aggregations = null;
|
|
33067
|
-
this.filter = null;
|
|
33068
|
-
this.sort = null;
|
|
33069
|
-
this.startIndex = null;
|
|
33070
|
-
this.count = null;
|
|
33071
|
-
}
|
|
33072
|
-
load() {
|
|
33073
|
-
throw new Error('not implemented');
|
|
33074
|
-
}
|
|
33075
|
-
get properties() {
|
|
33076
|
-
throw new Error('not implemented');
|
|
33077
|
-
}
|
|
33078
|
-
get info() {
|
|
33079
|
-
throw new Error('not implemented');
|
|
33080
|
-
}
|
|
33081
|
-
read() {
|
|
33082
|
-
throw new Error('not implemented');
|
|
33083
|
-
}
|
|
33084
|
-
selectAll() {
|
|
33085
|
-
this.groupedBy = null;
|
|
33086
|
-
this.aggregations = null;
|
|
33087
|
-
this.selected = null;
|
|
33088
|
-
this.filter = null;
|
|
33089
|
-
this.startIndex = null;
|
|
33090
|
-
this.count = null;
|
|
33091
|
-
return this;
|
|
33092
|
-
}
|
|
33093
|
-
select(...selectedFields) {
|
|
33094
|
-
this.selected = selectedFields;
|
|
33095
|
-
this.aggregations = null; // clear aggregations & groups when selecting fields
|
|
33096
|
-
this.groupedBy = null;
|
|
33097
|
-
return this;
|
|
33098
|
-
}
|
|
33099
|
-
groupBy(...groupBy) {
|
|
33100
|
-
this.groupedBy = groupBy;
|
|
33101
|
-
this.selected = null; // clear normal field selection when aggregating
|
|
33102
|
-
return this;
|
|
33103
|
-
}
|
|
33104
|
-
aggregate(...aggregations) {
|
|
33105
|
-
this.aggregations = aggregations;
|
|
33106
|
-
return this;
|
|
33107
|
-
}
|
|
33108
|
-
where(filter) {
|
|
33109
|
-
this.filter = filter;
|
|
33110
|
-
return this;
|
|
33111
|
-
}
|
|
33112
|
-
orderBy(...fieldSorts) {
|
|
33113
|
-
this.sort = fieldSorts;
|
|
33114
|
-
return this;
|
|
33115
|
-
}
|
|
33116
|
-
limit(startIndex, count) {
|
|
33117
|
-
this.startIndex = startIndex;
|
|
33118
|
-
this.count = count;
|
|
33119
|
-
return this;
|
|
33120
|
-
}
|
|
33121
|
-
}
|
|
33122
|
-
|
|
33123
|
-
class BaseCacheReader extends BaseReader {
|
|
33124
|
-
constructor(url, cacheActive = true) {
|
|
33125
|
-
super(url);
|
|
33126
|
-
this.url = url;
|
|
33127
|
-
this.cacheActive = cacheActive;
|
|
33128
|
-
}
|
|
33129
|
-
setCacheActive(value) {
|
|
33130
|
-
this.cacheActive = value;
|
|
33131
|
-
}
|
|
33132
|
-
}
|
|
33133
|
-
|
|
33134
|
-
class BaseFileReader extends BaseCacheReader {
|
|
33135
|
-
getData() {
|
|
33136
|
-
throw new Error('not implemented');
|
|
33137
|
-
}
|
|
33138
|
-
load() {
|
|
33139
|
-
this.parseResult_ = this.getData();
|
|
33140
|
-
}
|
|
33141
|
-
get properties() {
|
|
33142
|
-
return this.parseResult_.then((result) => result.properties);
|
|
33143
|
-
}
|
|
33144
|
-
get info() {
|
|
33145
|
-
return this.parseResult_.then((result) => ({
|
|
33146
|
-
itemsCount: result.items.length,
|
|
33147
|
-
}));
|
|
33148
|
-
}
|
|
33149
|
-
async read() {
|
|
33150
|
-
const items = (await this.parseResult_).items;
|
|
33151
|
-
// no query defined: return the full results as is
|
|
33152
|
-
if (this.groupedBy == null &&
|
|
33153
|
-
this.aggregations == null &&
|
|
33154
|
-
this.selected == null &&
|
|
33155
|
-
this.sort == null &&
|
|
33156
|
-
this.filter == null &&
|
|
33157
|
-
this.startIndex == null &&
|
|
33158
|
-
this.count == null) {
|
|
33159
|
-
return items;
|
|
33160
|
-
}
|
|
33161
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33162
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33163
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33164
|
-
return result.map(jsonToGeojsonFeature);
|
|
33165
|
-
}
|
|
33166
|
-
}
|
|
33167
|
-
|
|
33168
|
-
function parseCsv(text) {
|
|
33169
|
-
// first parse the header to guess the delimiter
|
|
33170
|
-
// note that we do that to not rely on Papaparse logic for guessing delimiter
|
|
33171
|
-
let delimiter;
|
|
33172
|
-
try {
|
|
33173
|
-
const header = text.split('\n')[0];
|
|
33174
|
-
const result = Papa.parse(header, {
|
|
33175
|
-
header: false,
|
|
33176
|
-
});
|
|
33177
|
-
delimiter = result.meta.delimiter;
|
|
33178
|
-
}
|
|
33179
|
-
catch (e) {
|
|
33180
|
-
throw new Error('CSV parsing failed: the delimiter could not be guessed');
|
|
33181
|
-
}
|
|
33182
|
-
const parsed = Papa.parse(text, {
|
|
33183
|
-
header: true,
|
|
33184
|
-
skipEmptyLines: true,
|
|
33185
|
-
delimiter,
|
|
33186
|
-
});
|
|
33187
|
-
if (parsed.errors.length) {
|
|
33188
|
-
throw new Error('CSV parsing failed for the following reasons:\n' +
|
|
33189
|
-
parsed.errors
|
|
33190
|
-
.map((error) => `* ${error.message} at row ${error.row}, column ${error.index}`)
|
|
33191
|
-
.join('\n'));
|
|
33192
|
-
}
|
|
33193
|
-
const items = parsed.data.map(jsonToGeojsonFeature);
|
|
33194
|
-
return processItemProperties(items, true);
|
|
33195
|
-
}
|
|
33196
|
-
class CsvReader extends BaseFileReader {
|
|
33197
|
-
getData() {
|
|
33198
|
-
return fetchDataAsText(this.url, this.cacheActive).then(parseCsv);
|
|
33790
|
+
const duckDbFn = isXls ? 'read_json' : 'read_xlsx';
|
|
33791
|
+
await this.engine.registerData(bufferHandle, new Uint8Array(buffer));
|
|
33792
|
+
return `
|
|
33793
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM ${duckDbFn}("${bufferHandle}", ignore_errors = true);`;
|
|
33199
33794
|
}
|
|
33200
33795
|
}
|
|
33201
33796
|
|
|
33202
|
-
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
|
|
33207
|
-
|
|
33208
|
-
if (!Array.isArray(parsed)) {
|
|
33209
|
-
throw new Error('Could not parse JSON, expected an array at root level');
|
|
33210
|
-
}
|
|
33211
|
-
return processItemProperties(parsed.map(jsonToGeojsonFeature));
|
|
33212
|
-
}
|
|
33213
|
-
class JsonReader extends BaseFileReader {
|
|
33214
|
-
getData() {
|
|
33215
|
-
return fetchDataAsText(this.url, this.cacheActive).then(parseJson);
|
|
33797
|
+
class GmlReader extends BaseFileReader {
|
|
33798
|
+
async getLoadQuery() {
|
|
33799
|
+
return `
|
|
33800
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33801
|
+
allowed_drivers = ['GML']
|
|
33802
|
+
);`;
|
|
33216
33803
|
}
|
|
33217
33804
|
}
|
|
33218
33805
|
|
|
33219
|
-
|
|
33220
|
-
* This parser supports both Geojson Feature collections or arrays
|
|
33221
|
-
* of Features
|
|
33222
|
-
* @param text
|
|
33223
|
-
*/
|
|
33806
|
+
const formatGeojson = new GeoJSON$1();
|
|
33224
33807
|
function parseGeojson(text) {
|
|
33225
33808
|
const parsed = JSON.parse(text);
|
|
33226
33809
|
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33227
33810
|
if (!Array.isArray(features)) {
|
|
33228
33811
|
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33229
33812
|
}
|
|
33230
|
-
return
|
|
33231
|
-
}
|
|
33232
|
-
class GeojsonReader extends BaseFileReader {
|
|
33233
|
-
getData() {
|
|
33234
|
-
return fetchDataAsText(this.url, this.cacheActive).then(parseGeojson);
|
|
33235
|
-
}
|
|
33236
|
-
}
|
|
33237
|
-
|
|
33238
|
-
/**
|
|
33239
|
-
* This will read the first sheet of the excel workbook and expect the first
|
|
33240
|
-
* line to contain the properties names
|
|
33241
|
-
* @param buffer
|
|
33242
|
-
*/
|
|
33243
|
-
function parseExcel(buffer) {
|
|
33244
|
-
return import('xlsx').then(({ read, utils }) => {
|
|
33245
|
-
const workbook = read(buffer);
|
|
33246
|
-
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
33247
|
-
let json = utils.sheet_to_json(sheet);
|
|
33248
|
-
if (!json.length) {
|
|
33249
|
-
json = [];
|
|
33250
|
-
}
|
|
33251
|
-
return processItemProperties(json.map(jsonToGeojsonFeature), true);
|
|
33252
|
-
});
|
|
33253
|
-
}
|
|
33254
|
-
class ExcelReader extends BaseFileReader {
|
|
33255
|
-
getData() {
|
|
33256
|
-
return fetchDataAsArrayBuffer(this.url, this.cacheActive).then(parseExcel);
|
|
33257
|
-
}
|
|
33813
|
+
return features;
|
|
33258
33814
|
}
|
|
33259
|
-
|
|
33260
|
-
|
|
33261
|
-
const
|
|
33262
|
-
const regex = new RegExp(`xmlns:${splittedNamespace[0]}=["']([^'"]*)["']`);
|
|
33815
|
+
function parseGml(text, featureType, version) {
|
|
33816
|
+
const parts = featureType.split(':');
|
|
33817
|
+
const regex = new RegExp(`xmlns:${parts[0]}=["']([^'"]*)["']`);
|
|
33263
33818
|
const match = regex.exec(text);
|
|
33264
33819
|
if (match && match.length >= 2) {
|
|
33265
|
-
const
|
|
33820
|
+
const wfs = new WFS({
|
|
33266
33821
|
featureNS: match[1],
|
|
33267
|
-
featureType:
|
|
33822
|
+
featureType: parts[1],
|
|
33268
33823
|
version: version,
|
|
33269
33824
|
});
|
|
33270
33825
|
let features;
|
|
33271
33826
|
try {
|
|
33272
|
-
features =
|
|
33827
|
+
features = wfs.readFeatures(text);
|
|
33273
33828
|
}
|
|
33274
33829
|
catch (e) {
|
|
33275
|
-
throw Error(
|
|
33830
|
+
throw Error(`Couldn't parse WFS with GML features: ${e.message}`);
|
|
33276
33831
|
}
|
|
33277
|
-
const geojsonItem =
|
|
33278
|
-
return
|
|
33832
|
+
const geojsonItem = formatGeojson.writeFeaturesObject(features);
|
|
33833
|
+
return geojsonItem.features;
|
|
33279
33834
|
}
|
|
33280
33835
|
throw Error("Couldn't retrieve namespace url");
|
|
33281
33836
|
}
|
|
33282
|
-
class GmlReader extends BaseFileReader {
|
|
33283
|
-
constructor(url, namespace, version, cacheActive = true) {
|
|
33284
|
-
super(url);
|
|
33285
|
-
this.url = url;
|
|
33286
|
-
this.namespace = namespace;
|
|
33287
|
-
this.version = version;
|
|
33288
|
-
this.cacheActive = cacheActive;
|
|
33289
|
-
}
|
|
33290
|
-
getData() {
|
|
33291
|
-
return fetchDataAsText(this.url, this.cacheActive).then((text) => parseGml(text, this.namespace, this.version));
|
|
33292
|
-
}
|
|
33293
|
-
}
|
|
33294
|
-
|
|
33295
33837
|
async function getWfsEndpoint(wfsUrl) {
|
|
33296
33838
|
try {
|
|
33297
33839
|
return await new WfsEndpoint(wfsUrl).isReady();
|
|
@@ -33319,21 +33861,65 @@ async function getWfsEndpoint(wfsUrl) {
|
|
|
33319
33861
|
}
|
|
33320
33862
|
}
|
|
33321
33863
|
}
|
|
33322
|
-
class WfsReader extends
|
|
33323
|
-
constructor(url,
|
|
33324
|
-
super(url
|
|
33325
|
-
this.endpoint =
|
|
33326
|
-
this.
|
|
33327
|
-
|
|
33864
|
+
class WfsReader extends BaseReader {
|
|
33865
|
+
constructor(url, featureTypeName) {
|
|
33866
|
+
super(url);
|
|
33867
|
+
this.endpoint = getWfsEndpoint(url);
|
|
33868
|
+
this.featureType = this.endpoint
|
|
33869
|
+
.then((endpoint) => {
|
|
33870
|
+
const featureTypes = endpoint.getFeatureTypes();
|
|
33871
|
+
return endpoint.getFeatureTypeFull(featureTypes.length === 1 && !featureTypeName
|
|
33872
|
+
? featureTypes[0].name
|
|
33873
|
+
: featureTypeName);
|
|
33874
|
+
})
|
|
33875
|
+
.then((featureType) => {
|
|
33876
|
+
if (!featureType) {
|
|
33877
|
+
throw new Error('wfs.featuretype.notfound');
|
|
33878
|
+
}
|
|
33879
|
+
return featureType;
|
|
33880
|
+
});
|
|
33881
|
+
}
|
|
33882
|
+
get backupReader() {
|
|
33883
|
+
if (this.backupReader_) {
|
|
33884
|
+
return this.backupReader_;
|
|
33885
|
+
}
|
|
33886
|
+
this.backupReader_ = Promise.all([this.endpoint, this.featureType]).then(([endpoint, featureType]) => {
|
|
33887
|
+
let reader;
|
|
33888
|
+
if (endpoint.supportsJson(featureType.name)) {
|
|
33889
|
+
reader = new GeojsonReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33890
|
+
asJson: true,
|
|
33891
|
+
outputCrs: 'EPSG:4326',
|
|
33892
|
+
}));
|
|
33893
|
+
}
|
|
33894
|
+
else {
|
|
33895
|
+
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33896
|
+
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33897
|
+
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33898
|
+
reader = new GmlReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33899
|
+
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33900
|
+
outputCrs: 'EPSG:4326',
|
|
33901
|
+
}));
|
|
33902
|
+
}
|
|
33903
|
+
}
|
|
33904
|
+
reader.enableCache(this.cacheEnabled);
|
|
33905
|
+
reader.load();
|
|
33906
|
+
return reader;
|
|
33907
|
+
});
|
|
33908
|
+
return this.backupReader_;
|
|
33328
33909
|
}
|
|
33329
33910
|
get properties() {
|
|
33330
|
-
return this.
|
|
33331
|
-
.getFeatureTypeFull(this.featureTypeName)
|
|
33332
|
-
.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33911
|
+
return this.featureType.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33333
33912
|
const originalType = featureType.properties[prop];
|
|
33334
|
-
|
|
33335
|
-
|
|
33336
|
-
|
|
33913
|
+
let type;
|
|
33914
|
+
if (originalType === 'float' || originalType === 'integer') {
|
|
33915
|
+
type = 'number';
|
|
33916
|
+
}
|
|
33917
|
+
else if (originalType === 'boolean') {
|
|
33918
|
+
type = 'string'; // we don't handle booleans yet in the data fetcher
|
|
33919
|
+
}
|
|
33920
|
+
else {
|
|
33921
|
+
type = originalType;
|
|
33922
|
+
}
|
|
33337
33923
|
return {
|
|
33338
33924
|
name: prop,
|
|
33339
33925
|
label: prop,
|
|
@@ -33342,83 +33928,63 @@ class WfsReader extends BaseCacheReader {
|
|
|
33342
33928
|
}));
|
|
33343
33929
|
}
|
|
33344
33930
|
get info() {
|
|
33345
|
-
return this.
|
|
33931
|
+
return this.featureType.then((result) => ({
|
|
33346
33932
|
itemsCount: result.objectCount,
|
|
33933
|
+
hasGeometry: !!result.geometryName,
|
|
33347
33934
|
}));
|
|
33348
33935
|
}
|
|
33349
|
-
|
|
33350
|
-
|
|
33351
|
-
const featureTypes = wfsEndpoint.getFeatureTypes();
|
|
33352
|
-
const featureType = wfsEndpoint.getFeatureTypeSummary(featureTypes.length === 1 && !featureTypeName
|
|
33353
|
-
? featureTypes[0].name
|
|
33354
|
-
: featureTypeName);
|
|
33355
|
-
if (!featureType) {
|
|
33356
|
-
throw new Error('wfs.featuretype.notfound');
|
|
33357
|
-
}
|
|
33358
|
-
if (wfsEndpoint.supportsStartIndex()) {
|
|
33359
|
-
return new WfsReader(wfsUrlEndpoint, wfsEndpoint, featureType.name);
|
|
33360
|
-
}
|
|
33361
|
-
else if (wfsEndpoint.supportsJson(featureType.name)) {
|
|
33362
|
-
return new GeojsonReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33363
|
-
asJson: true,
|
|
33364
|
-
outputCrs: 'EPSG:4326',
|
|
33365
|
-
}));
|
|
33366
|
-
}
|
|
33367
|
-
else {
|
|
33368
|
-
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33369
|
-
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33370
|
-
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33371
|
-
return new GmlReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33372
|
-
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33373
|
-
outputCrs: 'EPSG:4326',
|
|
33374
|
-
}), featureType.name, wfsEndpoint.getVersion());
|
|
33375
|
-
}
|
|
33376
|
-
throw new Error('wfs.geojsongml.notsupported');
|
|
33377
|
-
}
|
|
33936
|
+
load() {
|
|
33937
|
+
// Nothing to load for Wfs
|
|
33378
33938
|
}
|
|
33379
|
-
async
|
|
33380
|
-
|
|
33381
|
-
|
|
33939
|
+
async read() {
|
|
33940
|
+
const endpoint = await this.endpoint;
|
|
33941
|
+
const featureType = await this.featureType;
|
|
33942
|
+
// if we can't use the WFS protocol we fall back to the backup reader
|
|
33943
|
+
if (this.aggregations || this.groupedBy || !endpoint.supportsStartIndex()) {
|
|
33944
|
+
const backupReader = await this.backupReader;
|
|
33945
|
+
backupReader.selectAll();
|
|
33946
|
+
if (this.selected) {
|
|
33947
|
+
backupReader.select(...this.selected);
|
|
33948
|
+
}
|
|
33949
|
+
if (this.aggregations) {
|
|
33950
|
+
backupReader.aggregate(...this.aggregations);
|
|
33951
|
+
}
|
|
33952
|
+
if (this.groupedBy) {
|
|
33953
|
+
backupReader.groupBy(...this.groupedBy);
|
|
33954
|
+
}
|
|
33955
|
+
if (this.sort) {
|
|
33956
|
+
backupReader.orderBy(...this.sort);
|
|
33957
|
+
}
|
|
33958
|
+
if (this.startIndex !== null && this.count !== null) {
|
|
33959
|
+
backupReader.limit(this.startIndex, this.count);
|
|
33960
|
+
}
|
|
33961
|
+
return backupReader.read();
|
|
33382
33962
|
}
|
|
33383
|
-
const asJson =
|
|
33963
|
+
const asJson = endpoint.supportsJson(featureType.name);
|
|
33384
33964
|
const attributes = this.selected ?? undefined;
|
|
33385
|
-
let
|
|
33965
|
+
let sortBy = null;
|
|
33966
|
+
if (this.sort) {
|
|
33967
|
+
const mapSort = (s) => [s[0] === 'desc' ? 'D' : 'A', s[1]];
|
|
33968
|
+
sortBy = Array.isArray(this.sort[0])
|
|
33969
|
+
? this.sort.map(mapSort)
|
|
33970
|
+
: mapSort(this.sort);
|
|
33971
|
+
}
|
|
33972
|
+
const url = endpoint.getFeatureUrl(featureType.name, {
|
|
33386
33973
|
...(this.startIndex !== null && { startIndex: this.startIndex }),
|
|
33387
33974
|
...(this.count !== null && { maxFeatures: this.count }),
|
|
33388
33975
|
asJson,
|
|
33389
33976
|
outputCrs: 'EPSG:4326',
|
|
33390
33977
|
attributes,
|
|
33391
|
-
|
|
33978
|
+
sortBy,
|
|
33392
33979
|
});
|
|
33393
|
-
|
|
33394
|
-
const finalUrl = new URL(url);
|
|
33395
|
-
const sorts = this.sort
|
|
33396
|
-
.map((fieldSort) => `${fieldSort[1]}+${fieldSort[0] === 'asc' ? 'A' : 'D'}`)
|
|
33397
|
-
.join(',');
|
|
33398
|
-
// Direct update on string url to prevent encoding of +A and +D
|
|
33399
|
-
url = `${url}${finalUrl.search ? '&' : ''}SORTBY=${sorts}`;
|
|
33400
|
-
}
|
|
33401
|
-
return fetchDataAsText(url, this.cacheActive).then((text) => asJson
|
|
33980
|
+
return fetchDataAsText(url, this.cacheEnabled).then((text) => asJson
|
|
33402
33981
|
? parseGeojson(text)
|
|
33403
|
-
: parseGml(text,
|
|
33404
|
-
}
|
|
33405
|
-
async getQueryData() {
|
|
33406
|
-
const items = (await this.getData()).items;
|
|
33407
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33408
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33409
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33410
|
-
return result.map(jsonToGeojsonFeature);
|
|
33411
|
-
}
|
|
33412
|
-
load() {
|
|
33413
|
-
// Nothing to load for Wfs
|
|
33414
|
-
}
|
|
33415
|
-
async read() {
|
|
33416
|
-
return (await this.getData(this.aggregations, this.groupedBy)).items;
|
|
33982
|
+
: parseGml(text, featureType.name, endpoint.getVersion()));
|
|
33417
33983
|
}
|
|
33418
33984
|
}
|
|
33419
33985
|
|
|
33420
|
-
async function openDataset(url,
|
|
33421
|
-
const fileType = await inferDatasetType(url, typeHint);
|
|
33986
|
+
async function openDataset(url, options) {
|
|
33987
|
+
const fileType = await inferDatasetType(url, options?.typeHint);
|
|
33422
33988
|
let reader;
|
|
33423
33989
|
try {
|
|
33424
33990
|
switch (fileType) {
|
|
@@ -33435,18 +34001,18 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33435
34001
|
reader = new ExcelReader(url);
|
|
33436
34002
|
break;
|
|
33437
34003
|
case 'gml':
|
|
33438
|
-
reader = new GmlReader(url
|
|
34004
|
+
reader = new GmlReader(url);
|
|
33439
34005
|
break;
|
|
33440
34006
|
case 'wfs':
|
|
33441
|
-
reader =
|
|
34007
|
+
reader = new WfsReader(url, options?.wfsFeatureType);
|
|
33442
34008
|
break;
|
|
33443
34009
|
}
|
|
33444
|
-
reader.
|
|
34010
|
+
reader.enableCache(options?.enableCache ?? true);
|
|
33445
34011
|
reader.load();
|
|
33446
34012
|
return reader;
|
|
33447
34013
|
}
|
|
33448
34014
|
catch (e) {
|
|
33449
|
-
//WfsReader may already raise a FetchError
|
|
34015
|
+
// WfsReader may already raise a FetchError
|
|
33450
34016
|
if (e instanceof FetchError)
|
|
33451
34017
|
throw e;
|
|
33452
34018
|
else
|
|
@@ -33457,13 +34023,13 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33457
34023
|
* This fetches the full dataset at the given URL and parses it according to its mime type.
|
|
33458
34024
|
* All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
|
|
33459
34025
|
* File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
|
|
33460
|
-
* File type is determined
|
|
34026
|
+
* File type is determined like so:
|
|
33461
34027
|
* 1. if a type hint is given, use it
|
|
33462
34028
|
* 2. otherwise, look for a Content-Type header in the response with a supported mime type
|
|
33463
34029
|
* 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
|
|
33464
34030
|
*/
|
|
33465
|
-
async function readDataset(url,
|
|
33466
|
-
const reader = await openDataset(url,
|
|
34031
|
+
async function readDataset(url, options) {
|
|
34032
|
+
const reader = await openDataset(url, options);
|
|
33467
34033
|
try {
|
|
33468
34034
|
return await reader.read();
|
|
33469
34035
|
}
|
|
@@ -33694,9 +34260,11 @@ class DataService {
|
|
|
33694
34260
|
getDataset(link, cacheActive) {
|
|
33695
34261
|
if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
|
|
33696
34262
|
const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString());
|
|
33697
|
-
return from(openDataset(wfsUrlEndpoint,
|
|
34263
|
+
return from(openDataset(wfsUrlEndpoint, {
|
|
34264
|
+
typeHint: 'wfs',
|
|
33698
34265
|
wfsFeatureType: link.name,
|
|
33699
|
-
|
|
34266
|
+
enableCache: cacheActive,
|
|
34267
|
+
}));
|
|
33700
34268
|
}
|
|
33701
34269
|
else if (link.type === 'download') {
|
|
33702
34270
|
const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString());
|
|
@@ -33704,12 +34272,15 @@ class DataService {
|
|
|
33704
34272
|
const supportedType = SupportedTypes.indexOf(format) > -1
|
|
33705
34273
|
? format
|
|
33706
34274
|
: undefined;
|
|
33707
|
-
return from(openDataset(linkProxifiedUrl,
|
|
34275
|
+
return from(openDataset(linkProxifiedUrl, {
|
|
34276
|
+
typeHint: supportedType,
|
|
34277
|
+
enableCache: cacheActive,
|
|
34278
|
+
})).pipe();
|
|
33708
34279
|
}
|
|
33709
34280
|
else if (link.type === 'service' &&
|
|
33710
34281
|
link.accessServiceProtocol === 'esriRest') {
|
|
33711
34282
|
const url = this.getDownloadUrlFromEsriRest(link.url.toString(), 'geojson');
|
|
33712
|
-
return from(openDataset(url, 'geojson',
|
|
34283
|
+
return from(openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })).pipe();
|
|
33713
34284
|
}
|
|
33714
34285
|
else if (link.type === 'service' &&
|
|
33715
34286
|
link.accessServiceProtocol === 'ogcFeatures') {
|
|
@@ -33723,7 +34294,10 @@ class DataService {
|
|
|
33723
34294
|
}
|
|
33724
34295
|
const urlWithoutLimit = new URL(geojsonUrl);
|
|
33725
34296
|
urlWithoutLimit.searchParams.delete('limit');
|
|
33726
|
-
return openDataset(urlWithoutLimit.toString(),
|
|
34297
|
+
return openDataset(urlWithoutLimit.toString(), {
|
|
34298
|
+
typeHint: 'geojson',
|
|
34299
|
+
enableCache: cacheActive,
|
|
34300
|
+
});
|
|
33727
34301
|
}));
|
|
33728
34302
|
}
|
|
33729
34303
|
return throwError(() => 'protocol not supported');
|
|
@@ -33975,20 +34549,31 @@ class DataTableComponent {
|
|
|
33975
34549
|
this.eltRef = inject(ElementRef);
|
|
33976
34550
|
this.cdr = inject(ChangeDetectorRef);
|
|
33977
34551
|
this.translateService = inject(TranslateService);
|
|
33978
|
-
this.
|
|
34552
|
+
this.columnsFromFeatureCatalog = null;
|
|
34553
|
+
this.columnsFromDataset = [];
|
|
33979
34554
|
this.selected = new EventEmitter();
|
|
33980
|
-
this.properties$ = new BehaviorSubject(null);
|
|
33981
34555
|
this.loading$ = new BehaviorSubject(false);
|
|
33982
34556
|
this.error = null;
|
|
33983
34557
|
}
|
|
33984
34558
|
set featureAttributes(value) {
|
|
33985
|
-
this.
|
|
33986
|
-
|
|
34559
|
+
this.columnsFromFeatureCatalog = value.map((attrs) => ({
|
|
34560
|
+
name: attrs.value,
|
|
34561
|
+
label: attrs.label,
|
|
34562
|
+
}));
|
|
33987
34563
|
}
|
|
33988
34564
|
set dataset(value) {
|
|
33989
34565
|
this.dataset_ = value;
|
|
33990
34566
|
this.dataset_.load();
|
|
33991
|
-
this.dataset_.info.then((info) =>
|
|
34567
|
+
this.dataset_.info.then((info) => {
|
|
34568
|
+
this.count = info.itemsCount;
|
|
34569
|
+
this.cdr.detectChanges();
|
|
34570
|
+
});
|
|
34571
|
+
}
|
|
34572
|
+
get columns() {
|
|
34573
|
+
return this.columnsFromFeatureCatalog ?? this.columnsFromDataset;
|
|
34574
|
+
}
|
|
34575
|
+
get columnNames() {
|
|
34576
|
+
return this.columns.map((c) => c.name);
|
|
33992
34577
|
}
|
|
33993
34578
|
ngOnInit() {
|
|
33994
34579
|
this.dataSource = new DataTableDataSource();
|
|
@@ -34023,11 +34608,12 @@ class DataTableComponent {
|
|
|
34023
34608
|
}
|
|
34024
34609
|
async readData() {
|
|
34025
34610
|
this.loading$.next(true);
|
|
34026
|
-
// wait for properties to be read
|
|
34027
|
-
const properties = await firstValueFrom(this.properties$.pipe(filter((p) => !!p)));
|
|
34028
|
-
const propsWithoutGeom = properties.filter((p) => !p.toLowerCase().startsWith('geom'));
|
|
34029
|
-
this.dataset_.select(...propsWithoutGeom);
|
|
34030
34611
|
try {
|
|
34612
|
+
// wait for properties to be read
|
|
34613
|
+
if (!this.columnsFromFeatureCatalog) {
|
|
34614
|
+
this.columnsFromDataset = await this.dataset_.properties;
|
|
34615
|
+
}
|
|
34616
|
+
this.dataset_.select(...this.columnNames);
|
|
34031
34617
|
await this.dataSource.showData(this.dataset_.read());
|
|
34032
34618
|
this.error = null;
|
|
34033
34619
|
}
|
|
@@ -34057,7 +34643,7 @@ class DataTableComponent {
|
|
|
34057
34643
|
}
|
|
34058
34644
|
}
|
|
34059
34645
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34060
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: DataTableComponent, isStandalone: true, selector: "gn-ui-data-table", inputs: { featureAttributes: "featureAttributes", dataset: "dataset", activeId: "activeId" }, outputs: { selected: "selected" }, providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }], viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col border border-gray-300 rounded-lg bg-white h-full\">\n <div class=\"flex-1 overflow-y-hidden overflow-x-auto rounded-lg relative\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"setSort($event)\"\n [matSortDisableClear]=\"true\"\n
|
|
34646
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: DataTableComponent, isStandalone: true, selector: "gn-ui-data-table", inputs: { featureAttributes: "featureAttributes", dataset: "dataset", activeId: "activeId" }, outputs: { selected: "selected" }, providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }], viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col border border-gray-300 rounded-lg bg-white h-full\">\n <div class=\"flex-1 overflow-y-hidden overflow-x-auto rounded-lg relative\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"setSort($event)\"\n [matSortDisableClear]=\"true\"\n >\n @for (column of columns; track column) {\n <ng-container [matColumnDef]=\"column.name\">\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n class=\"text-sm text-black bg-white\"\n >\n {{ column.label }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n class=\"whitespace-nowrap pr-1 truncate\"\n >\n {{ element[column.name] }}\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames; sticky: true\"></tr>\n <tr\n [id]=\"getRowEltId(row.id)\"\n mat-row\n *matRowDef=\"let row; columns: columnNames\"\n (click)=\"selected.emit(row)\"\n [class.active]=\"\n activeId !== undefined && activeId !== null && row.id === activeId\n \"\n ></tr>\n </table>\n @if (loading$ | async) {\n <gn-ui-loading-mask\n class=\"sticky inset-0\"\n [message]=\"'table.loading.data' | translate\"\n ></gn-ui-loading-mask>\n }\n @if (error) {\n <gn-ui-popup-alert\n type=\"warning\"\n icon=\"matErrorOutlineOutline\"\n class=\"absolute m-2 inset-0 z-[100]\"\n >\n <span translate>{{ error }}</span>\n </gn-ui-popup-alert>\n }\n </div>\n <div class=\"flex justify-between items-center overflow-hidden\">\n <div class=\"text-gray-900 px-4 py-2 text-sm\">\n <span class=\"count font-extrabold text-primary\">{{ count }}</span\n > <span translate>table.object.count</span>.\n </div>\n\n <mat-paginator\n class=\"my-[-16px]\"\n (page)=\"setPagination()\"\n [length]=\"count\"\n [pageSize]=\"10\"\n [showFirstLastButtons]=\"true\"\n [hidePageSize]=\"true\"\n ></mat-paginator>\n </div>\n</div>\n", styles: ["table{width:100%;background:#fff}th.mat-mdc-header-cell,td.mat-mdc-cell,td.mat-mdc-footer-cell{padding-right:20px}tr.mat-mdc-row,tr.mat-mdc-footer-row{height:36px}tr:hover{background:#f5f5f5}tr.mat-mdc-header-row{height:48px}[mat-header-cell]{color:#0000008a;font-size:12px;font-weight:500}tr{cursor:pointer}.active .mat-mdc-cell{color:var(--color-primary)}.mat-mdc-paginator{background:none}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$b.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$b.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$b.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$b.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$b.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$b.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$b.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$b.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$b.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$b.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i2$4.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i2$4.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: LoadingMaskComponent, selector: "gn-ui-loading-mask", inputs: ["message"] }, { kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
34061
34647
|
}
|
|
34062
34648
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
34063
34649
|
type: Component,
|
|
@@ -34069,10 +34655,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
34069
34655
|
CommonModule,
|
|
34070
34656
|
LoadingMaskComponent,
|
|
34071
34657
|
PopupAlertComponent,
|
|
34072
|
-
LetDirective,
|
|
34073
34658
|
TranslatePipe,
|
|
34074
34659
|
TranslateDirective,
|
|
34075
|
-
], providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }], selector: 'gn-ui-data-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col border border-gray-300 rounded-lg bg-white h-full\">\n <div class=\"flex-1 overflow-y-hidden overflow-x-auto rounded-lg relative\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"setSort($event)\"\n [matSortDisableClear]=\"true\"\n
|
|
34660
|
+
], providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }], selector: 'gn-ui-data-table', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col border border-gray-300 rounded-lg bg-white h-full\">\n <div class=\"flex-1 overflow-y-hidden overflow-x-auto rounded-lg relative\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"setSort($event)\"\n [matSortDisableClear]=\"true\"\n >\n @for (column of columns; track column) {\n <ng-container [matColumnDef]=\"column.name\">\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n class=\"text-sm text-black bg-white\"\n >\n {{ column.label }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n class=\"whitespace-nowrap pr-1 truncate\"\n >\n {{ element[column.name] }}\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames; sticky: true\"></tr>\n <tr\n [id]=\"getRowEltId(row.id)\"\n mat-row\n *matRowDef=\"let row; columns: columnNames\"\n (click)=\"selected.emit(row)\"\n [class.active]=\"\n activeId !== undefined && activeId !== null && row.id === activeId\n \"\n ></tr>\n </table>\n @if (loading$ | async) {\n <gn-ui-loading-mask\n class=\"sticky inset-0\"\n [message]=\"'table.loading.data' | translate\"\n ></gn-ui-loading-mask>\n }\n @if (error) {\n <gn-ui-popup-alert\n type=\"warning\"\n icon=\"matErrorOutlineOutline\"\n class=\"absolute m-2 inset-0 z-[100]\"\n >\n <span translate>{{ error }}</span>\n </gn-ui-popup-alert>\n }\n </div>\n <div class=\"flex justify-between items-center overflow-hidden\">\n <div class=\"text-gray-900 px-4 py-2 text-sm\">\n <span class=\"count font-extrabold text-primary\">{{ count }}</span\n > <span translate>table.object.count</span>.\n </div>\n\n <mat-paginator\n class=\"my-[-16px]\"\n (page)=\"setPagination()\"\n [length]=\"count\"\n [pageSize]=\"10\"\n [showFirstLastButtons]=\"true\"\n [hidePageSize]=\"true\"\n ></mat-paginator>\n </div>\n</div>\n", styles: ["table{width:100%;background:#fff}th.mat-mdc-header-cell,td.mat-mdc-cell,td.mat-mdc-footer-cell{padding-right:20px}tr.mat-mdc-row,tr.mat-mdc-footer-row{height:36px}tr:hover{background:#f5f5f5}tr.mat-mdc-header-row{height:48px}[mat-header-cell]{color:#0000008a;font-size:12px;font-weight:500}tr{cursor:pointer}.active .mat-mdc-cell{color:var(--color-primary)}.mat-mdc-paginator{background:none}\n"] }]
|
|
34076
34661
|
}], propDecorators: { featureAttributes: [{
|
|
34077
34662
|
type: Input
|
|
34078
34663
|
}], dataset: [{
|
|
@@ -34175,7 +34760,7 @@ class ChartViewComponent {
|
|
|
34175
34760
|
}), shareReplay$1(1));
|
|
34176
34761
|
this.properties$ = combineLatest([this.dataset$, this.featureCatalog$]).pipe(switchMap$1(([dataset, catalog]) => this.setProperties(dataset, catalog)), shareReplay$1(1));
|
|
34177
34762
|
this.yChoices$ = this.properties$.pipe(map$1((properties) => properties
|
|
34178
|
-
.filter((prop) => prop.type === 'number'
|
|
34763
|
+
.filter((prop) => prop.type === 'number')
|
|
34179
34764
|
.map((prop) => ({ value: prop.name, label: prop.label || prop.name }))), tap$1((choices) => {
|
|
34180
34765
|
if (!choices.find((choice) => choice.value === this.yProperty$.value)) {
|
|
34181
34766
|
const newProp = choices[0]?.value || '';
|
|
@@ -34202,6 +34787,7 @@ class ChartViewComponent {
|
|
|
34202
34787
|
this.aggregation$,
|
|
34203
34788
|
]).pipe(filter$1(([_, x, y]) => !!x || !!y), switchMap$1(([dataset, xProp, yProp, aggregation]) => {
|
|
34204
34789
|
const fieldAgg = aggregation === 'count' ? ['count'] : [aggregation, yProp];
|
|
34790
|
+
this.loading = true;
|
|
34205
34791
|
return dataset
|
|
34206
34792
|
.groupBy(['distinct', xProp])
|
|
34207
34793
|
.aggregate(fieldAgg)
|
|
@@ -34443,6 +35029,7 @@ class GeoTableViewComponent {
|
|
|
34443
35029
|
}));
|
|
34444
35030
|
}
|
|
34445
35031
|
async initMapContext() {
|
|
35032
|
+
this.dataset.load();
|
|
34446
35033
|
this.dataset.selectAll();
|
|
34447
35034
|
return {
|
|
34448
35035
|
layers: [
|
|
@@ -34616,8 +35203,7 @@ class MdViewFacade {
|
|
|
34616
35203
|
}));
|
|
34617
35204
|
this.error$ = this.store.pipe(select(getMetadataError));
|
|
34618
35205
|
this.related$ = this.store.pipe(select(getRelated));
|
|
34619
|
-
this.
|
|
34620
|
-
this.sourceOf$ = this.store.pipe(select(getSourceOf));
|
|
35206
|
+
this.linkedRecords$ = this.store.pipe(select(getLinkedRecords));
|
|
34621
35207
|
this.chartConfig$ = this.store.pipe(select(getChartConfig));
|
|
34622
35208
|
this.allLinks$ = this.metadata$.pipe(map$1((record) => 'onlineResources' in record ? record.onlineResources : []), shareReplay$1(1));
|
|
34623
35209
|
this.resourceDoi$ = this.metadata$.pipe(map$1((record) => {
|
|
@@ -34736,12 +35322,9 @@ class MdViewEffects {
|
|
|
34736
35322
|
this.loadRelatedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSimilarRecords(full)), map$1((related) => {
|
|
34737
35323
|
return setRelated({ related });
|
|
34738
35324
|
}), catchError(() => of(setRelated({ related: null })))));
|
|
34739
|
-
this.
|
|
34740
|
-
return
|
|
34741
|
-
}), catchError(() => of(
|
|
34742
|
-
this.loadSourceOf$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSourceOf(full)), map$1((sourceOf) => {
|
|
34743
|
-
return setSourceOf({ sourceOf });
|
|
34744
|
-
}), catchError(() => of(setSourceOf({ sourceOf: null })))));
|
|
35325
|
+
this.loadLinkedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getLinkedRecords(full)), map$1((linkedRecords) => {
|
|
35326
|
+
return setLinkedRecords({ linkedRecords });
|
|
35327
|
+
}), catchError(() => of(setLinkedRecords({ linkedRecords: null })))));
|
|
34745
35328
|
/*
|
|
34746
35329
|
UserFeedback effects
|
|
34747
35330
|
*/
|
|
@@ -37442,7 +38025,7 @@ class GenericKeywordsComponent {
|
|
|
37442
38025
|
this.deletedKeyword.emit(keyword);
|
|
37443
38026
|
}
|
|
37444
38027
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37445
|
-
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 }); }
|
|
38028
|
+
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 }); }
|
|
37446
38029
|
}
|
|
37447
38030
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, decorators: [{
|
|
37448
38031
|
type: Component,
|
|
@@ -38034,7 +38617,7 @@ class FormFieldContactsForResourceComponent {
|
|
|
38034
38617
|
provideNgIconsConfig({
|
|
38035
38618
|
size: '1.5rem',
|
|
38036
38619
|
}),
|
|
38037
|
-
], 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 \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 }); }
|
|
38620
|
+
], 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 \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 }); }
|
|
38038
38621
|
}
|
|
38039
38622
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsForResourceComponent, decorators: [{
|
|
38040
38623
|
type: Component,
|
|
@@ -38134,7 +38717,7 @@ class FormFieldContactsComponent {
|
|
|
38134
38717
|
this.subscription.unsubscribe();
|
|
38135
38718
|
}
|
|
38136
38719
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38137
|
-
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 }); }
|
|
38720
|
+
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 }); }
|
|
38138
38721
|
}
|
|
38139
38722
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, decorators: [{
|
|
38140
38723
|
type: Component,
|
|
@@ -38487,7 +39070,7 @@ class OnlineServiceResourceInputComponent {
|
|
|
38487
39070
|
provideNgIconsConfig({
|
|
38488
39071
|
size: '1.5em',
|
|
38489
39072
|
}),
|
|
38490
|
-
], 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 }); }
|
|
39073
|
+
], 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 }); }
|
|
38491
39074
|
}
|
|
38492
39075
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: OnlineServiceResourceInputComponent, decorators: [{
|
|
38493
39076
|
type: Component,
|
|
@@ -40020,7 +40603,7 @@ function flattenQueryParams(params) {
|
|
|
40020
40603
|
const start = flattened[key].start;
|
|
40021
40604
|
const end = flattened[key].end;
|
|
40022
40605
|
flattened[key] = [
|
|
40023
|
-
`${start ? formatDate(start) : ''}..${formatDate(end)
|
|
40606
|
+
`${start ? formatDate(start) : ''}..${end ? formatDate(end) : ''}`,
|
|
40024
40607
|
];
|
|
40025
40608
|
}
|
|
40026
40609
|
}
|
|
@@ -40377,5 +40960,5 @@ const CHART_TYPE_VALUES = [
|
|
|
40377
40960
|
* Generated bundle index. Do not edit.
|
|
40378
40961
|
*/
|
|
40379
40962
|
|
|
40380
|
-
export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, 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_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, 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, isConfigLoaded, isDateRange, 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, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, 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 };
|
|
40963
|
+
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_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, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceCreationRevisionDateSearchField, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, defaultMapStyleFixture, defaultMapStyleHlFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, 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 };
|
|
40381
40964
|
//# sourceMappingURL=geonetwork-ui.mjs.map
|