geonetwork-ui 2.11.0-dev.8442dae6e → 2.11.0-dev.9ba9c4d3d
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 +1333 -691
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +228 -81
- 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/metadata-converter/src/lib/gn4/types/elasticsearch.model.ts +13 -1
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +70 -10
- 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 +22 -0
- package/src/libs/common/domain/src/lib/model/search/filter.model.ts +13 -1
- package/src/libs/common/domain/src/lib/model/search/sort-by.model.ts +1 -5
- 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/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.html +33 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.ts +94 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.html +16 -12
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +6 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +6 -0
- package/src/libs/feature/editor/src/lib/fields.config.ts +5 -0
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +1 -0
- 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/router.service.ts +1 -1
- package/src/libs/feature/router/src/lib/default/state/query-params.utils.ts +1 -1
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +9 -4
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +46 -19
- package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +17 -8
- package/src/libs/feature/search/src/lib/sort-by/sort-by.component.ts +1 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +3 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +27 -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/inputs/src/index.ts +2 -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 +1 -1
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.css +0 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +117 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +191 -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 +3 -0
- package/src/libs/util/app-config/src/lib/model.ts +1 -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/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 +8 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/tailwind.base.css +5 -0
- package/translations/de.json +26 -3
- package/translations/en.json +25 -2
- package/translations/es.json +23 -0
- package/translations/fr.json +26 -3
- package/translations/it.json +24 -1
- package/translations/nl.json +23 -0
- package/translations/pt.json +23 -0
- package/translations/sk.json +24 -1
- package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +0 -14
|
@@ -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, takeUntil, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1 } 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';
|
|
@@ -41,10 +41,10 @@ import * as TOML from '@ltd/j-toml';
|
|
|
41
41
|
import { Style, Stroke, Fill, Circle } from 'ol/style.js';
|
|
42
42
|
import CircleStyle from 'ol/style/Circle.js';
|
|
43
43
|
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,
|
|
44
|
+
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirTrash, iconoirSquareDashed, iconoirImport, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
|
|
45
45
|
import { MatButtonModule } from '@angular/material/button';
|
|
46
|
-
import * as i1$
|
|
47
|
-
import {
|
|
46
|
+
import * as i1$7 from '@angular/cdk/overlay';
|
|
47
|
+
import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
48
48
|
import * as i1$3 from '@angular/forms';
|
|
49
49
|
import { UntypedFormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
50
50
|
import * as i1$2 from '@angular/material/autocomplete';
|
|
@@ -52,16 +52,18 @@ import { MatAutocompleteModule, MatAutocompleteTrigger, MatAutocomplete } from '
|
|
|
52
52
|
import tippy from 'tippy.js';
|
|
53
53
|
import * as i2 from '@angular/material/progress-spinner';
|
|
54
54
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
55
|
-
import { matClose, matContentCopy,
|
|
55
|
+
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
56
|
import * as i1$4 from '@angular/material/checkbox';
|
|
57
57
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
58
58
|
import * as i1$5 from '@angular/material/tooltip';
|
|
59
59
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
60
|
-
import {
|
|
60
|
+
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
|
|
61
|
+
import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
|
62
|
+
import { enUS } from 'date-fns/locale/en-US';
|
|
61
63
|
import * as i1$6 from '@angular/material/datepicker';
|
|
62
64
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
63
|
-
import * as i1$
|
|
64
|
-
import { NgxDropzoneModule } from 'ngx-dropzone';
|
|
65
|
+
import * as i1$8 from 'ngx-dropzone';
|
|
66
|
+
import { NgxDropzoneModule, NgxDropzoneComponent } from 'ngx-dropzone';
|
|
65
67
|
import * as i1$9 from '@angular/material/button-toggle';
|
|
66
68
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
67
69
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -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';
|
|
@@ -788,6 +789,15 @@ marker('record.metadata.api.accessServiceProtocol.maplibre-style');
|
|
|
788
789
|
marker('record.metadata.api.accessServiceProtocol.postgis');
|
|
789
790
|
marker('record.metadata.api.accessServiceProtocol.stac');
|
|
790
791
|
marker('record.metadata.api.accessServiceProtocol.other');
|
|
792
|
+
marker('domain.record.associationType.crossReference');
|
|
793
|
+
marker('domain.record.associationType.largerWorkCitation');
|
|
794
|
+
marker('domain.record.associationType.partOfSeamlessDatabase');
|
|
795
|
+
marker('domain.record.associationType.stereoMate');
|
|
796
|
+
marker('domain.record.associationType.isComposedOf');
|
|
797
|
+
marker('domain.record.associationType.collectiveTitle');
|
|
798
|
+
marker('domain.record.associationType.series');
|
|
799
|
+
marker('domain.record.associationType.dependency');
|
|
800
|
+
marker('domain.record.associationType.revisionOf');
|
|
791
801
|
// DS_AssociationTypeCode values of the ISO19115-3 codelist, any unrecognized value
|
|
792
802
|
// being mapped to 'crossReference'
|
|
793
803
|
const associationTypeValues = [
|
|
@@ -18898,14 +18908,29 @@ class Gn4FieldMapper {
|
|
|
18898
18908
|
featureTypes: selectField(source, 'featureTypes'),
|
|
18899
18909
|
}, output),
|
|
18900
18910
|
related: (output, source) => {
|
|
18901
|
-
const
|
|
18911
|
+
const related = selectField(source, 'related');
|
|
18912
|
+
const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
|
|
18902
18913
|
const featureCatalogIdentifier = selectField(fcatSource, 'uuid');
|
|
18903
|
-
const sourceOfLinks = getAsArray(selectField(
|
|
18914
|
+
const sourceOfLinks = getAsArray(selectField(related, 'hassources'));
|
|
18904
18915
|
const sourceOfIdentifiers = sourceOfLinks
|
|
18905
18916
|
.filter((link) => link['origin'] === 'catalog')
|
|
18906
18917
|
.map((link) => {
|
|
18907
18918
|
return selectField(selectField(link, '_source'), 'uuid');
|
|
18908
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));
|
|
18909
18934
|
const extraValues = {};
|
|
18910
18935
|
if (featureCatalogIdentifier) {
|
|
18911
18936
|
extraValues.featureCatalogIdentifier = featureCatalogIdentifier;
|
|
@@ -18913,6 +18938,12 @@ class Gn4FieldMapper {
|
|
|
18913
18938
|
if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
|
|
18914
18939
|
extraValues.sourceOfIdentifiers = sourceOfIdentifiers;
|
|
18915
18940
|
}
|
|
18941
|
+
if (associatedIdentifiers && associatedIdentifiers.length > 0) {
|
|
18942
|
+
extraValues.associatedIdentifiers = associatedIdentifiers;
|
|
18943
|
+
}
|
|
18944
|
+
if (siblings && siblings.length > 0) {
|
|
18945
|
+
extraValues.siblings = siblings;
|
|
18946
|
+
}
|
|
18916
18947
|
return Object.keys(extraValues).length > 0
|
|
18917
18948
|
? this.addExtra(extraValues, output)
|
|
18918
18949
|
: output;
|
|
@@ -19438,10 +19469,10 @@ class DateService {
|
|
|
19438
19469
|
const dateObj = this.getDateObject(date);
|
|
19439
19470
|
return { locale, dateObj };
|
|
19440
19471
|
}
|
|
19441
|
-
async
|
|
19472
|
+
async getDateFnsLocale() {
|
|
19442
19473
|
const lang = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE;
|
|
19443
19474
|
const locales = await this.dateLocales;
|
|
19444
|
-
return locales[lang];
|
|
19475
|
+
return locales[lang] ?? locales[DEFAULT_LANGUAGE];
|
|
19445
19476
|
}
|
|
19446
19477
|
formatDate(date, options) {
|
|
19447
19478
|
const { locale, dateObj } = this.getLocaleAndDate(date);
|
|
@@ -19454,7 +19485,7 @@ class DateService {
|
|
|
19454
19485
|
async formatRelativeDateTime(date) {
|
|
19455
19486
|
const dateObj = this.getDateObject(date);
|
|
19456
19487
|
const now = new Date();
|
|
19457
|
-
const locale = await this.
|
|
19488
|
+
const locale = await this.getDateFnsLocale();
|
|
19458
19489
|
return formatDistance(dateObj, now, {
|
|
19459
19490
|
addSuffix: true,
|
|
19460
19491
|
locale: locale,
|
|
@@ -19489,6 +19520,18 @@ function propagateToDocumentOnly(event) {
|
|
|
19489
19520
|
}, 0);
|
|
19490
19521
|
}
|
|
19491
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
|
+
|
|
19492
19535
|
function formatUserInfo(userInfo, displayCount = false) {
|
|
19493
19536
|
const infos = (typeof userInfo === 'string' ? userInfo : '').split('|');
|
|
19494
19537
|
const count = displayCount ? ` ${infos[3].split(' ')[1]}` : '';
|
|
@@ -19548,6 +19591,11 @@ function getGeometryFromGeoJSON(data) {
|
|
|
19548
19591
|
}
|
|
19549
19592
|
return null;
|
|
19550
19593
|
}
|
|
19594
|
+
function isBoundingBox(value) {
|
|
19595
|
+
return (Array.isArray(value) &&
|
|
19596
|
+
value.length === 4 &&
|
|
19597
|
+
value.every((item) => typeof item === 'number'));
|
|
19598
|
+
}
|
|
19551
19599
|
function getGeometryBoundingBox(geometry) {
|
|
19552
19600
|
// use the bounding box if specified in the GeoJSON object
|
|
19553
19601
|
if (geometry.bbox) {
|
|
@@ -20333,6 +20381,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20333
20381
|
}]
|
|
20334
20382
|
}] });
|
|
20335
20383
|
|
|
20384
|
+
class AutofocusDirective {
|
|
20385
|
+
constructor() {
|
|
20386
|
+
this.el = inject(ElementRef);
|
|
20387
|
+
this.injector = inject(Injector);
|
|
20388
|
+
}
|
|
20389
|
+
set autofocus(active) {
|
|
20390
|
+
if (!active)
|
|
20391
|
+
return;
|
|
20392
|
+
afterNextRender(() => this.el.nativeElement.focus(), {
|
|
20393
|
+
injector: this.injector,
|
|
20394
|
+
});
|
|
20395
|
+
}
|
|
20396
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
20397
|
+
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 }); }
|
|
20398
|
+
}
|
|
20399
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, decorators: [{
|
|
20400
|
+
type: Directive,
|
|
20401
|
+
args: [{
|
|
20402
|
+
selector: '[gnUiAutofocus]',
|
|
20403
|
+
standalone: true,
|
|
20404
|
+
}]
|
|
20405
|
+
}], propDecorators: { autofocus: [{
|
|
20406
|
+
type: Input,
|
|
20407
|
+
args: [{ alias: 'gnUiAutofocus', transform: booleanAttribute }]
|
|
20408
|
+
}] } });
|
|
20409
|
+
|
|
20336
20410
|
class ImageFallbackDirective {
|
|
20337
20411
|
constructor() {
|
|
20338
20412
|
this.el = inject(ElementRef);
|
|
@@ -20360,7 +20434,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20360
20434
|
}] } });
|
|
20361
20435
|
|
|
20362
20436
|
var name = "geonetwork-ui";
|
|
20363
|
-
var version = "2.11.0-dev.
|
|
20437
|
+
var version = "2.11.0-dev.9ba9c4d3d";
|
|
20364
20438
|
var engines = {
|
|
20365
20439
|
node: ">=24"
|
|
20366
20440
|
};
|
|
@@ -20381,6 +20455,7 @@ var peerDependencies = {
|
|
|
20381
20455
|
"@angular/core": "19.x || 20.x || 21.x",
|
|
20382
20456
|
"@angular/forms": "19.x || 20.x || 21.x",
|
|
20383
20457
|
"@angular/material": "19.x || 20.x || 21.x",
|
|
20458
|
+
"@angular/material-date-fns-adapter": "19.x || 20.x",
|
|
20384
20459
|
"@angular/platform-browser": "19.x || 20.x || 21.x",
|
|
20385
20460
|
"@angular/platform-browser-dynamic": "19.x || 20.x || 21.x",
|
|
20386
20461
|
"@angular/router": "19.x || 20.x || 21.x",
|
|
@@ -20390,20 +20465,21 @@ var peerDependencies = {
|
|
|
20390
20465
|
"@ngrx/store": "19.x || 20.x || 21.x",
|
|
20391
20466
|
"@ngrx/store-devtools": "19.x || 20.x || 21.x",
|
|
20392
20467
|
"@ngrx/operators": "19.x || 20.x || 21.x",
|
|
20393
|
-
"@ngx-translate/core": "
|
|
20394
|
-
"@ngx-translate/http-loader": "
|
|
20395
|
-
"flag-icons": "
|
|
20468
|
+
"@ngx-translate/core": "17.x",
|
|
20469
|
+
"@ngx-translate/http-loader": "17.x",
|
|
20470
|
+
"flag-icons": "~7.5.0",
|
|
20396
20471
|
rxjs: "7.x",
|
|
20397
20472
|
"zone.js": "*",
|
|
20398
20473
|
tailwindcss: "3.x"
|
|
20399
20474
|
};
|
|
20400
20475
|
var dependencies = {
|
|
20401
20476
|
"@biesbjerg/ngx-translate-extract-marker": "~1.0.0",
|
|
20402
|
-
"@camptocamp/ogc-client": "1.3.1-dev.
|
|
20403
|
-
"@
|
|
20404
|
-
"@geospatial-sdk/
|
|
20405
|
-
"@geospatial-sdk/
|
|
20406
|
-
"@geospatial-sdk/
|
|
20477
|
+
"@camptocamp/ogc-client": "1.3.1-dev.200c02a",
|
|
20478
|
+
"@duckdb/duckdb-wasm": "~1.32.0",
|
|
20479
|
+
"@geospatial-sdk/core": "0.0.5-dev.78",
|
|
20480
|
+
"@geospatial-sdk/geocoding": "0.0.5-dev.78",
|
|
20481
|
+
"@geospatial-sdk/legend": "0.0.5-dev.78",
|
|
20482
|
+
"@geospatial-sdk/openlayers": "0.0.5-dev.78",
|
|
20407
20483
|
"@ltd/j-toml": "~1.38.0",
|
|
20408
20484
|
"@messageformat/core": "~3.4.0",
|
|
20409
20485
|
"@ng-icons/core": "~32.5.0",
|
|
@@ -20411,7 +20487,7 @@ var dependencies = {
|
|
|
20411
20487
|
"@ng-icons/material-icons": "~32.5.0",
|
|
20412
20488
|
"@ng-icons/tabler-icons": "~32.4.0",
|
|
20413
20489
|
"@rgrove/parse-xml": "4.2.0",
|
|
20414
|
-
|
|
20490
|
+
"apache-arrow": "~17.0.0",
|
|
20415
20491
|
"chart.js": "~4.5.1",
|
|
20416
20492
|
"chroma-js": "~3.2.0",
|
|
20417
20493
|
"date-fns": "4.1.0",
|
|
@@ -20424,7 +20500,6 @@ var dependencies = {
|
|
|
20424
20500
|
"ngx-dropzone": "~3.1.0",
|
|
20425
20501
|
"ngx-translate-messageformat-compiler": "~7.2.0",
|
|
20426
20502
|
ol: "~10.8.0",
|
|
20427
|
-
papaparse: "~5.5.3",
|
|
20428
20503
|
proj4: "~2.20.4",
|
|
20429
20504
|
rdflib: "~2.3.5",
|
|
20430
20505
|
semver: "~7.7.4",
|
|
@@ -20669,6 +20744,7 @@ class ElasticsearchService {
|
|
|
20669
20744
|
values: uuids,
|
|
20670
20745
|
},
|
|
20671
20746
|
},
|
|
20747
|
+
size: uuids.length,
|
|
20672
20748
|
};
|
|
20673
20749
|
}
|
|
20674
20750
|
getRelatedRecordPayload(record, size = 6, _source = [...ES_SOURCE_SUMMARY, 'createDate']) {
|
|
@@ -20719,10 +20795,28 @@ class ElasticsearchService {
|
|
|
20719
20795
|
};
|
|
20720
20796
|
}
|
|
20721
20797
|
buildPayloadSort(sortBy) {
|
|
20722
|
-
if (sortBy ===
|
|
20798
|
+
if (!sortBy || sortBy.length === 0)
|
|
20723
20799
|
return undefined;
|
|
20724
|
-
const fields = Array.isArray(sortBy[0])
|
|
20725
|
-
|
|
20800
|
+
const fields = Array.isArray(sortBy[0])
|
|
20801
|
+
? sortBy
|
|
20802
|
+
: [sortBy];
|
|
20803
|
+
return fields.map((field) => {
|
|
20804
|
+
// Sort by nested array of dates only works with the explicit syntax
|
|
20805
|
+
if (field[1].endsWith('.date')) {
|
|
20806
|
+
const nestedPath = field[1].slice(0, field[1].lastIndexOf('.date'));
|
|
20807
|
+
return {
|
|
20808
|
+
[field[1]]: {
|
|
20809
|
+
order: field[0],
|
|
20810
|
+
mode: field[0] === 'desc' ? 'max' : 'min',
|
|
20811
|
+
missing: '_last',
|
|
20812
|
+
nested: {
|
|
20813
|
+
path: nestedPath,
|
|
20814
|
+
},
|
|
20815
|
+
},
|
|
20816
|
+
};
|
|
20817
|
+
}
|
|
20818
|
+
return { [field[1]]: field[0] };
|
|
20819
|
+
});
|
|
20726
20820
|
}
|
|
20727
20821
|
injectLangInQueryStringFields(queryFieldsPriority) {
|
|
20728
20822
|
const queryLang = this.getQueryLang();
|
|
@@ -20758,7 +20852,13 @@ class ElasticsearchService {
|
|
|
20758
20852
|
isCurrentSearchLang() {
|
|
20759
20853
|
return this.metadataLang === 'current';
|
|
20760
20854
|
}
|
|
20761
|
-
|
|
20855
|
+
findSpatialFilterExtent(filters) {
|
|
20856
|
+
if (typeof filters === 'string') {
|
|
20857
|
+
return undefined;
|
|
20858
|
+
}
|
|
20859
|
+
return Object.values(filters).find(isBoundingBox);
|
|
20860
|
+
}
|
|
20861
|
+
filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
|
|
20762
20862
|
const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
|
|
20763
20863
|
const makeQuery = (filter) => {
|
|
20764
20864
|
if (typeof filter === 'string') {
|
|
@@ -20777,7 +20877,9 @@ class ElasticsearchService {
|
|
|
20777
20877
|
? filters
|
|
20778
20878
|
: Object.keys(filters)
|
|
20779
20879
|
.filter((fieldname) => fieldname !== 'gn-ui-crossFieldFilter')
|
|
20880
|
+
.filter((fieldname) => !isBoundingBox(filters[fieldname]))
|
|
20780
20881
|
.filter((fieldname) => !isDateRange(filters[fieldname]))
|
|
20882
|
+
.filter((fieldname) => !Array.isArray(filters[fieldname]))
|
|
20781
20883
|
.filter((fieldname) => filters[fieldname] &&
|
|
20782
20884
|
JSON.stringify(filters[fieldname]) !== '{}')
|
|
20783
20885
|
.map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
|
|
@@ -20813,6 +20915,21 @@ class ElasticsearchService {
|
|
|
20813
20915
|
},
|
|
20814
20916
|
},
|
|
20815
20917
|
},
|
|
20918
|
+
spatialFilterExtent && {
|
|
20919
|
+
geo_shape: {
|
|
20920
|
+
geom: {
|
|
20921
|
+
shape: {
|
|
20922
|
+
type: 'envelope',
|
|
20923
|
+
// spatialFilterExtent is [minX, minY, maxX, maxY]; envelope coordinates are [top-left, bottom-right]
|
|
20924
|
+
coordinates: [
|
|
20925
|
+
[spatialFilterExtent[0], spatialFilterExtent[3]],
|
|
20926
|
+
[spatialFilterExtent[2], spatialFilterExtent[1]],
|
|
20927
|
+
],
|
|
20928
|
+
},
|
|
20929
|
+
relation: 'intersects',
|
|
20930
|
+
},
|
|
20931
|
+
},
|
|
20932
|
+
},
|
|
20816
20933
|
].filter(Boolean);
|
|
20817
20934
|
return queryParts.length > 0 ? queryParts : undefined;
|
|
20818
20935
|
}
|
|
@@ -20839,7 +20956,9 @@ class ElasticsearchService {
|
|
|
20839
20956
|
},
|
|
20840
20957
|
});
|
|
20841
20958
|
}
|
|
20842
|
-
|
|
20959
|
+
// a spatial extent filter takes precedence over the preference geometry for boosting
|
|
20960
|
+
const spatialFilterExtent = this.findSpatialFilterExtent(fieldSearchFilters);
|
|
20961
|
+
const queryFilters = this.filtersToQuery(fieldSearchFilters, spatialFilterExtent);
|
|
20843
20962
|
if (queryFilters) {
|
|
20844
20963
|
filter.push(...queryFilters);
|
|
20845
20964
|
}
|
|
@@ -20850,7 +20969,10 @@ class ElasticsearchService {
|
|
|
20850
20969
|
},
|
|
20851
20970
|
});
|
|
20852
20971
|
}
|
|
20853
|
-
|
|
20972
|
+
const boostGeometry = spatialFilterExtent
|
|
20973
|
+
? bboxToPolygon(spatialFilterExtent)
|
|
20974
|
+
: geometry;
|
|
20975
|
+
if (boostGeometry) {
|
|
20854
20976
|
// boosts applied using the filter geometry:
|
|
20855
20977
|
// * records completely within the geometry receive a boost of 5
|
|
20856
20978
|
// * records intersecting the geometry receive a boost of 2
|
|
@@ -20859,7 +20981,7 @@ class ElasticsearchService {
|
|
|
20859
20981
|
should.push({
|
|
20860
20982
|
geo_shape: {
|
|
20861
20983
|
geom: {
|
|
20862
|
-
shape:
|
|
20984
|
+
shape: boostGeometry,
|
|
20863
20985
|
relation: 'within',
|
|
20864
20986
|
},
|
|
20865
20987
|
boost: 5.0,
|
|
@@ -20867,7 +20989,7 @@ class ElasticsearchService {
|
|
|
20867
20989
|
}, {
|
|
20868
20990
|
geo_shape: {
|
|
20869
20991
|
geom: {
|
|
20870
|
-
shape:
|
|
20992
|
+
shape: boostGeometry,
|
|
20871
20993
|
relation: 'intersects',
|
|
20872
20994
|
},
|
|
20873
20995
|
boost: 2.0,
|
|
@@ -20876,7 +20998,7 @@ class ElasticsearchService {
|
|
|
20876
20998
|
// this will boost the results variably depending on their distance from the given geometry
|
|
20877
20999
|
// note: this takes into account the `location` field of a record; this is generally the center of all spatial extents
|
|
20878
21000
|
// combined, and thus the actual size/coverage of the record spatial extent isn't relevant here
|
|
20879
|
-
const bbox = getGeometryBoundingBox(
|
|
21001
|
+
const bbox = getGeometryBoundingBox(boostGeometry);
|
|
20880
21002
|
const center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
|
20881
21003
|
const northToCenter = new LineString([
|
|
20882
21004
|
[center[0], bbox[3]],
|
|
@@ -21202,7 +21324,7 @@ class Gn4Repository {
|
|
|
21202
21324
|
}
|
|
21203
21325
|
getRecord(uniqueIdentifier) {
|
|
21204
21326
|
return this.gn4SearchApi
|
|
21205
|
-
.search('bucket', ['fcats', 'hassources'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21327
|
+
.search('bucket', ['fcats', 'hassources', 'siblings', 'associated'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21206
21328
|
.pipe(map$1((results) => results.hits.hits[0]), switchMap((record) => record ? this.gn4Mapper.readRecord(record) : of(null)));
|
|
21207
21329
|
}
|
|
21208
21330
|
getMultipleRecords(uniqueIdentifiers) {
|
|
@@ -21256,19 +21378,28 @@ class Gn4Repository {
|
|
|
21256
21378
|
.search('bucket', null, JSON.stringify(this.gn4SearchHelper.getRelatedRecordPayload(similarTo, 3)))
|
|
21257
21379
|
.pipe(switchMap((results) => this.gn4Mapper.readRecords(results.hits.hits)));
|
|
21258
21380
|
}
|
|
21259
|
-
|
|
21260
|
-
const
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21381
|
+
getLinkedRecords(record) {
|
|
21382
|
+
const siblings = (record.extras?.['siblings'] ?? []);
|
|
21383
|
+
const relations = [
|
|
21384
|
+
['source', (record.extras?.['sourcesIdentifiers'] ?? [])],
|
|
21385
|
+
['sourceOf', (record.extras?.['sourceOfIdentifiers'] ?? [])],
|
|
21386
|
+
['sibling', siblings.map(({ uniqueIdentifier }) => uniqueIdentifier)],
|
|
21387
|
+
[
|
|
21388
|
+
'associated',
|
|
21389
|
+
(record.extras?.['associatedIdentifiers'] ?? []),
|
|
21390
|
+
],
|
|
21391
|
+
];
|
|
21392
|
+
const requested = relations.filter(([, identifiers]) => identifiers.length > 0);
|
|
21393
|
+
if (requested.length === 0) {
|
|
21394
|
+
return of([]);
|
|
21270
21395
|
}
|
|
21271
|
-
return
|
|
21396
|
+
return forkJoin(requested.map(([relation, identifiers]) => this.getMultipleRecords(identifiers).pipe(map$1((records) => (records ?? []).map((record) => ({
|
|
21397
|
+
record,
|
|
21398
|
+
relation,
|
|
21399
|
+
associationType: relation === 'sibling'
|
|
21400
|
+
? siblings.find(({ uniqueIdentifier }) => uniqueIdentifier === record.uniqueIdentifier)?.associationType
|
|
21401
|
+
: undefined,
|
|
21402
|
+
}))), catchError(() => of([]))))).pipe(map$1((groups) => groups.flat()));
|
|
21272
21403
|
}
|
|
21273
21404
|
aggregate(params) {
|
|
21274
21405
|
// if aggregations are empty, return an empty object right away
|
|
@@ -22529,9 +22660,10 @@ const VECTOR_STYLE_DEFAULT = new InjectionToken('vectorStyleDefault', {
|
|
|
22529
22660
|
});
|
|
22530
22661
|
|
|
22531
22662
|
const DEFAULT_BASEMAP_LAYER = {
|
|
22532
|
-
type: '
|
|
22533
|
-
|
|
22534
|
-
|
|
22663
|
+
type: 'maplibre-style',
|
|
22664
|
+
styleUrl: `https://basemaps.cartocdn.com/gl/positron-gl-style/style.json`,
|
|
22665
|
+
clickable: false,
|
|
22666
|
+
hoverable: false,
|
|
22535
22667
|
};
|
|
22536
22668
|
const DEFAULT_VIEW = {
|
|
22537
22669
|
center: [0, 15],
|
|
@@ -23246,6 +23378,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23246
23378
|
'search_preset',
|
|
23247
23379
|
'advanced_filters',
|
|
23248
23380
|
'limit',
|
|
23381
|
+
'spatial_extent_max_file_size',
|
|
23249
23382
|
], warnings, errors);
|
|
23250
23383
|
const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
|
|
23251
23384
|
searchConfig =
|
|
@@ -23263,6 +23396,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23263
23396
|
})),
|
|
23264
23397
|
ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
|
|
23265
23398
|
LIMIT: parsedSearchSection.limit,
|
|
23399
|
+
SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
|
|
23266
23400
|
};
|
|
23267
23401
|
const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
|
|
23268
23402
|
metadataQualityConfig =
|
|
@@ -24520,12 +24654,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24520
24654
|
type: Input
|
|
24521
24655
|
}] } });
|
|
24522
24656
|
|
|
24657
|
+
function provideLocalizedDateAdapter() {
|
|
24658
|
+
return [
|
|
24659
|
+
{ provide: MAT_DATE_LOCALE, useValue: enUS },
|
|
24660
|
+
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
|
|
24661
|
+
{
|
|
24662
|
+
provide: DateAdapter,
|
|
24663
|
+
useFactory: () => {
|
|
24664
|
+
const dateService = inject(DateService);
|
|
24665
|
+
const adapter = new DateFnsAdapter();
|
|
24666
|
+
dateService
|
|
24667
|
+
.getDateFnsLocale()
|
|
24668
|
+
.then((locale) => adapter.setLocale(locale));
|
|
24669
|
+
return adapter;
|
|
24670
|
+
},
|
|
24671
|
+
},
|
|
24672
|
+
];
|
|
24673
|
+
}
|
|
24674
|
+
|
|
24523
24675
|
class DatePickerComponent {
|
|
24524
24676
|
constructor() {
|
|
24525
|
-
this.dateAdapter = inject(DateAdapter);
|
|
24526
|
-
this.translate = inject(TranslateService);
|
|
24527
24677
|
this.dateChange = new EventEmitter();
|
|
24528
|
-
this.dateAdapter.setLocale(this.translate.getCurrentLang());
|
|
24529
24678
|
}
|
|
24530
24679
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24531
24680
|
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: [
|
|
@@ -24533,30 +24682,19 @@ class DatePickerComponent {
|
|
|
24533
24682
|
provideNgIconsConfig({
|
|
24534
24683
|
size: '1.5rem',
|
|
24535
24684
|
}),
|
|
24536
|
-
|
|
24537
|
-
|
|
24538
|
-
useFactory: (locale) => locale,
|
|
24539
|
-
},
|
|
24540
|
-
], 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 }); }
|
|
24685
|
+
provideLocalizedDateAdapter(),
|
|
24686
|
+
], 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 }); }
|
|
24541
24687
|
}
|
|
24542
24688
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
24543
24689
|
type: Component,
|
|
24544
|
-
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24545
|
-
MatNativeDateModule,
|
|
24546
|
-
MatDatepickerModule,
|
|
24547
|
-
ButtonComponent,
|
|
24548
|
-
NgIconComponent,
|
|
24549
|
-
], providers: [
|
|
24690
|
+
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24550
24691
|
provideIcons({ iconoirCalendar }),
|
|
24551
24692
|
provideNgIconsConfig({
|
|
24552
24693
|
size: '1.5rem',
|
|
24553
24694
|
}),
|
|
24554
|
-
|
|
24555
|
-
provide: MAT_DATE_LOCALE,
|
|
24556
|
-
useFactory: (locale) => locale,
|
|
24557
|
-
},
|
|
24695
|
+
provideLocalizedDateAdapter(),
|
|
24558
24696
|
], 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"] }]
|
|
24559
|
-
}],
|
|
24697
|
+
}], propDecorators: { date: [{
|
|
24560
24698
|
type: Input
|
|
24561
24699
|
}], dateChange: [{
|
|
24562
24700
|
type: Output
|
|
@@ -24564,58 +24702,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24564
24702
|
|
|
24565
24703
|
class DateRangeDropdownComponent {
|
|
24566
24704
|
constructor() {
|
|
24567
|
-
this.
|
|
24705
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
24706
|
+
this.dateAdapter = inject(DateAdapter);
|
|
24707
|
+
this.dateFormats = inject(MAT_DATE_FORMATS);
|
|
24568
24708
|
this.cdr = inject(ChangeDetectorRef);
|
|
24569
|
-
this.
|
|
24570
|
-
this.
|
|
24571
|
-
this.
|
|
24709
|
+
this.dateRange = {};
|
|
24710
|
+
this.dateRangeChange = new EventEmitter();
|
|
24711
|
+
this.overlayPositions = [
|
|
24712
|
+
{
|
|
24713
|
+
originX: 'start',
|
|
24714
|
+
originY: 'bottom',
|
|
24715
|
+
overlayX: 'start',
|
|
24716
|
+
overlayY: 'top',
|
|
24717
|
+
offsetY: 8,
|
|
24718
|
+
},
|
|
24719
|
+
{
|
|
24720
|
+
originX: 'start',
|
|
24721
|
+
originY: 'top',
|
|
24722
|
+
overlayX: 'start',
|
|
24723
|
+
overlayY: 'bottom',
|
|
24724
|
+
offsetY: -8,
|
|
24725
|
+
},
|
|
24726
|
+
];
|
|
24727
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
24728
|
+
this.overlayOpen = false;
|
|
24729
|
+
this.expandedBound = 'start';
|
|
24730
|
+
this.invalidBounds = { start: false, end: false };
|
|
24731
|
+
// redraw when the lazily loaded UI locale reaches the adapter
|
|
24732
|
+
this.dateAdapter.localeChanges
|
|
24733
|
+
.pipe(takeUntilDestroyed())
|
|
24734
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
24572
24735
|
}
|
|
24573
|
-
|
|
24574
|
-
this.
|
|
24736
|
+
get startDate() {
|
|
24737
|
+
return this.dateRange.start;
|
|
24575
24738
|
}
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24579
|
-
|
|
24580
|
-
|
|
24581
|
-
|
|
24582
|
-
|
|
24583
|
-
|
|
24739
|
+
get endDate() {
|
|
24740
|
+
return this.dateRange.end;
|
|
24741
|
+
}
|
|
24742
|
+
get selectedDatesCount() {
|
|
24743
|
+
return (this.startDate ? 1 : 0) + (this.endDate ? 1 : 0);
|
|
24744
|
+
}
|
|
24745
|
+
openOverlay() {
|
|
24746
|
+
this.expandedBound = 'start';
|
|
24747
|
+
this.overlayOpen = true;
|
|
24748
|
+
}
|
|
24749
|
+
closeOverlay() {
|
|
24750
|
+
this.overlayOpen = false;
|
|
24751
|
+
}
|
|
24752
|
+
toggleBound(bound) {
|
|
24753
|
+
this.expandedBound = this.expandedBound === bound ? null : bound;
|
|
24754
|
+
}
|
|
24755
|
+
formatDate(date) {
|
|
24756
|
+
return this.dateAdapter.format(date, this.dateFormats.display.dateInput);
|
|
24757
|
+
}
|
|
24758
|
+
onDateInput(bound, event) {
|
|
24759
|
+
const typedText = event.target.value.trim();
|
|
24760
|
+
const date = typedText
|
|
24761
|
+
? this.dateAdapter.parse(typedText, this.dateFormats.parse.dateInput)
|
|
24762
|
+
: null;
|
|
24763
|
+
if (!this.isAcceptable(bound, typedText, date)) {
|
|
24764
|
+
// keep the text as typed and flag it; the filter stays on its last value
|
|
24765
|
+
this.invalidBounds = { ...this.invalidBounds, [bound]: true };
|
|
24766
|
+
return;
|
|
24767
|
+
}
|
|
24768
|
+
if (bound === 'start')
|
|
24769
|
+
this.setStartDate(date);
|
|
24770
|
+
else
|
|
24771
|
+
this.setEndDate(date);
|
|
24772
|
+
}
|
|
24773
|
+
normalizeDateInput(bound, event) {
|
|
24774
|
+
if (this.invalidBounds[bound])
|
|
24775
|
+
return;
|
|
24776
|
+
const date = bound === 'start' ? this.startDate : this.endDate;
|
|
24777
|
+
const input = event.target;
|
|
24778
|
+
input.value = date ? this.formatDate(date) : '';
|
|
24779
|
+
}
|
|
24780
|
+
isAcceptable(bound, typedText, date) {
|
|
24781
|
+
if (!typedText)
|
|
24782
|
+
return true;
|
|
24783
|
+
if (!date || !this.dateAdapter.isValid(date))
|
|
24784
|
+
return false;
|
|
24785
|
+
return bound === 'start'
|
|
24786
|
+
? !this.endDate || date <= this.endDate
|
|
24787
|
+
: !this.startDate || date >= this.startDate;
|
|
24788
|
+
}
|
|
24789
|
+
setStartDate(date) {
|
|
24790
|
+
this.invalidBounds = { ...this.invalidBounds, start: false };
|
|
24791
|
+
this.applyDateRange({ ...this.dateRange, start: date });
|
|
24792
|
+
this.expandedBound = 'end';
|
|
24793
|
+
}
|
|
24794
|
+
setEndDate(date) {
|
|
24795
|
+
this.invalidBounds = { ...this.invalidBounds, end: false };
|
|
24796
|
+
this.applyDateRange({ ...this.dateRange, end: date });
|
|
24797
|
+
this.expandedBound = null;
|
|
24798
|
+
}
|
|
24799
|
+
clearDates(event) {
|
|
24800
|
+
this.invalidBounds = { start: false, end: false };
|
|
24801
|
+
this.expandedBound = 'start';
|
|
24802
|
+
this.applyDateRange({});
|
|
24803
|
+
propagateToDocumentOnly(event);
|
|
24804
|
+
}
|
|
24805
|
+
applyDateRange(dateRange) {
|
|
24806
|
+
this.dateRange = {
|
|
24807
|
+
...(dateRange.start && { start: dateRange.start }),
|
|
24808
|
+
...(dateRange.end && { end: dateRange.end }),
|
|
24809
|
+
};
|
|
24810
|
+
this.dateRangeChange.emit(this.dateRange);
|
|
24584
24811
|
}
|
|
24585
24812
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24586
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
24813
|
+
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: [
|
|
24587
24814
|
provideIcons({
|
|
24588
|
-
|
|
24815
|
+
iconoirCalendar,
|
|
24816
|
+
matClose,
|
|
24589
24817
|
matExpandLess,
|
|
24818
|
+
matExpandMore,
|
|
24590
24819
|
}),
|
|
24591
|
-
|
|
24820
|
+
provideNgIconsConfig({
|
|
24821
|
+
size: '1.5rem',
|
|
24822
|
+
}),
|
|
24823
|
+
provideLocalizedDateAdapter(),
|
|
24824
|
+
], 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 }); }
|
|
24592
24825
|
}
|
|
24593
24826
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, decorators: [{
|
|
24594
24827
|
type: Component,
|
|
24595
24828
|
args: [{ selector: 'gn-ui-date-range-dropdown', standalone: true, imports: [
|
|
24596
|
-
|
|
24597
|
-
MatNativeDateModule,
|
|
24598
|
-
MatDatepickerModule,
|
|
24829
|
+
AutofocusDirective,
|
|
24599
24830
|
ButtonComponent,
|
|
24831
|
+
MatDatepickerModule,
|
|
24832
|
+
NgIcon,
|
|
24833
|
+
NgTemplateOutlet,
|
|
24834
|
+
OverlayModule,
|
|
24835
|
+
TranslateDirective,
|
|
24836
|
+
TranslatePipe,
|
|
24600
24837
|
], providers: [
|
|
24601
24838
|
provideIcons({
|
|
24602
|
-
|
|
24839
|
+
iconoirCalendar,
|
|
24840
|
+
matClose,
|
|
24603
24841
|
matExpandLess,
|
|
24842
|
+
matExpandMore,
|
|
24604
24843
|
}),
|
|
24605
|
-
|
|
24606
|
-
|
|
24607
|
-
|
|
24608
|
-
|
|
24844
|
+
provideNgIconsConfig({
|
|
24845
|
+
size: '1.5rem',
|
|
24846
|
+
}),
|
|
24847
|
+
provideLocalizedDateAdapter(),
|
|
24848
|
+
], 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"] }]
|
|
24849
|
+
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
24609
24850
|
type: Input
|
|
24610
|
-
}],
|
|
24851
|
+
}], dateRange: [{
|
|
24611
24852
|
type: Input
|
|
24612
|
-
}],
|
|
24853
|
+
}], dateRangeChange: [{
|
|
24613
24854
|
type: Output
|
|
24614
|
-
}],
|
|
24615
|
-
type: Output
|
|
24616
|
-
}], picker: [{
|
|
24855
|
+
}], overlayOrigin: [{
|
|
24617
24856
|
type: ViewChild,
|
|
24618
|
-
args: ['
|
|
24857
|
+
args: ['overlayOrigin']
|
|
24619
24858
|
}] } });
|
|
24620
24859
|
|
|
24621
24860
|
class DateRangePickerComponent {
|
|
@@ -24629,20 +24868,17 @@ class DateRangePickerComponent {
|
|
|
24629
24868
|
provideNgIconsConfig({
|
|
24630
24869
|
size: '1.5rem',
|
|
24631
24870
|
}),
|
|
24632
|
-
|
|
24871
|
+
provideLocalizedDateAdapter(),
|
|
24872
|
+
], 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 }); }
|
|
24633
24873
|
}
|
|
24634
24874
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
24635
24875
|
type: Component,
|
|
24636
|
-
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24637
|
-
MatNativeDateModule,
|
|
24638
|
-
MatDatepickerModule,
|
|
24639
|
-
ButtonComponent,
|
|
24640
|
-
NgIconComponent,
|
|
24641
|
-
], providers: [
|
|
24876
|
+
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24642
24877
|
provideIcons({ iconoirCalendar }),
|
|
24643
24878
|
provideNgIconsConfig({
|
|
24644
24879
|
size: '1.5rem',
|
|
24645
24880
|
}),
|
|
24881
|
+
provideLocalizedDateAdapter(),
|
|
24646
24882
|
], 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"] }]
|
|
24647
24883
|
}], propDecorators: { startDate: [{
|
|
24648
24884
|
type: Input
|
|
@@ -24660,28 +24896,68 @@ class DragAndDropFileInputComponent {
|
|
|
24660
24896
|
constructor() {
|
|
24661
24897
|
this.placeholder = placeholder;
|
|
24662
24898
|
this.accept = '*';
|
|
24899
|
+
this.maxFileSizeMb = null;
|
|
24900
|
+
this.icon = null;
|
|
24901
|
+
this.dropzoneBackgroundColor = null;
|
|
24902
|
+
this.textClass = '';
|
|
24903
|
+
this.extraClass = '';
|
|
24904
|
+
this.showFileName = true;
|
|
24663
24905
|
this.fileChange = new EventEmitter();
|
|
24906
|
+
this.errorChange = new EventEmitter();
|
|
24664
24907
|
this.selectedFile = null;
|
|
24665
24908
|
}
|
|
24666
24909
|
get fileName() {
|
|
24667
24910
|
return this.selectedFile && this.selectedFile.name;
|
|
24668
24911
|
}
|
|
24912
|
+
get maxFileSizeBytes() {
|
|
24913
|
+
return typeof this.maxFileSizeMb === 'number'
|
|
24914
|
+
? megabytesToBytes(this.maxFileSizeMb)
|
|
24915
|
+
: null;
|
|
24916
|
+
}
|
|
24669
24917
|
selectFile(event) {
|
|
24918
|
+
if (event.rejectedFiles?.length) {
|
|
24919
|
+
const reason = event.rejectedFiles[0].reason;
|
|
24920
|
+
this.errorChange.emit(reason === 'size' ? 'file-too-large' : 'invalid-extension');
|
|
24921
|
+
return;
|
|
24922
|
+
}
|
|
24670
24923
|
this.selectedFile = event.addedFiles[0];
|
|
24671
24924
|
this.fileChange.emit(this.selectedFile);
|
|
24672
24925
|
}
|
|
24926
|
+
openFileSelector() {
|
|
24927
|
+
this.dropzone.showFileSelector();
|
|
24928
|
+
}
|
|
24929
|
+
clear() {
|
|
24930
|
+
this.selectedFile = null;
|
|
24931
|
+
}
|
|
24673
24932
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24674
|
-
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
|
|
24933
|
+
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"] }] }); }
|
|
24675
24934
|
}
|
|
24676
24935
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, decorators: [{
|
|
24677
24936
|
type: Component,
|
|
24678
|
-
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule], template: "<div
|
|
24937
|
+
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"] }]
|
|
24679
24938
|
}], propDecorators: { placeholder: [{
|
|
24680
24939
|
type: Input
|
|
24681
24940
|
}], accept: [{
|
|
24682
24941
|
type: Input
|
|
24942
|
+
}], maxFileSizeMb: [{
|
|
24943
|
+
type: Input
|
|
24944
|
+
}], icon: [{
|
|
24945
|
+
type: Input
|
|
24946
|
+
}], dropzoneBackgroundColor: [{
|
|
24947
|
+
type: Input
|
|
24948
|
+
}], textClass: [{
|
|
24949
|
+
type: Input
|
|
24950
|
+
}], extraClass: [{
|
|
24951
|
+
type: Input
|
|
24952
|
+
}], showFileName: [{
|
|
24953
|
+
type: Input
|
|
24683
24954
|
}], fileChange: [{
|
|
24684
24955
|
type: Output
|
|
24956
|
+
}], errorChange: [{
|
|
24957
|
+
type: Output
|
|
24958
|
+
}], dropzone: [{
|
|
24959
|
+
type: ViewChild,
|
|
24960
|
+
args: [NgxDropzoneComponent]
|
|
24685
24961
|
}] } });
|
|
24686
24962
|
|
|
24687
24963
|
class DropdownMultiselectComponent {
|
|
@@ -24836,7 +25112,7 @@ class DropdownMultiselectComponent {
|
|
|
24836
25112
|
matExpandMore,
|
|
24837
25113
|
matExpandLess,
|
|
24838
25114
|
}),
|
|
24839
|
-
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-
|
|
25115
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24840
25116
|
}
|
|
24841
25117
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
|
|
24842
25118
|
type: Component,
|
|
@@ -24846,7 +25122,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24846
25122
|
matExpandMore,
|
|
24847
25123
|
matExpandLess,
|
|
24848
25124
|
}),
|
|
24849
|
-
], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-
|
|
25125
|
+
], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
|
|
24850
25126
|
}], propDecorators: { title: [{
|
|
24851
25127
|
type: Input
|
|
24852
25128
|
}], choices: [{
|
|
@@ -25018,7 +25294,7 @@ class DropdownSelectorComponent {
|
|
|
25018
25294
|
provideNgIconsConfig({
|
|
25019
25295
|
size: '1.5em',
|
|
25020
25296
|
}),
|
|
25021
|
-
], 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$
|
|
25297
|
+
], 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 }); }
|
|
25022
25298
|
}
|
|
25023
25299
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownSelectorComponent, decorators: [{
|
|
25024
25300
|
type: Component,
|
|
@@ -25758,6 +26034,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
25758
26034
|
type: Output
|
|
25759
26035
|
}] } });
|
|
25760
26036
|
|
|
26037
|
+
marker('search.filters.spatialExtent.import');
|
|
26038
|
+
marker('search.filters.spatialExtent.helpText');
|
|
26039
|
+
marker('search.filters.spatialExtent.error.title');
|
|
26040
|
+
marker('search.filters.spatialExtent.bboxPrefix');
|
|
26041
|
+
marker('search.filters.spatialExtent.bboxDelete');
|
|
26042
|
+
class SpatialExtentDropdownComponent {
|
|
26043
|
+
constructor() {
|
|
26044
|
+
this.cd = inject(ChangeDetectorRef);
|
|
26045
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
26046
|
+
this.maxFileSizeMb = null;
|
|
26047
|
+
this.bboxChange = new EventEmitter();
|
|
26048
|
+
this.errorChange = new EventEmitter();
|
|
26049
|
+
this.bbox = null;
|
|
26050
|
+
this.fileName = '';
|
|
26051
|
+
this.overlayPositions = [
|
|
26052
|
+
{
|
|
26053
|
+
originX: 'start',
|
|
26054
|
+
originY: 'bottom',
|
|
26055
|
+
overlayX: 'start',
|
|
26056
|
+
overlayY: 'top',
|
|
26057
|
+
offsetY: 8,
|
|
26058
|
+
},
|
|
26059
|
+
{
|
|
26060
|
+
originX: 'start',
|
|
26061
|
+
originY: 'top',
|
|
26062
|
+
overlayX: 'start',
|
|
26063
|
+
overlayY: 'bottom',
|
|
26064
|
+
offsetY: -8,
|
|
26065
|
+
},
|
|
26066
|
+
];
|
|
26067
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
26068
|
+
this.overlayOpen = false;
|
|
26069
|
+
this.overlayMinWidth = 'none';
|
|
26070
|
+
this.errorKey = null;
|
|
26071
|
+
}
|
|
26072
|
+
get hasSelection() {
|
|
26073
|
+
return !!this.bbox;
|
|
26074
|
+
}
|
|
26075
|
+
openOverlay() {
|
|
26076
|
+
this.overlayMinWidth =
|
|
26077
|
+
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
|
|
26078
|
+
.width + 'px';
|
|
26079
|
+
this.overlayOpen = true;
|
|
26080
|
+
}
|
|
26081
|
+
closeOverlay() {
|
|
26082
|
+
this.overlayOpen = false;
|
|
26083
|
+
}
|
|
26084
|
+
toggleOverlay() {
|
|
26085
|
+
if (this.overlayOpen) {
|
|
26086
|
+
this.closeOverlay();
|
|
26087
|
+
}
|
|
26088
|
+
else {
|
|
26089
|
+
this.openOverlay();
|
|
26090
|
+
}
|
|
26091
|
+
}
|
|
26092
|
+
async handleFileSelected(file) {
|
|
26093
|
+
this.errorKey = null;
|
|
26094
|
+
let content;
|
|
26095
|
+
try {
|
|
26096
|
+
content = await readFileAsText(file);
|
|
26097
|
+
const parsed = JSON.parse(content);
|
|
26098
|
+
const geometry = getGeometryFromGeoJSON(parsed);
|
|
26099
|
+
if (!geometry) {
|
|
26100
|
+
this.setError(marker('search.filters.spatialExtent.error.noGeometry'));
|
|
26101
|
+
return;
|
|
26102
|
+
}
|
|
26103
|
+
const bbox = getGeometryBoundingBox(geometry);
|
|
26104
|
+
this.bbox = bbox;
|
|
26105
|
+
this.fileName = file.name;
|
|
26106
|
+
this.bboxChange.emit(bbox);
|
|
26107
|
+
this.cd.markForCheck();
|
|
26108
|
+
}
|
|
26109
|
+
catch {
|
|
26110
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26111
|
+
return;
|
|
26112
|
+
}
|
|
26113
|
+
}
|
|
26114
|
+
handleFileError(error) {
|
|
26115
|
+
if (error === 'file-too-large') {
|
|
26116
|
+
this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
|
|
26117
|
+
maxSize: this.maxFileSizeMb,
|
|
26118
|
+
});
|
|
26119
|
+
}
|
|
26120
|
+
else {
|
|
26121
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26122
|
+
}
|
|
26123
|
+
}
|
|
26124
|
+
setError(errorKey, params) {
|
|
26125
|
+
this.errorKey = errorKey;
|
|
26126
|
+
this.errorChange.emit({ key: errorKey, params });
|
|
26127
|
+
this.cd.markForCheck();
|
|
26128
|
+
}
|
|
26129
|
+
removeSelection(event) {
|
|
26130
|
+
this.bbox = null;
|
|
26131
|
+
this.fileName = '';
|
|
26132
|
+
this.errorKey = null;
|
|
26133
|
+
this.fileInput?.clear();
|
|
26134
|
+
this.bboxChange.emit(null);
|
|
26135
|
+
propagateToDocumentOnly(event);
|
|
26136
|
+
}
|
|
26137
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26138
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SpatialExtentDropdownComponent, isStandalone: true, selector: "gn-ui-spatial-extent-dropdown", inputs: { title: "title", maxFileSizeMb: "maxFileSizeMb" }, outputs: { bboxChange: "bboxChange", errorChange: "errorChange" }, providers: [
|
|
26139
|
+
provideIcons({
|
|
26140
|
+
iconoirCheckCircle,
|
|
26141
|
+
iconoirImport,
|
|
26142
|
+
iconoirSquareDashed,
|
|
26143
|
+
iconoirTrash,
|
|
26144
|
+
matClose,
|
|
26145
|
+
matExpandLess,
|
|
26146
|
+
matExpandMore,
|
|
26147
|
+
}),
|
|
26148
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
26149
|
+
}
|
|
26150
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
|
|
26151
|
+
type: Component,
|
|
26152
|
+
args: [{ selector: 'gn-ui-spatial-extent-dropdown', standalone: true, imports: [
|
|
26153
|
+
ButtonComponent,
|
|
26154
|
+
NgIcon,
|
|
26155
|
+
OverlayModule,
|
|
26156
|
+
TranslatePipe,
|
|
26157
|
+
DragAndDropFileInputComponent,
|
|
26158
|
+
], providers: [
|
|
26159
|
+
provideIcons({
|
|
26160
|
+
iconoirCheckCircle,
|
|
26161
|
+
iconoirImport,
|
|
26162
|
+
iconoirSquareDashed,
|
|
26163
|
+
iconoirTrash,
|
|
26164
|
+
matClose,
|
|
26165
|
+
matExpandLess,
|
|
26166
|
+
matExpandMore,
|
|
26167
|
+
}),
|
|
26168
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
|
|
26169
|
+
}], propDecorators: { title: [{
|
|
26170
|
+
type: Input
|
|
26171
|
+
}], maxFileSizeMb: [{
|
|
26172
|
+
type: Input
|
|
26173
|
+
}], bboxChange: [{
|
|
26174
|
+
type: Output
|
|
26175
|
+
}], errorChange: [{
|
|
26176
|
+
type: Output
|
|
26177
|
+
}], overlayOrigin: [{
|
|
26178
|
+
type: ViewChild,
|
|
26179
|
+
args: ['overlayOrigin']
|
|
26180
|
+
}], overlay: [{
|
|
26181
|
+
type: ViewChild,
|
|
26182
|
+
args: [CdkConnectedOverlay]
|
|
26183
|
+
}], fileInput: [{
|
|
26184
|
+
type: ViewChild,
|
|
26185
|
+
args: [DragAndDropFileInputComponent]
|
|
26186
|
+
}] } });
|
|
26187
|
+
|
|
25761
26188
|
class CellPopinComponent {
|
|
25762
26189
|
constructor() {
|
|
25763
26190
|
this.scrollDispatcher = inject(ScrollDispatcher);
|
|
@@ -25834,7 +26261,7 @@ class CellPopinComponent {
|
|
|
25834
26261
|
this.isOpen = false;
|
|
25835
26262
|
}
|
|
25836
26263
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25837
|
-
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$
|
|
26264
|
+
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"] }] }); }
|
|
25838
26265
|
}
|
|
25839
26266
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, decorators: [{
|
|
25840
26267
|
type: Component,
|
|
@@ -27924,6 +28351,23 @@ class DateRangeSearchField extends SimpleSearchField {
|
|
|
27924
28351
|
return 'dateRange';
|
|
27925
28352
|
}
|
|
27926
28353
|
}
|
|
28354
|
+
class BoundingBoxSearchField extends SimpleSearchField {
|
|
28355
|
+
getAvailableValues() {
|
|
28356
|
+
return of([]);
|
|
28357
|
+
}
|
|
28358
|
+
getFiltersForValues(values) {
|
|
28359
|
+
return of({
|
|
28360
|
+
[this.esFieldName]: values.map(Number),
|
|
28361
|
+
});
|
|
28362
|
+
}
|
|
28363
|
+
getValuesForFilter(filters) {
|
|
28364
|
+
const filter = filters[this.esFieldName];
|
|
28365
|
+
return of(isBoundingBox(filter) ? filter : []);
|
|
28366
|
+
}
|
|
28367
|
+
getType() {
|
|
28368
|
+
return 'spatialExtent';
|
|
28369
|
+
}
|
|
28370
|
+
}
|
|
27927
28371
|
marker('search.filters.availableServices.view');
|
|
27928
28372
|
marker('search.filters.availableServices.download');
|
|
27929
28373
|
class AvailableServicesField extends SimpleSearchField {
|
|
@@ -28068,6 +28512,7 @@ marker('search.filters.producerOrg');
|
|
|
28068
28512
|
marker('search.filters.publisherOrg');
|
|
28069
28513
|
marker('search.filters.user');
|
|
28070
28514
|
marker('search.filters.changeDate');
|
|
28515
|
+
marker('search.filters.spatialExtent');
|
|
28071
28516
|
class FieldsService {
|
|
28072
28517
|
constructor() {
|
|
28073
28518
|
this.injector = inject(Injector);
|
|
@@ -28091,6 +28536,7 @@ class FieldsService {
|
|
|
28091
28536
|
user: new UserSearchField(this.injector),
|
|
28092
28537
|
changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
|
|
28093
28538
|
availableServices: new AvailableServicesField(this.injector),
|
|
28539
|
+
spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
|
|
28094
28540
|
};
|
|
28095
28541
|
}
|
|
28096
28542
|
get supportedFields() {
|
|
@@ -29353,7 +29799,7 @@ class ContactPillComponent {
|
|
|
29353
29799
|
this.overlayOpen = false;
|
|
29354
29800
|
}
|
|
29355
29801
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29356
|
-
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$
|
|
29802
|
+
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 }); }
|
|
29357
29803
|
}
|
|
29358
29804
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, decorators: [{
|
|
29359
29805
|
type: Component,
|
|
@@ -31275,19 +31721,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31275
31721
|
type: Output
|
|
31276
31722
|
}] } });
|
|
31277
31723
|
|
|
31724
|
+
class NotificationsService {
|
|
31725
|
+
constructor() {
|
|
31726
|
+
this.notifications$ = new BehaviorSubject([]);
|
|
31727
|
+
}
|
|
31728
|
+
showNotification(content, timeoutMs, error) {
|
|
31729
|
+
error && console.error(error);
|
|
31730
|
+
const id = Math.floor(Math.random() * 1000000);
|
|
31731
|
+
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31732
|
+
if (typeof timeoutMs !== 'undefined') {
|
|
31733
|
+
setTimeout(() => {
|
|
31734
|
+
this.removeNotificationById(id);
|
|
31735
|
+
}, timeoutMs);
|
|
31736
|
+
}
|
|
31737
|
+
return id;
|
|
31738
|
+
}
|
|
31739
|
+
removeNotificationById(id) {
|
|
31740
|
+
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31741
|
+
}
|
|
31742
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31743
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31744
|
+
}
|
|
31745
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31746
|
+
type: Injectable,
|
|
31747
|
+
args: [{
|
|
31748
|
+
providedIn: 'root',
|
|
31749
|
+
}]
|
|
31750
|
+
}] });
|
|
31751
|
+
|
|
31752
|
+
class NotificationsContainerComponent {
|
|
31753
|
+
constructor() {
|
|
31754
|
+
this.notificationsService = inject(NotificationsService);
|
|
31755
|
+
}
|
|
31756
|
+
trackById(index, notification) {
|
|
31757
|
+
return notification.id;
|
|
31758
|
+
}
|
|
31759
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31760
|
+
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: [
|
|
31761
|
+
trigger('enterExit', [
|
|
31762
|
+
transition(':enter', [
|
|
31763
|
+
animate('150ms', keyframes([
|
|
31764
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31765
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31766
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31767
|
+
])),
|
|
31768
|
+
]),
|
|
31769
|
+
transition(':leave', [
|
|
31770
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31771
|
+
]),
|
|
31772
|
+
]),
|
|
31773
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31774
|
+
}
|
|
31775
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31776
|
+
type: Component,
|
|
31777
|
+
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31778
|
+
trigger('enterExit', [
|
|
31779
|
+
transition(':enter', [
|
|
31780
|
+
animate('150ms', keyframes([
|
|
31781
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31782
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31783
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31784
|
+
])),
|
|
31785
|
+
]),
|
|
31786
|
+
transition(':leave', [
|
|
31787
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31788
|
+
]),
|
|
31789
|
+
]),
|
|
31790
|
+
], 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" }]
|
|
31791
|
+
}] });
|
|
31792
|
+
|
|
31278
31793
|
class FilterDropdownComponent {
|
|
31279
31794
|
constructor() {
|
|
31280
31795
|
this.searchFacade = inject(SearchFacade);
|
|
31281
31796
|
this.searchService = inject(SearchService);
|
|
31282
31797
|
this.fieldsService = inject(FieldsService);
|
|
31798
|
+
this.notificationsService = inject(NotificationsService);
|
|
31799
|
+
this.translateService = inject(TranslateService);
|
|
31800
|
+
this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
|
|
31283
31801
|
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([])));
|
|
31284
|
-
this.selectedDateRange$ = this.selected$.pipe(map$1((
|
|
31802
|
+
this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
|
|
31803
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31285
31804
|
}
|
|
31286
31805
|
onSelectedValues(values) {
|
|
31287
31806
|
this.fieldsService
|
|
31288
31807
|
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
31289
31808
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31290
31809
|
}
|
|
31810
|
+
onBboxChange(bbox) {
|
|
31811
|
+
console.log(bbox);
|
|
31812
|
+
this.clearSpatialExtentErrorNotification();
|
|
31813
|
+
}
|
|
31814
|
+
onSpatialExtentError(error) {
|
|
31815
|
+
this.clearSpatialExtentErrorNotification();
|
|
31816
|
+
this.spatialExtentErrorNotificationId =
|
|
31817
|
+
this.notificationsService.showNotification({
|
|
31818
|
+
type: 'error',
|
|
31819
|
+
title: this.translateService.instant('search.filters.spatialExtent.error.title'),
|
|
31820
|
+
text: this.translateService.instant(error.key, error.params),
|
|
31821
|
+
});
|
|
31822
|
+
}
|
|
31823
|
+
clearSpatialExtentErrorNotification() {
|
|
31824
|
+
if (this.spatialExtentErrorNotificationId === null)
|
|
31825
|
+
return;
|
|
31826
|
+
this.notificationsService.removeNotificationById(this.spatialExtentErrorNotificationId);
|
|
31827
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31828
|
+
}
|
|
31291
31829
|
ngOnInit() {
|
|
31292
31830
|
this.fieldType = this.fieldsService.getFieldType(this.fieldName);
|
|
31293
31831
|
this.choices$ = this.fieldsService.getAvailableValues(this.fieldName).pipe(startWith$1([]), map$1((values) => values.map((v) => ({
|
|
@@ -31295,27 +31833,15 @@ class FilterDropdownComponent {
|
|
|
31295
31833
|
value: v.value.toString(), // converting to string for the dropdown
|
|
31296
31834
|
}))), catchError(() => of([])));
|
|
31297
31835
|
}
|
|
31298
|
-
|
|
31299
|
-
|
|
31300
|
-
|
|
31301
|
-
|
|
31302
|
-
|
|
31303
|
-
|
|
31304
|
-
if (!end)
|
|
31305
|
-
return;
|
|
31306
|
-
this.dateRange = { ...this.dateRange, end };
|
|
31307
|
-
if (this.dateRange.start && this.dateRange.end) {
|
|
31308
|
-
this.fieldsService
|
|
31309
|
-
.buildFiltersFromFieldValues({
|
|
31310
|
-
[this.fieldName]: this.dateRange,
|
|
31311
|
-
})
|
|
31312
|
-
.subscribe((filters) => {
|
|
31313
|
-
return this.searchService.updateFilters(filters);
|
|
31314
|
-
});
|
|
31315
|
-
}
|
|
31836
|
+
onDateRangeChange(dateRange) {
|
|
31837
|
+
this.fieldsService
|
|
31838
|
+
.buildFiltersFromFieldValues({
|
|
31839
|
+
[this.fieldName]: dateRange,
|
|
31840
|
+
})
|
|
31841
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31316
31842
|
}
|
|
31317
31843
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31318
|
-
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 [
|
|
31844
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FilterDropdownComponent, isStandalone: true, selector: "gn-ui-filter-dropdown", inputs: { fieldName: "fieldName", title: "title" }, ngImport: i0, template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DateRangeDropdownComponent, selector: "gn-ui-date-range-dropdown", inputs: ["title", "dateRange"], outputs: ["dateRangeChange"] }, { kind: "component", type: DropdownMultiselectComponent, selector: "gn-ui-dropdown-multiselect", inputs: ["title", "choices", "selected", "allowSearch", "maxRows", "searchInputValue"], outputs: ["selectValues"] }, { kind: "component", type: SpatialExtentDropdownComponent, selector: "gn-ui-spatial-extent-dropdown", inputs: ["title", "maxFileSizeMb"], outputs: ["bboxChange", "errorChange"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31319
31845
|
}
|
|
31320
31846
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
|
|
31321
31847
|
type: Component,
|
|
@@ -31323,7 +31849,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31323
31849
|
CommonModule,
|
|
31324
31850
|
DateRangeDropdownComponent,
|
|
31325
31851
|
DropdownMultiselectComponent,
|
|
31326
|
-
|
|
31852
|
+
SpatialExtentDropdownComponent,
|
|
31853
|
+
], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n" }]
|
|
31327
31854
|
}], propDecorators: { fieldName: [{
|
|
31328
31855
|
type: Input
|
|
31329
31856
|
}], title: [{
|
|
@@ -31793,11 +32320,7 @@ const SortByEnum = {
|
|
|
31793
32320
|
RELEVANCY: ['desc', '_score'],
|
|
31794
32321
|
QUALITY_SCORE: ['desc', 'qualityScore'],
|
|
31795
32322
|
CHANGE_DATE: ['desc', 'changeDate'],
|
|
31796
|
-
|
|
31797
|
-
['desc', 'revisionDateForResource'],
|
|
31798
|
-
['desc', 'publicationDateForResource'],
|
|
31799
|
-
['desc', 'creationDateForResource'],
|
|
31800
|
-
],
|
|
32323
|
+
RESOURCE_DATE: ['desc', 'resourceDate.date'],
|
|
31801
32324
|
};
|
|
31802
32325
|
|
|
31803
32326
|
class SortByComponent {
|
|
@@ -31811,7 +32334,7 @@ class SortByComponent {
|
|
|
31811
32334
|
},
|
|
31812
32335
|
{
|
|
31813
32336
|
label: marker('results.sortBy.dateStamp'),
|
|
31814
|
-
value: SortByEnum.
|
|
32337
|
+
value: SortByEnum.RESOURCE_DATE,
|
|
31815
32338
|
},
|
|
31816
32339
|
{
|
|
31817
32340
|
label: marker('results.sortBy.popularity'),
|
|
@@ -31863,74 +32386,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31863
32386
|
args: ['gnUiSearchStateContainer']
|
|
31864
32387
|
}] } });
|
|
31865
32388
|
|
|
31866
|
-
class NotificationsService {
|
|
31867
|
-
constructor() {
|
|
31868
|
-
this.notifications$ = new BehaviorSubject([]);
|
|
31869
|
-
}
|
|
31870
|
-
showNotification(content, timeoutMs, error) {
|
|
31871
|
-
error && console.error(error);
|
|
31872
|
-
const id = Math.floor(Math.random() * 1000000);
|
|
31873
|
-
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31874
|
-
if (typeof timeoutMs === 'undefined')
|
|
31875
|
-
return;
|
|
31876
|
-
setTimeout(() => {
|
|
31877
|
-
this.removeNotificationById(id);
|
|
31878
|
-
}, timeoutMs);
|
|
31879
|
-
}
|
|
31880
|
-
removeNotificationById(id) {
|
|
31881
|
-
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31882
|
-
}
|
|
31883
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31884
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31885
|
-
}
|
|
31886
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31887
|
-
type: Injectable,
|
|
31888
|
-
args: [{
|
|
31889
|
-
providedIn: 'root',
|
|
31890
|
-
}]
|
|
31891
|
-
}] });
|
|
31892
|
-
|
|
31893
|
-
class NotificationsContainerComponent {
|
|
31894
|
-
constructor() {
|
|
31895
|
-
this.notificationsService = inject(NotificationsService);
|
|
31896
|
-
}
|
|
31897
|
-
trackById(index, notification) {
|
|
31898
|
-
return notification.id;
|
|
31899
|
-
}
|
|
31900
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31901
|
-
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: [
|
|
31902
|
-
trigger('enterExit', [
|
|
31903
|
-
transition(':enter', [
|
|
31904
|
-
animate('150ms', keyframes([
|
|
31905
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31906
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31907
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31908
|
-
])),
|
|
31909
|
-
]),
|
|
31910
|
-
transition(':leave', [
|
|
31911
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31912
|
-
]),
|
|
31913
|
-
]),
|
|
31914
|
-
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31915
|
-
}
|
|
31916
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31917
|
-
type: Component,
|
|
31918
|
-
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31919
|
-
trigger('enterExit', [
|
|
31920
|
-
transition(':enter', [
|
|
31921
|
-
animate('150ms', keyframes([
|
|
31922
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31923
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31924
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31925
|
-
])),
|
|
31926
|
-
]),
|
|
31927
|
-
transition(':leave', [
|
|
31928
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31929
|
-
]),
|
|
31930
|
-
]),
|
|
31931
|
-
], 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" }]
|
|
31932
|
-
}] });
|
|
31933
|
-
|
|
31934
32389
|
class ResultsTableContainerComponent {
|
|
31935
32390
|
constructor() {
|
|
31936
32391
|
this.searchFacade = inject(SearchFacade);
|
|
@@ -32015,12 +32470,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
32015
32470
|
|
|
32016
32471
|
marker('search.filters.summaryLabel.user');
|
|
32017
32472
|
marker('search.filters.summaryLabel.changeDate');
|
|
32473
|
+
const OPEN_BOUND = '…';
|
|
32018
32474
|
class SearchFiltersSummaryItemComponent {
|
|
32019
32475
|
constructor() {
|
|
32020
32476
|
this.searchFacade = inject(SearchFacade);
|
|
32021
32477
|
this.searchService = inject(SearchService);
|
|
32022
32478
|
this.fieldsService = inject(FieldsService);
|
|
32023
|
-
this.
|
|
32479
|
+
this.dateService = inject(DateService);
|
|
32024
32480
|
this.translate = inject(TranslateService);
|
|
32025
32481
|
this.fieldValues$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$2((fieldValues) => Array.isArray(fieldValues[this.fieldName])
|
|
32026
32482
|
? fieldValues[this.fieldName]
|
|
@@ -32047,9 +32503,10 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32047
32503
|
getReadableValues(fieldValues) {
|
|
32048
32504
|
return fieldValues.map((value) => {
|
|
32049
32505
|
if (this.fieldType === 'dateRange') {
|
|
32506
|
+
const { start, end } = value;
|
|
32050
32507
|
return {
|
|
32051
32508
|
value,
|
|
32052
|
-
label: `${this.
|
|
32509
|
+
label: `${this.formatBound(start)} - ${this.formatBound(end)}`,
|
|
32053
32510
|
};
|
|
32054
32511
|
}
|
|
32055
32512
|
else if (this.fieldName === 'user') {
|
|
@@ -32060,6 +32517,15 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32060
32517
|
}
|
|
32061
32518
|
});
|
|
32062
32519
|
}
|
|
32520
|
+
formatBound(date) {
|
|
32521
|
+
return date
|
|
32522
|
+
? this.dateService.formatDate(date, {
|
|
32523
|
+
day: '2-digit',
|
|
32524
|
+
month: '2-digit',
|
|
32525
|
+
year: 'numeric',
|
|
32526
|
+
})
|
|
32527
|
+
: OPEN_BOUND;
|
|
32528
|
+
}
|
|
32063
32529
|
async removeFilterValue(fieldValue) {
|
|
32064
32530
|
const currentFieldValues = await firstValueFrom(this.fieldValues$);
|
|
32065
32531
|
const updatedFieldValues = currentFieldValues
|
|
@@ -32072,11 +32538,11 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32072
32538
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
32073
32539
|
}
|
|
32074
32540
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32075
|
-
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" },
|
|
32541
|
+
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" }] }); }
|
|
32076
32542
|
}
|
|
32077
32543
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, decorators: [{
|
|
32078
32544
|
type: Component,
|
|
32079
|
-
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent],
|
|
32545
|
+
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" }]
|
|
32080
32546
|
}], propDecorators: { fieldName: [{
|
|
32081
32547
|
type: Input
|
|
32082
32548
|
}] } });
|
|
@@ -32320,11 +32786,11 @@ class AddLayerFromFileComponent {
|
|
|
32320
32786
|
}, 5000);
|
|
32321
32787
|
}
|
|
32322
32788
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32323
|
-
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" }] }); }
|
|
32789
|
+
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" }] }); }
|
|
32324
32790
|
}
|
|
32325
32791
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, decorators: [{
|
|
32326
32792
|
type: Component,
|
|
32327
|
-
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" }]
|
|
32793
|
+
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" }]
|
|
32328
32794
|
}] });
|
|
32329
32795
|
|
|
32330
32796
|
class LayersPanelComponent {
|
|
@@ -32489,8 +32955,7 @@ const closeMetadata = createAction('[Metadata view] close');
|
|
|
32489
32955
|
Related actions
|
|
32490
32956
|
*/
|
|
32491
32957
|
const setRelated = createAction('[Metadata view] Set related records', props());
|
|
32492
|
-
const
|
|
32493
|
-
const setSourceOf = createAction('[Metadata view] Set has sources', props());
|
|
32958
|
+
const setLinkedRecords = createAction('[Metadata view] Set associated records', props());
|
|
32494
32959
|
/*
|
|
32495
32960
|
ChartConfig actions
|
|
32496
32961
|
*/
|
|
@@ -32522,9 +32987,8 @@ var mdview_actions = /*#__PURE__*/Object.freeze({
|
|
|
32522
32987
|
loadUserFeedbacksSuccess: loadUserFeedbacksSuccess,
|
|
32523
32988
|
setChartConfig: setChartConfig,
|
|
32524
32989
|
setIncompleteMetadata: setIncompleteMetadata,
|
|
32525
|
-
|
|
32526
|
-
|
|
32527
|
-
setSources: setSources
|
|
32990
|
+
setLinkedRecords: setLinkedRecords,
|
|
32991
|
+
setRelated: setRelated
|
|
32528
32992
|
});
|
|
32529
32993
|
|
|
32530
32994
|
const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView';
|
|
@@ -32567,12 +33031,9 @@ on(loadFullMetadata, (state) => ({
|
|
|
32567
33031
|
on(setRelated, (state, { related }) => ({
|
|
32568
33032
|
...state,
|
|
32569
33033
|
related,
|
|
32570
|
-
})), on(
|
|
33034
|
+
})), on(setLinkedRecords, (state, { linkedRecords }) => ({
|
|
32571
33035
|
...state,
|
|
32572
|
-
|
|
32573
|
-
})), on(setSourceOf, (state, { sourceOf }) => ({
|
|
32574
|
-
...state,
|
|
32575
|
-
sourceOf,
|
|
33036
|
+
linkedRecords,
|
|
32576
33037
|
})),
|
|
32577
33038
|
/*
|
|
32578
33039
|
ChartConfig reducers
|
|
@@ -32634,8 +33095,7 @@ const getMetadataError = createSelector(getMdViewState, (state) => state.error);
|
|
|
32634
33095
|
Related selectors
|
|
32635
33096
|
*/
|
|
32636
33097
|
const getRelated = createSelector(getMdViewState, (state) => state.related);
|
|
32637
|
-
const
|
|
32638
|
-
const getSourceOf = createSelector(getMdViewState, (state) => state.sourceOf);
|
|
33098
|
+
const getLinkedRecords = createSelector(getMdViewState, (state) => state.linkedRecords);
|
|
32639
33099
|
/*
|
|
32640
33100
|
Metadata selectors
|
|
32641
33101
|
*/
|
|
@@ -32736,212 +33196,10 @@ function parseHeaders(httpHeaders) {
|
|
|
32736
33196
|
return result;
|
|
32737
33197
|
}
|
|
32738
33198
|
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
? fileExtensionMatches[1].toLowerCase()
|
|
32743
|
-
: null;
|
|
32744
|
-
// 1. type hint
|
|
32745
|
-
if (typeHint)
|
|
32746
|
-
return Promise.resolve(typeHint);
|
|
32747
|
-
// 2. content-type header
|
|
32748
|
-
const headers = await fetchHeaders(url);
|
|
32749
|
-
if ('supportedType' in headers)
|
|
32750
|
-
return headers.supportedType;
|
|
32751
|
-
// 3. file extension from url
|
|
32752
|
-
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
32753
|
-
return fileExtension;
|
|
32754
|
-
// no type inferred or hinted
|
|
32755
|
-
if ('mimeType' in headers)
|
|
32756
|
-
throw FetchError.unsupportedType(headers.mimeType);
|
|
32757
|
-
else
|
|
32758
|
-
throw FetchError.unknownType();
|
|
32759
|
-
}
|
|
32760
|
-
function fetchHeaders(url) {
|
|
32761
|
-
return sharedFetch(url, 'HEAD')
|
|
32762
|
-
.catch((error) => {
|
|
32763
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32764
|
-
})
|
|
32765
|
-
.then((response) => {
|
|
32766
|
-
if (!response.ok) {
|
|
32767
|
-
throw FetchError.http(response.status);
|
|
32768
|
-
}
|
|
32769
|
-
return parseHeaders(response.headers);
|
|
32770
|
-
});
|
|
32771
|
-
}
|
|
32772
|
-
function fetchDataAsText(url, cacheActive) {
|
|
32773
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32774
|
-
.catch((error) => {
|
|
32775
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32776
|
-
})
|
|
32777
|
-
.then(async (response) => {
|
|
32778
|
-
if (!response.ok) {
|
|
32779
|
-
const clonedResponse = response.clone();
|
|
32780
|
-
throw FetchError.http(response.status, await clonedResponse.text());
|
|
32781
|
-
}
|
|
32782
|
-
const clonedResponse = response.clone();
|
|
32783
|
-
return clonedResponse.text();
|
|
32784
|
-
});
|
|
32785
|
-
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
32786
|
-
}
|
|
32787
|
-
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
32788
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32789
|
-
.catch((error) => {
|
|
32790
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32791
|
-
})
|
|
32792
|
-
.then(async (response) => {
|
|
32793
|
-
if (!response.ok) {
|
|
32794
|
-
throw FetchError.http(response.status, await response.text());
|
|
32795
|
-
}
|
|
32796
|
-
// convert to a numeric array so that we can store the response in cache
|
|
32797
|
-
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
32798
|
-
});
|
|
32799
|
-
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
32800
|
-
return new Uint8Array(array).buffer;
|
|
32801
|
-
});
|
|
32802
|
-
}
|
|
32803
|
-
function tryParseDate(input) {
|
|
32804
|
-
if (typeof input !== 'string')
|
|
32805
|
-
return null;
|
|
32806
|
-
function tryIso(value) {
|
|
32807
|
-
const parsed = parseISO(value);
|
|
32808
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32809
|
-
}
|
|
32810
|
-
function tryFormat(value, format) {
|
|
32811
|
-
const parsed = parse$4(value, format, new Date());
|
|
32812
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32813
|
-
}
|
|
32814
|
-
return (tryIso(input) ||
|
|
32815
|
-
tryFormat(input, 'dd/MM/yyyy') ||
|
|
32816
|
-
tryFormat(input, 'dd.MM.yyyy') ||
|
|
32817
|
-
tryFormat(input, 'MM/dd/yyyy') ||
|
|
32818
|
-
null);
|
|
32819
|
-
}
|
|
32820
|
-
function tryParseNumber(input) {
|
|
32821
|
-
if (isNaN(input))
|
|
32822
|
-
return null;
|
|
32823
|
-
const parsed = parseFloat(input);
|
|
32824
|
-
return isNaN(parsed) ? null : parsed;
|
|
32825
|
-
}
|
|
32826
|
-
function jsonToGeojsonFeature(object) {
|
|
32827
|
-
const { id, properties } = Object.keys(object)
|
|
32828
|
-
.map((property) => (property ? property : 'unknown')) //prevent empty strings
|
|
32829
|
-
.reduce((prev, curr) => curr.toLowerCase().endsWith('id')
|
|
32830
|
-
? {
|
|
32831
|
-
...prev,
|
|
32832
|
-
id: object[curr],
|
|
32833
|
-
}
|
|
32834
|
-
: {
|
|
32835
|
-
...prev,
|
|
32836
|
-
properties: { ...prev.properties, [curr]: object[curr] },
|
|
32837
|
-
}, { id: undefined, properties: {} });
|
|
32838
|
-
return {
|
|
32839
|
-
type: 'Feature',
|
|
32840
|
-
geometry: null,
|
|
32841
|
-
properties,
|
|
32842
|
-
...(id !== undefined && { id }),
|
|
32843
|
-
};
|
|
32844
|
-
}
|
|
32845
|
-
function mutateProperties(items, mutators) {
|
|
32846
|
-
const mutatorKeys = Object.keys(mutators);
|
|
32847
|
-
for (let i = 0, ii = items.length; i < ii; i++) {
|
|
32848
|
-
const item = items[i];
|
|
32849
|
-
for (const mutatorField of mutatorKeys) {
|
|
32850
|
-
if (!(mutatorField in item.properties))
|
|
32851
|
-
continue;
|
|
32852
|
-
item.properties[mutatorField] = mutators[mutatorField](item.properties[mutatorField]);
|
|
32853
|
-
}
|
|
32854
|
-
}
|
|
32855
|
-
return items;
|
|
32856
|
-
}
|
|
32857
|
-
const SAMPLE_SIZE = 20;
|
|
32858
|
-
/**
|
|
32859
|
-
* This will infer field types from a list of data items and cast the values accordingly
|
|
32860
|
-
* @param items
|
|
32861
|
-
* @param inferTypes
|
|
32862
|
-
*/
|
|
32863
|
-
function processItemProperties(items, inferTypes = false) {
|
|
32864
|
-
const foundFields = {};
|
|
32865
|
-
for (let i = 0, ii = Math.min(SAMPLE_SIZE, items.length); i < ii; i++) {
|
|
32866
|
-
const item = items[i];
|
|
32867
|
-
const fields = Object.keys(item.properties);
|
|
32868
|
-
for (const field of fields) {
|
|
32869
|
-
if (!(field in foundFields)) {
|
|
32870
|
-
foundFields[field] = {
|
|
32871
|
-
label: field,
|
|
32872
|
-
name: field,
|
|
32873
|
-
type: null,
|
|
32874
|
-
};
|
|
32875
|
-
}
|
|
32876
|
-
const value = item.properties[field];
|
|
32877
|
-
const info = foundFields[field];
|
|
32878
|
-
if (value === undefined || value === '' || value === null)
|
|
32879
|
-
continue;
|
|
32880
|
-
if (!inferTypes) {
|
|
32881
|
-
if (info.type === null && typeof value === 'number') {
|
|
32882
|
-
info.type = 'number';
|
|
32883
|
-
}
|
|
32884
|
-
else if (info.type === 'number' && typeof value !== 'number') {
|
|
32885
|
-
info.type = 'string';
|
|
32886
|
-
}
|
|
32887
|
-
continue;
|
|
32888
|
-
}
|
|
32889
|
-
const parsedNumber = tryParseNumber(value);
|
|
32890
|
-
if (info.type === null && parsedNumber !== null) {
|
|
32891
|
-
info.type = 'number';
|
|
32892
|
-
continue;
|
|
32893
|
-
}
|
|
32894
|
-
else if (info.type === 'number' && parsedNumber === null) {
|
|
32895
|
-
info.type = 'string';
|
|
32896
|
-
continue;
|
|
32897
|
-
}
|
|
32898
|
-
const parsedDate = tryParseDate(value);
|
|
32899
|
-
if (info.type === null && parsedDate !== null) {
|
|
32900
|
-
info.type = 'date';
|
|
32901
|
-
}
|
|
32902
|
-
else if (info.type === 'date' && parsedDate === null) {
|
|
32903
|
-
info.type = 'string';
|
|
32904
|
-
}
|
|
32905
|
-
}
|
|
32906
|
-
}
|
|
32907
|
-
const properties = [];
|
|
32908
|
-
const mutators = {};
|
|
32909
|
-
for (const field in foundFields) {
|
|
32910
|
-
const info = foundFields[field];
|
|
32911
|
-
if (info.type === 'number') {
|
|
32912
|
-
mutators[field] = tryParseNumber;
|
|
32913
|
-
}
|
|
32914
|
-
else if (info.type === 'date') {
|
|
32915
|
-
mutators[field] = tryParseDate;
|
|
32916
|
-
}
|
|
32917
|
-
properties.push({ ...info, type: info.type || 'string' });
|
|
32918
|
-
}
|
|
32919
|
-
if (inferTypes) {
|
|
32920
|
-
mutateProperties(items, mutators);
|
|
32921
|
-
}
|
|
32922
|
-
return { items, properties };
|
|
32923
|
-
}
|
|
32924
|
-
/**
|
|
32925
|
-
* This creates a Proxy that allows reading and writing to the data item properties
|
|
32926
|
-
* as if it was a simple array of JSON objects
|
|
32927
|
-
* @param items
|
|
32928
|
-
*/
|
|
32929
|
-
function getJsonDataItemsProxy(items) {
|
|
32930
|
-
return new Proxy(items, {
|
|
32931
|
-
get(target, p) {
|
|
32932
|
-
if (typeof p === 'string' &&
|
|
32933
|
-
!Number.isNaN(parseInt(p)) &&
|
|
32934
|
-
target[p]?.properties) {
|
|
32935
|
-
return target[p].properties;
|
|
32936
|
-
}
|
|
32937
|
-
return target[p];
|
|
32938
|
-
},
|
|
32939
|
-
set() {
|
|
32940
|
-
throw new Error('This object is read-only');
|
|
32941
|
-
},
|
|
32942
|
-
});
|
|
33199
|
+
const GEOMETRY_COLUMN_ALIAS = '__geometry__';
|
|
33200
|
+
function fieldToSql(name) {
|
|
33201
|
+
return `"${name.replace(/"/g, '""')}"`; // escape double quotes in field names
|
|
32943
33202
|
}
|
|
32944
|
-
|
|
32945
33203
|
function filterToSql(filter) {
|
|
32946
33204
|
const operator = filter[0];
|
|
32947
33205
|
const args = filter.slice(1);
|
|
@@ -32956,10 +33214,10 @@ function filterToSql(filter) {
|
|
|
32956
33214
|
case '=':
|
|
32957
33215
|
case '!=':
|
|
32958
33216
|
case 'like':
|
|
32959
|
-
return
|
|
33217
|
+
return `${fieldToSql(args[0])} ${operator.toUpperCase()} ${valueToSql(args[1])}`;
|
|
32960
33218
|
case 'in': {
|
|
32961
33219
|
const values = args.slice(1);
|
|
32962
|
-
return
|
|
33220
|
+
return `${fieldToSql(args[0])} IN (${values.map(valueToSql).join(', ')})`;
|
|
32963
33221
|
}
|
|
32964
33222
|
case 'and':
|
|
32965
33223
|
case 'or': {
|
|
@@ -32978,17 +33236,18 @@ function aggregationToSql(aggregation) {
|
|
|
32978
33236
|
const field = aggregation[1];
|
|
32979
33237
|
switch (operation) {
|
|
32980
33238
|
case 'average':
|
|
32981
|
-
return `AVG(
|
|
33239
|
+
return `CAST(AVG(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`average(${field})`)}`;
|
|
32982
33240
|
case 'sum':
|
|
32983
33241
|
case 'max':
|
|
32984
33242
|
case 'min':
|
|
32985
|
-
return
|
|
33243
|
+
return `CAST(${operation.toUpperCase()}(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`${operation}(${field})`)}`;
|
|
32986
33244
|
case 'count':
|
|
32987
|
-
return 'COUNT(*) as
|
|
33245
|
+
return 'CAST(COUNT(*) AS INTEGER) as "count()"'; // we don't need Bigint precision here
|
|
32988
33246
|
}
|
|
32989
33247
|
}
|
|
32990
33248
|
/**
|
|
32991
33249
|
* Leave arguments at null if not used
|
|
33250
|
+
* @param tableName
|
|
32992
33251
|
* @param selected
|
|
32993
33252
|
* @param filter
|
|
32994
33253
|
* @param sort
|
|
@@ -32997,22 +33256,25 @@ function aggregationToSql(aggregation) {
|
|
|
32997
33256
|
* @param groupBy
|
|
32998
33257
|
* @param aggregations
|
|
32999
33258
|
*/
|
|
33000
|
-
function generateSqlQuery(selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null) {
|
|
33259
|
+
function generateSqlQuery(tableName, selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null, geometryColumn = null) {
|
|
33001
33260
|
let sqlSelect = 'SELECT *';
|
|
33002
|
-
const sqlFrom =
|
|
33261
|
+
const sqlFrom = ` FROM ${tableName}`;
|
|
33003
33262
|
let sqlOrderBy = '';
|
|
33004
33263
|
let sqlWhere = '';
|
|
33005
33264
|
let sqlLimit = '';
|
|
33006
33265
|
let sqlGroupBy = '';
|
|
33007
33266
|
if (selected !== null) {
|
|
33008
|
-
sqlSelect = `SELECT ${selected.map(
|
|
33267
|
+
sqlSelect = `SELECT ${selected.map(fieldToSql).join(', ')}`;
|
|
33268
|
+
}
|
|
33269
|
+
if (geometryColumn !== null) {
|
|
33270
|
+
sqlSelect += `, ST_AsGeoJSON(${fieldToSql(geometryColumn)}) as ${GEOMETRY_COLUMN_ALIAS}`;
|
|
33009
33271
|
}
|
|
33010
33272
|
if (filter !== null) {
|
|
33011
33273
|
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
33012
33274
|
}
|
|
33013
33275
|
if (sort?.length) {
|
|
33014
33276
|
sqlOrderBy = ` ORDER BY ${sort
|
|
33015
|
-
.map((sort) =>
|
|
33277
|
+
.map((sort) => `${fieldToSql(sort[1])} ${sort[0].toUpperCase()}`)
|
|
33016
33278
|
.join(', ')}`;
|
|
33017
33279
|
}
|
|
33018
33280
|
if (startIndex !== null && count !== null) {
|
|
@@ -33022,17 +33284,212 @@ function generateSqlQuery(selected = null, filter = null, sort = null, startInde
|
|
|
33022
33284
|
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33023
33285
|
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33024
33286
|
const sqlGroupByFields = groupedByDistinct
|
|
33025
|
-
.map((group) =>
|
|
33287
|
+
.map((group) => fieldToSql(group[1]))
|
|
33026
33288
|
.join(', ');
|
|
33027
33289
|
const sqlGroupBySelect = groupedByDistinct
|
|
33028
|
-
.map((group) =>
|
|
33290
|
+
.map((group) => `${fieldToSql(group[1])} as ${fieldToSql(`distinct(${group[1]})`)}`)
|
|
33029
33291
|
.join(', ');
|
|
33030
33292
|
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33031
33293
|
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33032
33294
|
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33033
33295
|
}
|
|
33034
33296
|
}
|
|
33035
|
-
return sqlSelect + sqlFrom + sqlGroupBy +
|
|
33297
|
+
return sqlSelect + sqlFrom + sqlGroupBy + sqlWhere + sqlOrderBy + sqlLimit;
|
|
33298
|
+
}
|
|
33299
|
+
|
|
33300
|
+
function arrowTableToDataItems(table) {
|
|
33301
|
+
const fields = table.schema.fields;
|
|
33302
|
+
return table.toArray().map((row) => {
|
|
33303
|
+
const rowJson = row.toJSON();
|
|
33304
|
+
const feature = {
|
|
33305
|
+
type: 'Feature',
|
|
33306
|
+
geometry: null,
|
|
33307
|
+
properties: {},
|
|
33308
|
+
};
|
|
33309
|
+
const keys = Object.keys(rowJson);
|
|
33310
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33311
|
+
const key = keys[i];
|
|
33312
|
+
const dataType = fields[i].type;
|
|
33313
|
+
let value = rowJson[key];
|
|
33314
|
+
// this might happen if we get an array inside a field
|
|
33315
|
+
if (value instanceof Vector) {
|
|
33316
|
+
value = Array.from(value);
|
|
33317
|
+
}
|
|
33318
|
+
// cast bigints to ints
|
|
33319
|
+
if (typeof value === 'bigint') {
|
|
33320
|
+
value = Number(value);
|
|
33321
|
+
}
|
|
33322
|
+
// rename columns with empty name
|
|
33323
|
+
if (!key) {
|
|
33324
|
+
feature.properties['unknown'] = value;
|
|
33325
|
+
continue;
|
|
33326
|
+
}
|
|
33327
|
+
// assign properties that look like an id to the geojson `id` field
|
|
33328
|
+
if (/^(object|feature)?_?id$/.test(key.toLowerCase()) &&
|
|
33329
|
+
(typeof value == 'string' || typeof value === 'number')) {
|
|
33330
|
+
feature.id = value;
|
|
33331
|
+
}
|
|
33332
|
+
// if a date is in timestamp (number) format, convert it to native
|
|
33333
|
+
if (typeof value === 'number' &&
|
|
33334
|
+
(DataType.isTimestamp(dataType) || DataType.isDate(dataType))) {
|
|
33335
|
+
value = new Date(value);
|
|
33336
|
+
}
|
|
33337
|
+
// if a binary field (most likely a geometry column): skip
|
|
33338
|
+
if (DataType.isBinary(dataType)) {
|
|
33339
|
+
continue;
|
|
33340
|
+
}
|
|
33341
|
+
// geometry column
|
|
33342
|
+
if (key === GEOMETRY_COLUMN_ALIAS && DataType.isUtf8(dataType)) {
|
|
33343
|
+
feature.geometry = JSON.parse(value);
|
|
33344
|
+
continue;
|
|
33345
|
+
}
|
|
33346
|
+
feature.properties[key] = value;
|
|
33347
|
+
}
|
|
33348
|
+
return feature;
|
|
33349
|
+
});
|
|
33350
|
+
}
|
|
33351
|
+
|
|
33352
|
+
// init code taken from https://github.com/duckdb/duckdb-wasm/blob/main/packages/duckdb-wasm/README.md
|
|
33353
|
+
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
|
33354
|
+
// from https://duckdb.org/docs/current/sql/data_types/overview
|
|
33355
|
+
const typesMapping = {
|
|
33356
|
+
INTEGER: 'number',
|
|
33357
|
+
SMALLINT: 'number',
|
|
33358
|
+
TINYINT: 'number',
|
|
33359
|
+
BIGINT: 'number',
|
|
33360
|
+
HUGEINT: 'number',
|
|
33361
|
+
UINTEGER: 'number',
|
|
33362
|
+
USMALLINT: 'number',
|
|
33363
|
+
UTINYINT: 'number',
|
|
33364
|
+
UBIGINT: 'number',
|
|
33365
|
+
UHUGEINT: 'number',
|
|
33366
|
+
DOUBLE: 'number',
|
|
33367
|
+
BIGNUM: 'number',
|
|
33368
|
+
DECIMAL: 'number',
|
|
33369
|
+
NUMERIC: 'number',
|
|
33370
|
+
FLOAT: 'number',
|
|
33371
|
+
REAL: 'number',
|
|
33372
|
+
'TIMESTAMP WITH TIME ZONE': 'date',
|
|
33373
|
+
TIMESTAMP: 'date',
|
|
33374
|
+
DATE: 'date',
|
|
33375
|
+
CHAR: 'string',
|
|
33376
|
+
VARCHAR: 'string',
|
|
33377
|
+
TEXT: 'string',
|
|
33378
|
+
UUID: 'string',
|
|
33379
|
+
BLOB: 'string',
|
|
33380
|
+
BIT: 'string',
|
|
33381
|
+
INTERVAL: 'string',
|
|
33382
|
+
LIST: 'string',
|
|
33383
|
+
BOOLEAN: 'boolean',
|
|
33384
|
+
};
|
|
33385
|
+
class Engine {
|
|
33386
|
+
async makeInit() {
|
|
33387
|
+
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
|
|
33388
|
+
let worker_url = bundle.mainWorker;
|
|
33389
|
+
// this is necessary to let browsers execute WASM code coming from a cross-origin host
|
|
33390
|
+
if (worker_url.startsWith('https://')) {
|
|
33391
|
+
worker_url = URL.createObjectURL(new Blob([`importScripts("${worker_url}");`], {
|
|
33392
|
+
type: 'text/javascript',
|
|
33393
|
+
}));
|
|
33394
|
+
}
|
|
33395
|
+
const worker = new Worker(worker_url);
|
|
33396
|
+
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
|
|
33397
|
+
this.db = new duckdb.AsyncDuckDB(logger, worker);
|
|
33398
|
+
await this.db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
33399
|
+
// setup duckdb options
|
|
33400
|
+
const conn = await this.db.connect();
|
|
33401
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33402
|
+
await conn.query(`INSTALL spatial; LOAD spatial;`);
|
|
33403
|
+
await conn.query(`SET TimeZone = '${timezone}';`);
|
|
33404
|
+
await conn.query(`SET threads = 1;`);
|
|
33405
|
+
// await conn.query(`SET memory_limit = '2GB';`) // used for experimenting when we encounter memory issues
|
|
33406
|
+
await conn.query(`SET preserve_insertion_order = false;`); // this reduces memory usage when loading a dataset
|
|
33407
|
+
conn.close();
|
|
33408
|
+
return this;
|
|
33409
|
+
}
|
|
33410
|
+
isReady() {
|
|
33411
|
+
if (!this.init_) {
|
|
33412
|
+
this.init_ = this.makeInit();
|
|
33413
|
+
}
|
|
33414
|
+
return this.init_;
|
|
33415
|
+
}
|
|
33416
|
+
/**
|
|
33417
|
+
* Returns information about a dataset once it's loaded:
|
|
33418
|
+
* - a list of properties description
|
|
33419
|
+
* - the name of the dataset geometry column (null if no geometry present)
|
|
33420
|
+
* @param datasetId name of the table under which the dataset will be stored
|
|
33421
|
+
* @param loadQuery duckdb-specific query for creating a table out of the data
|
|
33422
|
+
* @param forceReload if true, any existing data will be dropped and redownloaded
|
|
33423
|
+
*/
|
|
33424
|
+
async loadFile(datasetId, loadQuery, forceReload = false) {
|
|
33425
|
+
const conn = await this.db.connect();
|
|
33426
|
+
let results;
|
|
33427
|
+
// either we want to recreate the table, or we keep it if it already exists
|
|
33428
|
+
const safeLoadQuery = forceReload
|
|
33429
|
+
? `DROP TABLE IF EXISTS ${datasetId};
|
|
33430
|
+
${loadQuery}`
|
|
33431
|
+
: loadQuery.replace(/CREATE TABLE(?! IF NOT EXISTS)/gi, 'CREATE TABLE IF NOT EXISTS');
|
|
33432
|
+
// create the table
|
|
33433
|
+
try {
|
|
33434
|
+
results = await conn.query(safeLoadQuery);
|
|
33435
|
+
}
|
|
33436
|
+
catch (e) {
|
|
33437
|
+
throw new FetchError('parse', `DuckDB encountered an error when loading the data: ${e.message}`);
|
|
33438
|
+
}
|
|
33439
|
+
// read rows count
|
|
33440
|
+
results = await conn.query(`SELECT count(*) FROM ${datasetId}`);
|
|
33441
|
+
const { 'count_star()': recordsCount } = results.toArray()[0].toJSON();
|
|
33442
|
+
// read columns
|
|
33443
|
+
results = await conn.query(`SELECT * FROM information_schema.columns WHERE table_name = '${datasetId}';`);
|
|
33444
|
+
let geometryColumn = null;
|
|
33445
|
+
const properties = results
|
|
33446
|
+
.toArray()
|
|
33447
|
+
.map((row) => {
|
|
33448
|
+
const rowObj = row.toJSON();
|
|
33449
|
+
if (rowObj['data_type'] === 'GEOMETRY') {
|
|
33450
|
+
// the geometry is not part of the properties
|
|
33451
|
+
// note: right now we only keep one geometry column name, but if there are multiple they will
|
|
33452
|
+
// all get discarded
|
|
33453
|
+
geometryColumn = rowObj['column_name'];
|
|
33454
|
+
return null;
|
|
33455
|
+
}
|
|
33456
|
+
return {
|
|
33457
|
+
name: rowObj['column_name'],
|
|
33458
|
+
label: rowObj['column_name'],
|
|
33459
|
+
type: typesMapping[rowObj['data_type']] ?? 'other',
|
|
33460
|
+
};
|
|
33461
|
+
})
|
|
33462
|
+
.filter((prop) => prop !== null);
|
|
33463
|
+
conn.close();
|
|
33464
|
+
return {
|
|
33465
|
+
properties,
|
|
33466
|
+
geometryColumn,
|
|
33467
|
+
rowsCount: Number(recordsCount),
|
|
33468
|
+
};
|
|
33469
|
+
}
|
|
33470
|
+
// register a Uint8 buffer using a handle in the duckdb instance
|
|
33471
|
+
async registerData(name, buffer) {
|
|
33472
|
+
return this.db.registerFileBuffer(name, buffer);
|
|
33473
|
+
}
|
|
33474
|
+
/**
|
|
33475
|
+
* @param query duckdb-specific query for fetching items
|
|
33476
|
+
*/
|
|
33477
|
+
async queryItems(query) {
|
|
33478
|
+
const conn = await this.db.connect();
|
|
33479
|
+
const results = await conn.query(query);
|
|
33480
|
+
conn.close();
|
|
33481
|
+
return arrowTableToDataItems(results);
|
|
33482
|
+
}
|
|
33483
|
+
close() {
|
|
33484
|
+
this.db?.terminate();
|
|
33485
|
+
}
|
|
33486
|
+
}
|
|
33487
|
+
let engine = null;
|
|
33488
|
+
async function getEngine() {
|
|
33489
|
+
if (!engine) {
|
|
33490
|
+
engine = new Engine();
|
|
33491
|
+
}
|
|
33492
|
+
return engine.isReady();
|
|
33036
33493
|
}
|
|
33037
33494
|
|
|
33038
33495
|
class BaseReader {
|
|
@@ -33045,10 +33502,18 @@ class BaseReader {
|
|
|
33045
33502
|
this.sort = null;
|
|
33046
33503
|
this.startIndex = null;
|
|
33047
33504
|
this.count = null;
|
|
33505
|
+
this.loadPromise_ = Promise.resolve();
|
|
33506
|
+
this.cacheEnabled = false;
|
|
33507
|
+
}
|
|
33508
|
+
enableCache(enabled) {
|
|
33509
|
+
this.cacheEnabled = enabled;
|
|
33048
33510
|
}
|
|
33049
33511
|
load() {
|
|
33050
33512
|
throw new Error('not implemented');
|
|
33051
33513
|
}
|
|
33514
|
+
get isLoaded() {
|
|
33515
|
+
return this.loadPromise_;
|
|
33516
|
+
}
|
|
33052
33517
|
get properties() {
|
|
33053
33518
|
throw new Error('not implemented');
|
|
33054
33519
|
}
|
|
@@ -33097,178 +33562,237 @@ class BaseReader {
|
|
|
33097
33562
|
}
|
|
33098
33563
|
}
|
|
33099
33564
|
|
|
33100
|
-
|
|
33101
|
-
|
|
33102
|
-
|
|
33103
|
-
|
|
33104
|
-
|
|
33105
|
-
|
|
33106
|
-
|
|
33107
|
-
|
|
33108
|
-
|
|
33109
|
-
|
|
33110
|
-
|
|
33111
|
-
|
|
33112
|
-
|
|
33565
|
+
/**
|
|
33566
|
+
* This reader handles file formats supported natively by DuckDB
|
|
33567
|
+
*/
|
|
33568
|
+
class BaseFileReader extends BaseReader {
|
|
33569
|
+
// a table id should not exceed 63 chars
|
|
33570
|
+
generateDatasetId() {
|
|
33571
|
+
// generate a hash out of the url
|
|
33572
|
+
let hash = 0;
|
|
33573
|
+
for (const char of this.url) {
|
|
33574
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
33575
|
+
hash = hash >>> 0; // make it unsigned
|
|
33576
|
+
}
|
|
33577
|
+
return `datafetcher_${hash.toString(16)}`;
|
|
33578
|
+
}
|
|
33579
|
+
async getLoadQuery() {
|
|
33113
33580
|
throw new Error('not implemented');
|
|
33114
33581
|
}
|
|
33115
|
-
load() {
|
|
33116
|
-
this.
|
|
33582
|
+
async load() {
|
|
33583
|
+
this.datasetId = this.generateDatasetId();
|
|
33584
|
+
this.loadPromise_ = getEngine()
|
|
33585
|
+
.then((engine) => {
|
|
33586
|
+
this.engine = engine;
|
|
33587
|
+
return this.getLoadQuery();
|
|
33588
|
+
})
|
|
33589
|
+
.then((loadQuery) => this.engine.loadFile(this.datasetId, loadQuery, !this.cacheEnabled))
|
|
33590
|
+
.then((datasetInfo) => {
|
|
33591
|
+
this.properties_ = datasetInfo.properties;
|
|
33592
|
+
this.geometryColumn = datasetInfo.geometryColumn;
|
|
33593
|
+
this.rowsCount = datasetInfo.rowsCount;
|
|
33594
|
+
// returns void for the loaded promise
|
|
33595
|
+
});
|
|
33117
33596
|
}
|
|
33118
33597
|
get properties() {
|
|
33119
|
-
return this.
|
|
33598
|
+
return this.isLoaded.then(() => this.properties_);
|
|
33120
33599
|
}
|
|
33121
33600
|
get info() {
|
|
33122
|
-
return this.
|
|
33123
|
-
itemsCount:
|
|
33601
|
+
return this.isLoaded.then(() => ({
|
|
33602
|
+
itemsCount: this.rowsCount,
|
|
33603
|
+
hasGeometry: !!this.geometryColumn,
|
|
33124
33604
|
}));
|
|
33125
33605
|
}
|
|
33126
33606
|
async read() {
|
|
33127
|
-
|
|
33128
|
-
//
|
|
33129
|
-
|
|
33130
|
-
|
|
33131
|
-
|
|
33132
|
-
this.sort == null &&
|
|
33133
|
-
this.filter == null &&
|
|
33134
|
-
this.startIndex == null &&
|
|
33135
|
-
this.count == null) {
|
|
33136
|
-
return items;
|
|
33137
|
-
}
|
|
33138
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33139
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33140
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33141
|
-
return result.map(jsonToGeojsonFeature);
|
|
33142
|
-
}
|
|
33143
|
-
}
|
|
33144
|
-
|
|
33145
|
-
function parseCsv(text) {
|
|
33146
|
-
// first parse the header to guess the delimiter
|
|
33147
|
-
// note that we do that to not rely on Papaparse logic for guessing delimiter
|
|
33148
|
-
let delimiter;
|
|
33149
|
-
try {
|
|
33150
|
-
const header = text.split('\n')[0];
|
|
33151
|
-
const result = Papa.parse(header, {
|
|
33152
|
-
header: false,
|
|
33153
|
-
});
|
|
33154
|
-
delimiter = result.meta.delimiter;
|
|
33155
|
-
}
|
|
33156
|
-
catch (e) {
|
|
33157
|
-
throw new Error('CSV parsing failed: the delimiter could not be guessed');
|
|
33158
|
-
}
|
|
33159
|
-
const parsed = Papa.parse(text, {
|
|
33160
|
-
header: true,
|
|
33161
|
-
skipEmptyLines: true,
|
|
33162
|
-
delimiter,
|
|
33163
|
-
});
|
|
33164
|
-
if (parsed.errors.length) {
|
|
33165
|
-
throw new Error('CSV parsing failed for the following reasons:\n' +
|
|
33166
|
-
parsed.errors
|
|
33167
|
-
.map((error) => `* ${error.message} at row ${error.row}, column ${error.index}`)
|
|
33168
|
-
.join('\n'));
|
|
33607
|
+
await this.isLoaded;
|
|
33608
|
+
// if only certain fields are selected, omit the geometry
|
|
33609
|
+
const geometryColumn = this.selected === null ? this.geometryColumn : null;
|
|
33610
|
+
const query = generateSqlQuery(this.datasetId, this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations, geometryColumn);
|
|
33611
|
+
return this.engine.queryItems(query);
|
|
33169
33612
|
}
|
|
33170
|
-
const items = parsed.data.map(jsonToGeojsonFeature);
|
|
33171
|
-
return processItemProperties(items, true);
|
|
33172
33613
|
}
|
|
33614
|
+
|
|
33173
33615
|
class CsvReader extends BaseFileReader {
|
|
33174
|
-
|
|
33175
|
-
|
|
33616
|
+
async getLoadQuery() {
|
|
33617
|
+
// first we get a list of columns hich have a detected type of VARCHAR
|
|
33618
|
+
// 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
|
|
33619
|
+
return `
|
|
33620
|
+
SET VARIABLE strColumns = (SELECT list(name) FROM (SELECT unnest(Columns, recursive := true) FROM sniff_csv("${this.url}")) WHERE type = 'VARCHAR');
|
|
33621
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_csv("${this.url}",
|
|
33622
|
+
force_not_null = getvariable('strColumns'),
|
|
33623
|
+
auto_type_candidates = ['NULL', 'BOOLEAN', 'INTEGER', 'DOUBLE', 'DATE', 'VARCHAR']
|
|
33624
|
+
);`;
|
|
33176
33625
|
}
|
|
33177
33626
|
}
|
|
33178
33627
|
|
|
33179
|
-
/**
|
|
33180
|
-
* This parser only supports arrays of simple flat objects with properties
|
|
33181
|
-
* @param text
|
|
33182
|
-
*/
|
|
33183
|
-
function parseJson(text) {
|
|
33184
|
-
const parsed = JSON.parse(text);
|
|
33185
|
-
if (!Array.isArray(parsed)) {
|
|
33186
|
-
throw new Error('Could not parse JSON, expected an array at root level');
|
|
33187
|
-
}
|
|
33188
|
-
return processItemProperties(parsed.map(jsonToGeojsonFeature));
|
|
33189
|
-
}
|
|
33190
33628
|
class JsonReader extends BaseFileReader {
|
|
33191
|
-
|
|
33192
|
-
return
|
|
33629
|
+
async getLoadQuery() {
|
|
33630
|
+
return `
|
|
33631
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_json("${this.url}",
|
|
33632
|
+
maximum_object_size = 536870912 -- 500MB
|
|
33633
|
+
);`;
|
|
33193
33634
|
}
|
|
33194
33635
|
}
|
|
33195
33636
|
|
|
33196
|
-
/**
|
|
33197
|
-
* This parser supports both Geojson Feature collections or arrays
|
|
33198
|
-
* of Features
|
|
33199
|
-
* @param text
|
|
33200
|
-
*/
|
|
33201
|
-
function parseGeojson(text) {
|
|
33202
|
-
const parsed = JSON.parse(text);
|
|
33203
|
-
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33204
|
-
if (!Array.isArray(features)) {
|
|
33205
|
-
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33206
|
-
}
|
|
33207
|
-
return processItemProperties(features);
|
|
33208
|
-
}
|
|
33209
33637
|
class GeojsonReader extends BaseFileReader {
|
|
33210
|
-
|
|
33211
|
-
return
|
|
33638
|
+
async getLoadQuery() {
|
|
33639
|
+
return `
|
|
33640
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33641
|
+
allowed_drivers = ['GeoJSON']
|
|
33642
|
+
);`;
|
|
33212
33643
|
}
|
|
33213
33644
|
}
|
|
33214
33645
|
|
|
33646
|
+
async function inferDatasetType(url, typeHint) {
|
|
33647
|
+
const fileExtensionMatches = new URL(url, typeof window !== 'undefined' ? window.location.toString() : undefined).pathname.match(/\.(.+)$/);
|
|
33648
|
+
const fileExtension = fileExtensionMatches && fileExtensionMatches.length
|
|
33649
|
+
? fileExtensionMatches[1].toLowerCase()
|
|
33650
|
+
: null;
|
|
33651
|
+
// 1. type hint
|
|
33652
|
+
if (typeHint)
|
|
33653
|
+
return Promise.resolve(typeHint);
|
|
33654
|
+
// 2. content-type header
|
|
33655
|
+
const headers = await fetchHeaders(url);
|
|
33656
|
+
if ('supportedType' in headers)
|
|
33657
|
+
return headers.supportedType;
|
|
33658
|
+
// 3. file extension from url
|
|
33659
|
+
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
33660
|
+
return fileExtension;
|
|
33661
|
+
// no type inferred or hinted
|
|
33662
|
+
if ('mimeType' in headers)
|
|
33663
|
+
throw FetchError.unsupportedType(headers.mimeType);
|
|
33664
|
+
else
|
|
33665
|
+
throw FetchError.unknownType();
|
|
33666
|
+
}
|
|
33667
|
+
function fetchHeaders(url) {
|
|
33668
|
+
return sharedFetch(url, 'HEAD')
|
|
33669
|
+
.catch((error) => {
|
|
33670
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33671
|
+
})
|
|
33672
|
+
.then((response) => {
|
|
33673
|
+
if (!response.ok) {
|
|
33674
|
+
throw FetchError.http(response.status);
|
|
33675
|
+
}
|
|
33676
|
+
return parseHeaders(response.headers);
|
|
33677
|
+
});
|
|
33678
|
+
}
|
|
33679
|
+
function fetchDataAsText(url, cacheActive) {
|
|
33680
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33681
|
+
.catch((error) => {
|
|
33682
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33683
|
+
})
|
|
33684
|
+
.then(async (response) => {
|
|
33685
|
+
if (!response.ok) {
|
|
33686
|
+
const clonedResponse = response.clone();
|
|
33687
|
+
throw FetchError.http(response.status, await clonedResponse.text());
|
|
33688
|
+
}
|
|
33689
|
+
const clonedResponse = response.clone();
|
|
33690
|
+
return clonedResponse.text();
|
|
33691
|
+
});
|
|
33692
|
+
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
33693
|
+
}
|
|
33694
|
+
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
33695
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33696
|
+
.catch((error) => {
|
|
33697
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33698
|
+
})
|
|
33699
|
+
.then(async (response) => {
|
|
33700
|
+
if (!response.ok) {
|
|
33701
|
+
throw FetchError.http(response.status, await response.text());
|
|
33702
|
+
}
|
|
33703
|
+
// convert to a numeric array so that we can store the response in cache
|
|
33704
|
+
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
33705
|
+
});
|
|
33706
|
+
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
33707
|
+
return new Uint8Array(array).buffer;
|
|
33708
|
+
});
|
|
33709
|
+
}
|
|
33215
33710
|
/**
|
|
33216
|
-
* This
|
|
33217
|
-
*
|
|
33218
|
-
* @param
|
|
33711
|
+
* This creates a Proxy that allows reading and writing to the data item properties
|
|
33712
|
+
* as if it was a simple array of JSON objects
|
|
33713
|
+
* @param items
|
|
33219
33714
|
*/
|
|
33220
|
-
function
|
|
33221
|
-
return
|
|
33222
|
-
|
|
33223
|
-
|
|
33224
|
-
|
|
33225
|
-
|
|
33226
|
-
|
|
33227
|
-
|
|
33228
|
-
|
|
33715
|
+
function getJsonDataItemsProxy(items) {
|
|
33716
|
+
return new Proxy(items, {
|
|
33717
|
+
get(target, p) {
|
|
33718
|
+
if (typeof p === 'string' &&
|
|
33719
|
+
!Number.isNaN(parseInt(p)) &&
|
|
33720
|
+
target[p]?.properties) {
|
|
33721
|
+
return target[p].properties;
|
|
33722
|
+
}
|
|
33723
|
+
return target[p];
|
|
33724
|
+
},
|
|
33725
|
+
set() {
|
|
33726
|
+
throw new Error('This object is read-only');
|
|
33727
|
+
},
|
|
33229
33728
|
});
|
|
33230
33729
|
}
|
|
33730
|
+
|
|
33231
33731
|
class ExcelReader extends BaseFileReader {
|
|
33232
|
-
|
|
33233
|
-
|
|
33732
|
+
async getLoadQuery() {
|
|
33733
|
+
// we download the file as an array buffer first, in order to be able to check if it's an XLS file
|
|
33734
|
+
let buffer = await fetchDataAsArrayBuffer(this.url, this.cacheEnabled);
|
|
33735
|
+
const bufferHandle = `B${this.datasetId}`;
|
|
33736
|
+
// checking against the magic number at the beginning of XLS files, see https://en.wikipedia.org/wiki/List_of_file_signatures
|
|
33737
|
+
const magicNumber = new Uint8Array(buffer, 0, 8); // first 8 bytes
|
|
33738
|
+
const isXls = Array.from(magicNumber)
|
|
33739
|
+
.map((n) => n.toString(16).toUpperCase())
|
|
33740
|
+
.join(' ') === 'D0 CF 11 E0 A1 B1 1A E1';
|
|
33741
|
+
// uh oh, this is an XLS file (not supported by duckdb); convert it to CSV using the xlsx package
|
|
33742
|
+
if (isXls) {
|
|
33743
|
+
buffer = await import('xlsx').then(({ read, utils }) => {
|
|
33744
|
+
const workbook = read(buffer);
|
|
33745
|
+
const json = utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
|
|
33746
|
+
return new TextEncoder().encode(JSON.stringify(json)).buffer;
|
|
33747
|
+
});
|
|
33748
|
+
}
|
|
33749
|
+
const duckDbFn = isXls ? 'read_json' : 'read_xlsx';
|
|
33750
|
+
await this.engine.registerData(bufferHandle, new Uint8Array(buffer));
|
|
33751
|
+
return `
|
|
33752
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM ${duckDbFn}("${bufferHandle}", ignore_errors = true);`;
|
|
33234
33753
|
}
|
|
33235
33754
|
}
|
|
33236
33755
|
|
|
33237
|
-
|
|
33238
|
-
|
|
33239
|
-
|
|
33756
|
+
class GmlReader extends BaseFileReader {
|
|
33757
|
+
async getLoadQuery() {
|
|
33758
|
+
return `
|
|
33759
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33760
|
+
allowed_drivers = ['GML']
|
|
33761
|
+
);`;
|
|
33762
|
+
}
|
|
33763
|
+
}
|
|
33764
|
+
|
|
33765
|
+
const formatGeojson = new GeoJSON$1();
|
|
33766
|
+
function parseGeojson(text) {
|
|
33767
|
+
const parsed = JSON.parse(text);
|
|
33768
|
+
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33769
|
+
if (!Array.isArray(features)) {
|
|
33770
|
+
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33771
|
+
}
|
|
33772
|
+
return features;
|
|
33773
|
+
}
|
|
33774
|
+
function parseGml(text, featureType, version) {
|
|
33775
|
+
const parts = featureType.split(':');
|
|
33776
|
+
const regex = new RegExp(`xmlns:${parts[0]}=["']([^'"]*)["']`);
|
|
33240
33777
|
const match = regex.exec(text);
|
|
33241
33778
|
if (match && match.length >= 2) {
|
|
33242
|
-
const
|
|
33779
|
+
const wfs = new WFS({
|
|
33243
33780
|
featureNS: match[1],
|
|
33244
|
-
featureType:
|
|
33781
|
+
featureType: parts[1],
|
|
33245
33782
|
version: version,
|
|
33246
33783
|
});
|
|
33247
33784
|
let features;
|
|
33248
33785
|
try {
|
|
33249
|
-
features =
|
|
33786
|
+
features = wfs.readFeatures(text);
|
|
33250
33787
|
}
|
|
33251
33788
|
catch (e) {
|
|
33252
|
-
throw Error(
|
|
33789
|
+
throw Error(`Couldn't parse WFS with GML features: ${e.message}`);
|
|
33253
33790
|
}
|
|
33254
|
-
const geojsonItem =
|
|
33255
|
-
return
|
|
33791
|
+
const geojsonItem = formatGeojson.writeFeaturesObject(features);
|
|
33792
|
+
return geojsonItem.features;
|
|
33256
33793
|
}
|
|
33257
33794
|
throw Error("Couldn't retrieve namespace url");
|
|
33258
33795
|
}
|
|
33259
|
-
class GmlReader extends BaseFileReader {
|
|
33260
|
-
constructor(url, namespace, version, cacheActive = true) {
|
|
33261
|
-
super(url);
|
|
33262
|
-
this.url = url;
|
|
33263
|
-
this.namespace = namespace;
|
|
33264
|
-
this.version = version;
|
|
33265
|
-
this.cacheActive = cacheActive;
|
|
33266
|
-
}
|
|
33267
|
-
getData() {
|
|
33268
|
-
return fetchDataAsText(this.url, this.cacheActive).then((text) => parseGml(text, this.namespace, this.version));
|
|
33269
|
-
}
|
|
33270
|
-
}
|
|
33271
|
-
|
|
33272
33796
|
async function getWfsEndpoint(wfsUrl) {
|
|
33273
33797
|
try {
|
|
33274
33798
|
return await new WfsEndpoint(wfsUrl).isReady();
|
|
@@ -33296,21 +33820,65 @@ async function getWfsEndpoint(wfsUrl) {
|
|
|
33296
33820
|
}
|
|
33297
33821
|
}
|
|
33298
33822
|
}
|
|
33299
|
-
class WfsReader extends
|
|
33300
|
-
constructor(url,
|
|
33301
|
-
super(url
|
|
33302
|
-
this.endpoint =
|
|
33303
|
-
this.
|
|
33304
|
-
|
|
33823
|
+
class WfsReader extends BaseReader {
|
|
33824
|
+
constructor(url, featureTypeName) {
|
|
33825
|
+
super(url);
|
|
33826
|
+
this.endpoint = getWfsEndpoint(url);
|
|
33827
|
+
this.featureType = this.endpoint
|
|
33828
|
+
.then((endpoint) => {
|
|
33829
|
+
const featureTypes = endpoint.getFeatureTypes();
|
|
33830
|
+
return endpoint.getFeatureTypeFull(featureTypes.length === 1 && !featureTypeName
|
|
33831
|
+
? featureTypes[0].name
|
|
33832
|
+
: featureTypeName);
|
|
33833
|
+
})
|
|
33834
|
+
.then((featureType) => {
|
|
33835
|
+
if (!featureType) {
|
|
33836
|
+
throw new Error('wfs.featuretype.notfound');
|
|
33837
|
+
}
|
|
33838
|
+
return featureType;
|
|
33839
|
+
});
|
|
33840
|
+
}
|
|
33841
|
+
get backupReader() {
|
|
33842
|
+
if (this.backupReader_) {
|
|
33843
|
+
return this.backupReader_;
|
|
33844
|
+
}
|
|
33845
|
+
this.backupReader_ = Promise.all([this.endpoint, this.featureType]).then(([endpoint, featureType]) => {
|
|
33846
|
+
let reader;
|
|
33847
|
+
if (endpoint.supportsJson(featureType.name)) {
|
|
33848
|
+
reader = new GeojsonReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33849
|
+
asJson: true,
|
|
33850
|
+
outputCrs: 'EPSG:4326',
|
|
33851
|
+
}));
|
|
33852
|
+
}
|
|
33853
|
+
else {
|
|
33854
|
+
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33855
|
+
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33856
|
+
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33857
|
+
reader = new GmlReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33858
|
+
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33859
|
+
outputCrs: 'EPSG:4326',
|
|
33860
|
+
}));
|
|
33861
|
+
}
|
|
33862
|
+
}
|
|
33863
|
+
reader.enableCache(this.cacheEnabled);
|
|
33864
|
+
reader.load();
|
|
33865
|
+
return reader;
|
|
33866
|
+
});
|
|
33867
|
+
return this.backupReader_;
|
|
33305
33868
|
}
|
|
33306
33869
|
get properties() {
|
|
33307
|
-
return this.
|
|
33308
|
-
.getFeatureTypeFull(this.featureTypeName)
|
|
33309
|
-
.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33870
|
+
return this.featureType.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33310
33871
|
const originalType = featureType.properties[prop];
|
|
33311
|
-
|
|
33312
|
-
|
|
33313
|
-
|
|
33872
|
+
let type;
|
|
33873
|
+
if (originalType === 'float' || originalType === 'integer') {
|
|
33874
|
+
type = 'number';
|
|
33875
|
+
}
|
|
33876
|
+
else if (originalType === 'boolean') {
|
|
33877
|
+
type = 'string'; // we don't handle booleans yet in the data fetcher
|
|
33878
|
+
}
|
|
33879
|
+
else {
|
|
33880
|
+
type = originalType;
|
|
33881
|
+
}
|
|
33314
33882
|
return {
|
|
33315
33883
|
name: prop,
|
|
33316
33884
|
label: prop,
|
|
@@ -33319,83 +33887,63 @@ class WfsReader extends BaseCacheReader {
|
|
|
33319
33887
|
}));
|
|
33320
33888
|
}
|
|
33321
33889
|
get info() {
|
|
33322
|
-
return this.
|
|
33890
|
+
return this.featureType.then((result) => ({
|
|
33323
33891
|
itemsCount: result.objectCount,
|
|
33892
|
+
hasGeometry: !!result.geometryName,
|
|
33324
33893
|
}));
|
|
33325
33894
|
}
|
|
33326
|
-
|
|
33327
|
-
|
|
33328
|
-
const featureTypes = wfsEndpoint.getFeatureTypes();
|
|
33329
|
-
const featureType = wfsEndpoint.getFeatureTypeSummary(featureTypes.length === 1 && !featureTypeName
|
|
33330
|
-
? featureTypes[0].name
|
|
33331
|
-
: featureTypeName);
|
|
33332
|
-
if (!featureType) {
|
|
33333
|
-
throw new Error('wfs.featuretype.notfound');
|
|
33334
|
-
}
|
|
33335
|
-
if (wfsEndpoint.supportsStartIndex()) {
|
|
33336
|
-
return new WfsReader(wfsUrlEndpoint, wfsEndpoint, featureType.name);
|
|
33337
|
-
}
|
|
33338
|
-
else if (wfsEndpoint.supportsJson(featureType.name)) {
|
|
33339
|
-
return new GeojsonReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33340
|
-
asJson: true,
|
|
33341
|
-
outputCrs: 'EPSG:4326',
|
|
33342
|
-
}));
|
|
33343
|
-
}
|
|
33344
|
-
else {
|
|
33345
|
-
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33346
|
-
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33347
|
-
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33348
|
-
return new GmlReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33349
|
-
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33350
|
-
outputCrs: 'EPSG:4326',
|
|
33351
|
-
}), featureType.name, wfsEndpoint.getVersion());
|
|
33352
|
-
}
|
|
33353
|
-
throw new Error('wfs.geojsongml.notsupported');
|
|
33354
|
-
}
|
|
33895
|
+
load() {
|
|
33896
|
+
// Nothing to load for Wfs
|
|
33355
33897
|
}
|
|
33356
|
-
async
|
|
33357
|
-
|
|
33358
|
-
|
|
33898
|
+
async read() {
|
|
33899
|
+
const endpoint = await this.endpoint;
|
|
33900
|
+
const featureType = await this.featureType;
|
|
33901
|
+
// if we can't use the WFS protocol we fall back to the backup reader
|
|
33902
|
+
if (this.aggregations || this.groupedBy || !endpoint.supportsStartIndex()) {
|
|
33903
|
+
const backupReader = await this.backupReader;
|
|
33904
|
+
backupReader.selectAll();
|
|
33905
|
+
if (this.selected) {
|
|
33906
|
+
backupReader.select(...this.selected);
|
|
33907
|
+
}
|
|
33908
|
+
if (this.aggregations) {
|
|
33909
|
+
backupReader.aggregate(...this.aggregations);
|
|
33910
|
+
}
|
|
33911
|
+
if (this.groupedBy) {
|
|
33912
|
+
backupReader.groupBy(...this.groupedBy);
|
|
33913
|
+
}
|
|
33914
|
+
if (this.sort) {
|
|
33915
|
+
backupReader.orderBy(...this.sort);
|
|
33916
|
+
}
|
|
33917
|
+
if (this.startIndex !== null && this.count !== null) {
|
|
33918
|
+
backupReader.limit(this.startIndex, this.count);
|
|
33919
|
+
}
|
|
33920
|
+
return backupReader.read();
|
|
33359
33921
|
}
|
|
33360
|
-
const asJson =
|
|
33922
|
+
const asJson = endpoint.supportsJson(featureType.name);
|
|
33361
33923
|
const attributes = this.selected ?? undefined;
|
|
33362
|
-
let
|
|
33924
|
+
let sortBy = null;
|
|
33925
|
+
if (this.sort) {
|
|
33926
|
+
const mapSort = (s) => [s[0] === 'desc' ? 'D' : 'A', s[1]];
|
|
33927
|
+
sortBy = Array.isArray(this.sort[0])
|
|
33928
|
+
? this.sort.map(mapSort)
|
|
33929
|
+
: mapSort(this.sort);
|
|
33930
|
+
}
|
|
33931
|
+
const url = endpoint.getFeatureUrl(featureType.name, {
|
|
33363
33932
|
...(this.startIndex !== null && { startIndex: this.startIndex }),
|
|
33364
33933
|
...(this.count !== null && { maxFeatures: this.count }),
|
|
33365
33934
|
asJson,
|
|
33366
33935
|
outputCrs: 'EPSG:4326',
|
|
33367
33936
|
attributes,
|
|
33368
|
-
|
|
33937
|
+
sortBy,
|
|
33369
33938
|
});
|
|
33370
|
-
|
|
33371
|
-
const finalUrl = new URL(url);
|
|
33372
|
-
const sorts = this.sort
|
|
33373
|
-
.map((fieldSort) => `${fieldSort[1]}+${fieldSort[0] === 'asc' ? 'A' : 'D'}`)
|
|
33374
|
-
.join(',');
|
|
33375
|
-
// Direct update on string url to prevent encoding of +A and +D
|
|
33376
|
-
url = `${url}${finalUrl.search ? '&' : ''}SORTBY=${sorts}`;
|
|
33377
|
-
}
|
|
33378
|
-
return fetchDataAsText(url, this.cacheActive).then((text) => asJson
|
|
33939
|
+
return fetchDataAsText(url, this.cacheEnabled).then((text) => asJson
|
|
33379
33940
|
? parseGeojson(text)
|
|
33380
|
-
: parseGml(text,
|
|
33381
|
-
}
|
|
33382
|
-
async getQueryData() {
|
|
33383
|
-
const items = (await this.getData()).items;
|
|
33384
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33385
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33386
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33387
|
-
return result.map(jsonToGeojsonFeature);
|
|
33388
|
-
}
|
|
33389
|
-
load() {
|
|
33390
|
-
// Nothing to load for Wfs
|
|
33391
|
-
}
|
|
33392
|
-
async read() {
|
|
33393
|
-
return (await this.getData(this.aggregations, this.groupedBy)).items;
|
|
33941
|
+
: parseGml(text, featureType.name, endpoint.getVersion()));
|
|
33394
33942
|
}
|
|
33395
33943
|
}
|
|
33396
33944
|
|
|
33397
|
-
async function openDataset(url,
|
|
33398
|
-
const fileType = await inferDatasetType(url, typeHint);
|
|
33945
|
+
async function openDataset(url, options) {
|
|
33946
|
+
const fileType = await inferDatasetType(url, options?.typeHint);
|
|
33399
33947
|
let reader;
|
|
33400
33948
|
try {
|
|
33401
33949
|
switch (fileType) {
|
|
@@ -33412,18 +33960,18 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33412
33960
|
reader = new ExcelReader(url);
|
|
33413
33961
|
break;
|
|
33414
33962
|
case 'gml':
|
|
33415
|
-
reader = new GmlReader(url
|
|
33963
|
+
reader = new GmlReader(url);
|
|
33416
33964
|
break;
|
|
33417
33965
|
case 'wfs':
|
|
33418
|
-
reader =
|
|
33966
|
+
reader = new WfsReader(url, options?.wfsFeatureType);
|
|
33419
33967
|
break;
|
|
33420
33968
|
}
|
|
33421
|
-
reader.
|
|
33969
|
+
reader.enableCache(options?.enableCache ?? true);
|
|
33422
33970
|
reader.load();
|
|
33423
33971
|
return reader;
|
|
33424
33972
|
}
|
|
33425
33973
|
catch (e) {
|
|
33426
|
-
//WfsReader may already raise a FetchError
|
|
33974
|
+
// WfsReader may already raise a FetchError
|
|
33427
33975
|
if (e instanceof FetchError)
|
|
33428
33976
|
throw e;
|
|
33429
33977
|
else
|
|
@@ -33434,13 +33982,13 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33434
33982
|
* This fetches the full dataset at the given URL and parses it according to its mime type.
|
|
33435
33983
|
* All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
|
|
33436
33984
|
* File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
|
|
33437
|
-
* File type is determined
|
|
33985
|
+
* File type is determined like so:
|
|
33438
33986
|
* 1. if a type hint is given, use it
|
|
33439
33987
|
* 2. otherwise, look for a Content-Type header in the response with a supported mime type
|
|
33440
33988
|
* 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
|
|
33441
33989
|
*/
|
|
33442
|
-
async function readDataset(url,
|
|
33443
|
-
const reader = await openDataset(url,
|
|
33990
|
+
async function readDataset(url, options) {
|
|
33991
|
+
const reader = await openDataset(url, options);
|
|
33444
33992
|
try {
|
|
33445
33993
|
return await reader.read();
|
|
33446
33994
|
}
|
|
@@ -33671,9 +34219,11 @@ class DataService {
|
|
|
33671
34219
|
getDataset(link, cacheActive) {
|
|
33672
34220
|
if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
|
|
33673
34221
|
const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString());
|
|
33674
|
-
return from(openDataset(wfsUrlEndpoint,
|
|
34222
|
+
return from(openDataset(wfsUrlEndpoint, {
|
|
34223
|
+
typeHint: 'wfs',
|
|
33675
34224
|
wfsFeatureType: link.name,
|
|
33676
|
-
|
|
34225
|
+
enableCache: cacheActive,
|
|
34226
|
+
}));
|
|
33677
34227
|
}
|
|
33678
34228
|
else if (link.type === 'download') {
|
|
33679
34229
|
const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString());
|
|
@@ -33681,12 +34231,15 @@ class DataService {
|
|
|
33681
34231
|
const supportedType = SupportedTypes.indexOf(format) > -1
|
|
33682
34232
|
? format
|
|
33683
34233
|
: undefined;
|
|
33684
|
-
return from(openDataset(linkProxifiedUrl,
|
|
34234
|
+
return from(openDataset(linkProxifiedUrl, {
|
|
34235
|
+
typeHint: supportedType,
|
|
34236
|
+
enableCache: cacheActive,
|
|
34237
|
+
})).pipe();
|
|
33685
34238
|
}
|
|
33686
34239
|
else if (link.type === 'service' &&
|
|
33687
34240
|
link.accessServiceProtocol === 'esriRest') {
|
|
33688
34241
|
const url = this.getDownloadUrlFromEsriRest(link.url.toString(), 'geojson');
|
|
33689
|
-
return from(openDataset(url, 'geojson',
|
|
34242
|
+
return from(openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })).pipe();
|
|
33690
34243
|
}
|
|
33691
34244
|
else if (link.type === 'service' &&
|
|
33692
34245
|
link.accessServiceProtocol === 'ogcFeatures') {
|
|
@@ -33700,7 +34253,10 @@ class DataService {
|
|
|
33700
34253
|
}
|
|
33701
34254
|
const urlWithoutLimit = new URL(geojsonUrl);
|
|
33702
34255
|
urlWithoutLimit.searchParams.delete('limit');
|
|
33703
|
-
return openDataset(urlWithoutLimit.toString(),
|
|
34256
|
+
return openDataset(urlWithoutLimit.toString(), {
|
|
34257
|
+
typeHint: 'geojson',
|
|
34258
|
+
enableCache: cacheActive,
|
|
34259
|
+
});
|
|
33704
34260
|
}));
|
|
33705
34261
|
}
|
|
33706
34262
|
return throwError(() => 'protocol not supported');
|
|
@@ -33952,20 +34508,31 @@ class DataTableComponent {
|
|
|
33952
34508
|
this.eltRef = inject(ElementRef);
|
|
33953
34509
|
this.cdr = inject(ChangeDetectorRef);
|
|
33954
34510
|
this.translateService = inject(TranslateService);
|
|
33955
|
-
this.
|
|
34511
|
+
this.columnsFromFeatureCatalog = null;
|
|
34512
|
+
this.columnsFromDataset = [];
|
|
33956
34513
|
this.selected = new EventEmitter();
|
|
33957
|
-
this.properties$ = new BehaviorSubject(null);
|
|
33958
34514
|
this.loading$ = new BehaviorSubject(false);
|
|
33959
34515
|
this.error = null;
|
|
33960
34516
|
}
|
|
33961
34517
|
set featureAttributes(value) {
|
|
33962
|
-
this.
|
|
33963
|
-
|
|
34518
|
+
this.columnsFromFeatureCatalog = value.map((attrs) => ({
|
|
34519
|
+
name: attrs.value,
|
|
34520
|
+
label: attrs.label,
|
|
34521
|
+
}));
|
|
33964
34522
|
}
|
|
33965
34523
|
set dataset(value) {
|
|
33966
34524
|
this.dataset_ = value;
|
|
33967
34525
|
this.dataset_.load();
|
|
33968
|
-
this.dataset_.info.then((info) =>
|
|
34526
|
+
this.dataset_.info.then((info) => {
|
|
34527
|
+
this.count = info.itemsCount;
|
|
34528
|
+
this.cdr.detectChanges();
|
|
34529
|
+
});
|
|
34530
|
+
}
|
|
34531
|
+
get columns() {
|
|
34532
|
+
return this.columnsFromFeatureCatalog ?? this.columnsFromDataset;
|
|
34533
|
+
}
|
|
34534
|
+
get columnNames() {
|
|
34535
|
+
return this.columns.map((c) => c.name);
|
|
33969
34536
|
}
|
|
33970
34537
|
ngOnInit() {
|
|
33971
34538
|
this.dataSource = new DataTableDataSource();
|
|
@@ -34000,11 +34567,12 @@ class DataTableComponent {
|
|
|
34000
34567
|
}
|
|
34001
34568
|
async readData() {
|
|
34002
34569
|
this.loading$.next(true);
|
|
34003
|
-
// wait for properties to be read
|
|
34004
|
-
const properties = await firstValueFrom(this.properties$.pipe(filter((p) => !!p)));
|
|
34005
|
-
const propsWithoutGeom = properties.filter((p) => !p.toLowerCase().startsWith('geom'));
|
|
34006
|
-
this.dataset_.select(...propsWithoutGeom);
|
|
34007
34570
|
try {
|
|
34571
|
+
// wait for properties to be read
|
|
34572
|
+
if (!this.columnsFromFeatureCatalog) {
|
|
34573
|
+
this.columnsFromDataset = await this.dataset_.properties;
|
|
34574
|
+
}
|
|
34575
|
+
this.dataset_.select(...this.columnNames);
|
|
34008
34576
|
await this.dataSource.showData(this.dataset_.read());
|
|
34009
34577
|
this.error = null;
|
|
34010
34578
|
}
|
|
@@ -34034,7 +34602,7 @@ class DataTableComponent {
|
|
|
34034
34602
|
}
|
|
34035
34603
|
}
|
|
34036
34604
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34037
|
-
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
|
|
34605
|
+
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 }); }
|
|
34038
34606
|
}
|
|
34039
34607
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
34040
34608
|
type: Component,
|
|
@@ -34046,10 +34614,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
34046
34614
|
CommonModule,
|
|
34047
34615
|
LoadingMaskComponent,
|
|
34048
34616
|
PopupAlertComponent,
|
|
34049
|
-
LetDirective,
|
|
34050
34617
|
TranslatePipe,
|
|
34051
34618
|
TranslateDirective,
|
|
34052
|
-
], 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
|
|
34619
|
+
], 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"] }]
|
|
34053
34620
|
}], propDecorators: { featureAttributes: [{
|
|
34054
34621
|
type: Input
|
|
34055
34622
|
}], dataset: [{
|
|
@@ -34152,7 +34719,7 @@ class ChartViewComponent {
|
|
|
34152
34719
|
}), shareReplay$1(1));
|
|
34153
34720
|
this.properties$ = combineLatest([this.dataset$, this.featureCatalog$]).pipe(switchMap$1(([dataset, catalog]) => this.setProperties(dataset, catalog)), shareReplay$1(1));
|
|
34154
34721
|
this.yChoices$ = this.properties$.pipe(map$1((properties) => properties
|
|
34155
|
-
.filter((prop) => prop.type === 'number'
|
|
34722
|
+
.filter((prop) => prop.type === 'number')
|
|
34156
34723
|
.map((prop) => ({ value: prop.name, label: prop.label || prop.name }))), tap$1((choices) => {
|
|
34157
34724
|
if (!choices.find((choice) => choice.value === this.yProperty$.value)) {
|
|
34158
34725
|
const newProp = choices[0]?.value || '';
|
|
@@ -34179,6 +34746,7 @@ class ChartViewComponent {
|
|
|
34179
34746
|
this.aggregation$,
|
|
34180
34747
|
]).pipe(filter$1(([_, x, y]) => !!x || !!y), switchMap$1(([dataset, xProp, yProp, aggregation]) => {
|
|
34181
34748
|
const fieldAgg = aggregation === 'count' ? ['count'] : [aggregation, yProp];
|
|
34749
|
+
this.loading = true;
|
|
34182
34750
|
return dataset
|
|
34183
34751
|
.groupBy(['distinct', xProp])
|
|
34184
34752
|
.aggregate(fieldAgg)
|
|
@@ -34420,6 +34988,7 @@ class GeoTableViewComponent {
|
|
|
34420
34988
|
}));
|
|
34421
34989
|
}
|
|
34422
34990
|
async initMapContext() {
|
|
34991
|
+
this.dataset.load();
|
|
34423
34992
|
this.dataset.selectAll();
|
|
34424
34993
|
return {
|
|
34425
34994
|
layers: [
|
|
@@ -34593,8 +35162,7 @@ class MdViewFacade {
|
|
|
34593
35162
|
}));
|
|
34594
35163
|
this.error$ = this.store.pipe(select(getMetadataError));
|
|
34595
35164
|
this.related$ = this.store.pipe(select(getRelated));
|
|
34596
|
-
this.
|
|
34597
|
-
this.sourceOf$ = this.store.pipe(select(getSourceOf));
|
|
35165
|
+
this.linkedRecords$ = this.store.pipe(select(getLinkedRecords));
|
|
34598
35166
|
this.chartConfig$ = this.store.pipe(select(getChartConfig));
|
|
34599
35167
|
this.allLinks$ = this.metadata$.pipe(map$1((record) => 'onlineResources' in record ? record.onlineResources : []), shareReplay$1(1));
|
|
34600
35168
|
this.resourceDoi$ = this.metadata$.pipe(map$1((record) => {
|
|
@@ -34713,12 +35281,9 @@ class MdViewEffects {
|
|
|
34713
35281
|
this.loadRelatedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSimilarRecords(full)), map$1((related) => {
|
|
34714
35282
|
return setRelated({ related });
|
|
34715
35283
|
}), catchError(() => of(setRelated({ related: null })))));
|
|
34716
|
-
this.
|
|
34717
|
-
return
|
|
34718
|
-
}), catchError(() => of(
|
|
34719
|
-
this.loadSourceOf$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSourceOf(full)), map$1((sourceOf) => {
|
|
34720
|
-
return setSourceOf({ sourceOf });
|
|
34721
|
-
}), catchError(() => of(setSourceOf({ sourceOf: null })))));
|
|
35284
|
+
this.loadLinkedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getLinkedRecords(full)), map$1((linkedRecords) => {
|
|
35285
|
+
return setLinkedRecords({ linkedRecords });
|
|
35286
|
+
}), catchError(() => of(setLinkedRecords({ linkedRecords: null })))));
|
|
34722
35287
|
/*
|
|
34723
35288
|
UserFeedback effects
|
|
34724
35289
|
*/
|
|
@@ -36452,6 +37017,11 @@ const DEFAULT_CONFIGURATION = {
|
|
|
36452
37017
|
},
|
|
36453
37018
|
hidden: '${record.kind == "service"}',
|
|
36454
37019
|
},
|
|
37020
|
+
{
|
|
37021
|
+
model: 'associatedRecords',
|
|
37022
|
+
formFieldConfig: {},
|
|
37023
|
+
hidden: '${record.kind == "service"}',
|
|
37024
|
+
},
|
|
36455
37025
|
],
|
|
36456
37026
|
},
|
|
36457
37027
|
// Section: Geographical coverage
|
|
@@ -37589,7 +38159,7 @@ class FormFieldTemporalExtentsComponent {
|
|
|
37589
38159
|
provideNgIconsConfig({
|
|
37590
38160
|
size: '1.5rem',
|
|
37591
38161
|
}),
|
|
37592
|
-
], ngImport: i0, template: "<div class=\"flex gap-2
|
|
38162
|
+
], ngImport: i0, template: "<div class=\"flex flex-col gap-2\">\n <div class=\"flex gap-2\">\n @for (addOption of addOptions$ | async; track addOption) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"onAdd(addOption.eventName)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon> {{\n addOption.buttonLabel\n }}</gn-ui-button\n >\n }\n </div>\n @if (extents.length) {\n <gn-ui-sortable-list\n [items]=\"extents\"\n (itemsOrderChange)=\"onItemsOrderChange($event)\"\n [elementTemplate]=\"template\"\n ></gn-ui-sortable-list>\n }\n</div>\n<ng-template #template let-extent let-index=\"index\">\n @if (extent.end === undefined) {\n <div class=\"border rounded-lg px-4 pb-4\">\n <p class=\"my-2\" translate>editor.record.form.temporalExtents.date</p>\n <gn-ui-date-picker\n [date]=\"extent.start\"\n (dateChange)=\"onExtentChange({ start: $event }, index)\"\n ></gn-ui-date-picker>\n </div>\n }\n @if (extent.end !== undefined) {\n <div class=\"border rounded-lg px-4 pb-4\">\n <p class=\"my-2\" translate>editor.record.form.temporalExtents.range</p>\n <gn-ui-date-range-picker\n [startDate]=\"extent.start\"\n [endDate]=\"extent.end\"\n (startDateChange)=\"onExtentChange({ start: $event }, index)\"\n (endDateChange)=\"onExtentChange({ end: $event }, index)\"\n ></gn-ui-date-range-picker>\n </div>\n }\n</ng-template>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: DatePickerComponent, selector: "gn-ui-date-picker", inputs: ["date"], outputs: ["dateChange"] }, { kind: "component", type: DateRangePickerComponent, selector: "gn-ui-date-range-picker", inputs: ["startDate", "endDate"], outputs: ["startDateChange", "endDateChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { 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 }); }
|
|
37593
38163
|
}
|
|
37594
38164
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldTemporalExtentsComponent, decorators: [{
|
|
37595
38165
|
type: Component,
|
|
@@ -37606,7 +38176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37606
38176
|
provideNgIconsConfig({
|
|
37607
38177
|
size: '1.5rem',
|
|
37608
38178
|
}),
|
|
37609
|
-
], template: "<div class=\"flex gap-2
|
|
38179
|
+
], template: "<div class=\"flex flex-col gap-2\">\n <div class=\"flex gap-2\">\n @for (addOption of addOptions$ | async; track addOption) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"onAdd(addOption.eventName)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon> {{\n addOption.buttonLabel\n }}</gn-ui-button\n >\n }\n </div>\n @if (extents.length) {\n <gn-ui-sortable-list\n [items]=\"extents\"\n (itemsOrderChange)=\"onItemsOrderChange($event)\"\n [elementTemplate]=\"template\"\n ></gn-ui-sortable-list>\n }\n</div>\n<ng-template #template let-extent let-index=\"index\">\n @if (extent.end === undefined) {\n <div class=\"border rounded-lg px-4 pb-4\">\n <p class=\"my-2\" translate>editor.record.form.temporalExtents.date</p>\n <gn-ui-date-picker\n [date]=\"extent.start\"\n (dateChange)=\"onExtentChange({ start: $event }, index)\"\n ></gn-ui-date-picker>\n </div>\n }\n @if (extent.end !== undefined) {\n <div class=\"border rounded-lg px-4 pb-4\">\n <p class=\"my-2\" translate>editor.record.form.temporalExtents.range</p>\n <gn-ui-date-range-picker\n [startDate]=\"extent.start\"\n [endDate]=\"extent.end\"\n (startDateChange)=\"onExtentChange({ start: $event }, index)\"\n (endDateChange)=\"onExtentChange({ end: $event }, index)\"\n ></gn-ui-date-range-picker>\n </div>\n }\n</ng-template>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"] }]
|
|
37610
38180
|
}], propDecorators: { value: [{
|
|
37611
38181
|
type: Input
|
|
37612
38182
|
}], valueChange: [{
|
|
@@ -37822,6 +38392,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37822
38392
|
], template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-generic-keywords\n [placeholder]=\"'editor.record.form.keywords.place.placeholder' | translate\"\n [keywords]=\"shownKeywords$ | async\"\n [keywordTypes]=\"['place']\"\n (deletedKeyword)=\"handleKeywordDelete($event)\"\n (addedKeyword)=\"handleKeywordAdd($event)\"\n >\n </gn-ui-generic-keywords>\n <div class=\"w-full h-96 mt-2\">\n <gn-ui-spatial-extent\n [spatialExtents]=\"spatialExtents$ | async\"\n ></gn-ui-spatial-extent>\n </div>\n</div>\n" }]
|
|
37823
38393
|
}] });
|
|
37824
38394
|
|
|
38395
|
+
class FormFieldAssociatedRecordsComponent {
|
|
38396
|
+
constructor() {
|
|
38397
|
+
this.valueChange = new EventEmitter();
|
|
38398
|
+
}
|
|
38399
|
+
get list() {
|
|
38400
|
+
return this.value ?? [];
|
|
38401
|
+
}
|
|
38402
|
+
get first() {
|
|
38403
|
+
return this.list[0];
|
|
38404
|
+
}
|
|
38405
|
+
get rest() {
|
|
38406
|
+
return this.list.slice(1);
|
|
38407
|
+
}
|
|
38408
|
+
get hasParentLink() {
|
|
38409
|
+
return this.list.length > 0;
|
|
38410
|
+
}
|
|
38411
|
+
get uniqueIdentifier() {
|
|
38412
|
+
return this.first?.uniqueIdentifier ?? '';
|
|
38413
|
+
}
|
|
38414
|
+
get selectedType() {
|
|
38415
|
+
return this.first?.associationType;
|
|
38416
|
+
}
|
|
38417
|
+
get choices() {
|
|
38418
|
+
return associationTypeValues.map((value) => ({
|
|
38419
|
+
value,
|
|
38420
|
+
label: `domain.record.associationType.${value}`,
|
|
38421
|
+
}));
|
|
38422
|
+
}
|
|
38423
|
+
onToggle(checked) {
|
|
38424
|
+
this.valueChange.emit(checked
|
|
38425
|
+
? [
|
|
38426
|
+
{
|
|
38427
|
+
uniqueIdentifier: '',
|
|
38428
|
+
associationType: associationTypeValues[0],
|
|
38429
|
+
},
|
|
38430
|
+
...this.rest,
|
|
38431
|
+
]
|
|
38432
|
+
: this.rest);
|
|
38433
|
+
}
|
|
38434
|
+
onUniqueIdentifierChange(uniqueIdentifier) {
|
|
38435
|
+
this.valueChange.emit(uniqueIdentifier
|
|
38436
|
+
? [{ ...this.first, uniqueIdentifier }, ...this.rest]
|
|
38437
|
+
: this.rest);
|
|
38438
|
+
}
|
|
38439
|
+
onTypeChange(associationType) {
|
|
38440
|
+
this.valueChange.emit([
|
|
38441
|
+
{ ...this.first, associationType: associationType },
|
|
38442
|
+
...this.rest,
|
|
38443
|
+
]);
|
|
38444
|
+
}
|
|
38445
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38446
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldAssociatedRecordsComponent, isStandalone: true, selector: "gn-ui-form-field-associated-records", inputs: { value: "value" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"flex flex-col gap-2\">\n <gn-ui-check-toggle\n [label]=\"'editor.record.form.field.parentLink' | translate\"\n [value]=\"hasParentLink\"\n (toggled)=\"onToggle($event)\"\n data-cy=\"associated-record-toggle\"\n ></gn-ui-check-toggle>\n @if (hasParentLink) {\n <gn-ui-form-field-wrapper\n [label]=\"'editor.record.form.field.parentIdentifier' | translate\"\n >\n <gn-ui-text-input\n [value]=\"uniqueIdentifier\"\n (valueChange)=\"onUniqueIdentifierChange($event)\"\n placeholder=\"\"\n data-cy=\"associated-record-identifier\"\n ></gn-ui-text-input>\n </gn-ui-form-field-wrapper>\n <gn-ui-form-field-wrapper\n [label]=\"'editor.record.form.field.parentType' | translate\"\n >\n <gn-ui-dropdown-selector\n [title]=\"'editor.record.form.field.parentType' | translate\"\n [showTitle]=\"false\"\n [choices]=\"choices\"\n [selected]=\"selectedType\"\n (selectValue)=\"onTypeChange($event)\"\n [extraBtnClass]=\"'input-as-button gn-ui-text-input'\"\n data-cy=\"associated-record-type\"\n ></gn-ui-dropdown-selector>\n </gn-ui-form-field-wrapper>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: CheckToggleComponent, selector: "gn-ui-check-toggle", inputs: ["title", "label", "value", "color"], outputs: ["toggled"] }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "component", type: DropdownSelectorComponent, selector: "gn-ui-dropdown-selector", inputs: ["title", "showTitle", "ariaName", "choices", "selected", "maxRows", "extraBtnClass", "minWidth", "disabled"], outputs: ["selectValue"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
38447
|
+
}
|
|
38448
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, decorators: [{
|
|
38449
|
+
type: Component,
|
|
38450
|
+
args: [{ selector: 'gn-ui-form-field-associated-records', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
38451
|
+
CheckToggleComponent,
|
|
38452
|
+
TextInputComponent,
|
|
38453
|
+
DropdownSelectorComponent,
|
|
38454
|
+
FormFieldWrapperComponent,
|
|
38455
|
+
TranslatePipe,
|
|
38456
|
+
], template: "<div class=\"flex flex-col gap-2\">\n <gn-ui-check-toggle\n [label]=\"'editor.record.form.field.parentLink' | translate\"\n [value]=\"hasParentLink\"\n (toggled)=\"onToggle($event)\"\n data-cy=\"associated-record-toggle\"\n ></gn-ui-check-toggle>\n @if (hasParentLink) {\n <gn-ui-form-field-wrapper\n [label]=\"'editor.record.form.field.parentIdentifier' | translate\"\n >\n <gn-ui-text-input\n [value]=\"uniqueIdentifier\"\n (valueChange)=\"onUniqueIdentifierChange($event)\"\n placeholder=\"\"\n data-cy=\"associated-record-identifier\"\n ></gn-ui-text-input>\n </gn-ui-form-field-wrapper>\n <gn-ui-form-field-wrapper\n [label]=\"'editor.record.form.field.parentType' | translate\"\n >\n <gn-ui-dropdown-selector\n [title]=\"'editor.record.form.field.parentType' | translate\"\n [showTitle]=\"false\"\n [choices]=\"choices\"\n [selected]=\"selectedType\"\n (selectValue)=\"onTypeChange($event)\"\n [extraBtnClass]=\"'input-as-button gn-ui-text-input'\"\n data-cy=\"associated-record-type\"\n ></gn-ui-dropdown-selector>\n </gn-ui-form-field-wrapper>\n }\n</div>\n" }]
|
|
38457
|
+
}], propDecorators: { value: [{
|
|
38458
|
+
type: Input
|
|
38459
|
+
}], valueChange: [{
|
|
38460
|
+
type: Output
|
|
38461
|
+
}] } });
|
|
38462
|
+
|
|
37825
38463
|
class ContactCardComponent {
|
|
37826
38464
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37827
38465
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: ContactCardComponent, isStandalone: true, selector: "gn-ui-contact-card", inputs: { contact: "contact" }, ngImport: i0, template: "<div class=\"gn-ui-card\">\n <gn-ui-thumbnail\n class=\"w-[56px] h-[56px] rounded-[4px] overflow-hidden shrink-0\"\n [thumbnailUrl]=\"contact.organization?.logoUrl?.href\"\n [fit]=\"'contain'\"\n ></gn-ui-thumbnail>\n <div class=\"flex flex-col w-full overflow-hidden leading-snug justify-center\">\n <div class=\"text-[16px] font-bold text-main\" data-test=\"contactCardName\">\n {{ contact.firstName }} {{ contact.lastName }}\n </div>\n <div class=\"text-[14px] text-gray-900\" data-test=\"contactCardEmail\">\n {{ contact.email }}\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: ThumbnailComponent, selector: "gn-ui-thumbnail", inputs: ["thumbnailUrl", "fit"], outputs: ["placeholderShown"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
@@ -39207,6 +39845,9 @@ class FormFieldComponent {
|
|
|
39207
39845
|
get valueAsUpdateFrequency() {
|
|
39208
39846
|
return this.value;
|
|
39209
39847
|
}
|
|
39848
|
+
get valueAsAssociatedRecords() {
|
|
39849
|
+
return this.value;
|
|
39850
|
+
}
|
|
39210
39851
|
get valueAsTemporalExtents() {
|
|
39211
39852
|
return this.value;
|
|
39212
39853
|
}
|
|
@@ -39246,7 +39887,7 @@ class FormFieldComponent {
|
|
|
39246
39887
|
}
|
|
39247
39888
|
}
|
|
39248
39889
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39249
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FormFieldComponent, isStandalone: true, selector: "gn-ui-form-field", inputs: { uniqueIdentifier: "uniqueIdentifier", recordKind: "recordKind", model: "model", modelSpecifier: "modelSpecifier", componentName: "componentName", config: "config", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [provideIcons({ matEditOutline, matHelpOutline })], viewQueries: [{ propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }], hostDirectives: [{ directive: FieldFocusDirective }], ngImport: i0, template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "component", type: FormFieldLicenseComponent, selector: "gn-ui-form-field-license", inputs: ["label", "recordLicences"], outputs: ["recordLicencesChange"] }, { kind: "component", type: FormFieldDateComponent, selector: "gn-ui-form-field-date", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldUpdateFrequencyComponent, selector: "gn-ui-form-field-update-frequency", inputs: ["value", "recordKind"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldTemporalExtentsComponent, selector: "gn-ui-form-field-temporal-extents", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSimpleComponent, selector: "gn-ui-form-field-simple", inputs: ["type", "readonly", "invalid", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldRichComponent, selector: "gn-ui-form-field-rich", inputs: ["label", "hint", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSpatialExtentComponent, selector: "gn-ui-form-field-spatial-extent" }, { kind: "component", type: FormFieldKeywordsComponent, selector: "gn-ui-form-field-keywords", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOverviewsComponent, selector: "gn-ui-form-field-overviews", inputs: ["metadataUuid", "recordKind", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsForResourceComponent, selector: "gn-ui-form-field-contacts-for-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineResourcesComponent, selector: "gn-ui-form-field-online-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineLinkResourcesComponent, selector: "gn-ui-form-field-online-link-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineSingleLinkResourceComponent, selector: "gn-ui-form-field-online-single-link-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsComponent, selector: "gn-ui-form-field-contacts", inputs: ["value", "modelSpecifier"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsComponent, selector: "gn-ui-form-field-constraints", inputs: ["label", "value", "constraintType"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsShortcutsComponent, selector: "gn-ui-form-field-constraints-shortcuts" }, { kind: "component", type: FormFieldSpatialToggleComponent, selector: "gn-ui-form-field-spatial-toggle" }, { kind: "component", type: FormFieldTopicsComponent, selector: "gn-ui-form-field-topics", inputs: ["value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i4$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
39890
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FormFieldComponent, isStandalone: true, selector: "gn-ui-form-field", inputs: { uniqueIdentifier: "uniqueIdentifier", recordKind: "recordKind", model: "model", modelSpecifier: "modelSpecifier", componentName: "componentName", config: "config", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [provideIcons({ matEditOutline, matHelpOutline })], viewQueries: [{ propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }], hostDirectives: [{ directive: FieldFocusDirective }], ngImport: i0, template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "component", type: FormFieldLicenseComponent, selector: "gn-ui-form-field-license", inputs: ["label", "recordLicences"], outputs: ["recordLicencesChange"] }, { kind: "component", type: FormFieldDateComponent, selector: "gn-ui-form-field-date", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldUpdateFrequencyComponent, selector: "gn-ui-form-field-update-frequency", inputs: ["value", "recordKind"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldAssociatedRecordsComponent, selector: "gn-ui-form-field-associated-records", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldTemporalExtentsComponent, selector: "gn-ui-form-field-temporal-extents", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSimpleComponent, selector: "gn-ui-form-field-simple", inputs: ["type", "readonly", "invalid", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldRichComponent, selector: "gn-ui-form-field-rich", inputs: ["label", "hint", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSpatialExtentComponent, selector: "gn-ui-form-field-spatial-extent" }, { kind: "component", type: FormFieldKeywordsComponent, selector: "gn-ui-form-field-keywords", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOverviewsComponent, selector: "gn-ui-form-field-overviews", inputs: ["metadataUuid", "recordKind", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsForResourceComponent, selector: "gn-ui-form-field-contacts-for-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineResourcesComponent, selector: "gn-ui-form-field-online-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineLinkResourcesComponent, selector: "gn-ui-form-field-online-link-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineSingleLinkResourceComponent, selector: "gn-ui-form-field-online-single-link-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsComponent, selector: "gn-ui-form-field-contacts", inputs: ["value", "modelSpecifier"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsComponent, selector: "gn-ui-form-field-constraints", inputs: ["label", "value", "constraintType"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsShortcutsComponent, selector: "gn-ui-form-field-constraints-shortcuts" }, { kind: "component", type: FormFieldSpatialToggleComponent, selector: "gn-ui-form-field-spatial-toggle" }, { kind: "component", type: FormFieldTopicsComponent, selector: "gn-ui-form-field-topics", inputs: ["value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i4$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
39250
39891
|
}
|
|
39251
39892
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
39252
39893
|
type: Component,
|
|
@@ -39258,6 +39899,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39258
39899
|
FormFieldLicenseComponent,
|
|
39259
39900
|
FormFieldDateComponent,
|
|
39260
39901
|
FormFieldUpdateFrequencyComponent,
|
|
39902
|
+
FormFieldAssociatedRecordsComponent,
|
|
39261
39903
|
FormFieldTemporalExtentsComponent,
|
|
39262
39904
|
FormFieldSimpleComponent,
|
|
39263
39905
|
FormFieldRichComponent,
|
|
@@ -39275,7 +39917,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39275
39917
|
FormFieldTopicsComponent,
|
|
39276
39918
|
TextFieldModule,
|
|
39277
39919
|
NgIconComponent,
|
|
39278
|
-
], providers: [provideIcons({ matEditOutline, matHelpOutline })], hostDirectives: [FieldFocusDirective], template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"] }]
|
|
39920
|
+
], providers: [provideIcons({ matEditOutline, matHelpOutline })], hostDirectives: [FieldFocusDirective], template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"] }]
|
|
39279
39921
|
}], propDecorators: { uniqueIdentifier: [{
|
|
39280
39922
|
type: Input
|
|
39281
39923
|
}], recordKind: [{
|
|
@@ -39860,7 +40502,7 @@ class RouterService {
|
|
|
39860
40502
|
return ROUTER_ROUTE_ORGANIZATION;
|
|
39861
40503
|
}
|
|
39862
40504
|
getDefaultSort() {
|
|
39863
|
-
return SortByEnum.
|
|
40505
|
+
return SortByEnum.RESOURCE_DATE;
|
|
39864
40506
|
}
|
|
39865
40507
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39866
40508
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, providedIn: 'root' }); }
|
|
@@ -39920,7 +40562,7 @@ function flattenQueryParams(params) {
|
|
|
39920
40562
|
const start = flattened[key].start;
|
|
39921
40563
|
const end = flattened[key].end;
|
|
39922
40564
|
flattened[key] = [
|
|
39923
|
-
`${start ? formatDate(start) : ''}..${formatDate(end)
|
|
40565
|
+
`${start ? formatDate(start) : ''}..${end ? formatDate(end) : ''}`,
|
|
39924
40566
|
];
|
|
39925
40567
|
}
|
|
39926
40568
|
}
|
|
@@ -40277,5 +40919,5 @@ const CHART_TYPE_VALUES = [
|
|
|
40277
40919
|
* Generated bundle index. Do not edit.
|
|
40278
40920
|
*/
|
|
40279
40921
|
|
|
40280
|
-
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 };
|
|
40922
|
+
export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingComponent, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, defaultMapStyleFixture, defaultMapStyleHlFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
|
|
40281
40923
|
//# sourceMappingURL=geonetwork-ui.mjs.map
|