geonetwork-ui 2.11.0-dev.a2881de31 → 2.11.0-dev.a63e6e32a
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 +1667 -991
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +300 -129
- package/index.d.ts.map +1 -1
- package/package.json +12 -11
- package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +5 -5
- package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +5 -5
- 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/metadata-converter/src/lib/iso19115-3/write-parts.ts +2 -2
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +9 -5
- package/src/libs/api/metadata-converter/src/lib/iso19139/utils/association-type.mapper.ts +12 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +2 -2
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +130 -37
- 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 +40 -2
- package/src/libs/common/domain/src/lib/model/search/filter.model.ts +20 -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.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/index.ts +0 -1
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +1 -0
- package/src/libs/feature/map/src/lib/feature-map.module.ts +1 -8
- package/src/libs/feature/notifications/src/lib/notifications.service.ts +6 -4
- package/src/libs/feature/record/src/lib/state/mdview.actions.ts +4 -8
- package/src/libs/feature/record/src/lib/state/mdview.effects.ts +7 -16
- package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -3
- package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +4 -9
- package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +2 -7
- package/src/libs/feature/router/src/lib/default/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/index.ts +2 -0
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +12 -4
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +58 -19
- package/src/libs/feature/{map/src/lib → search/src/lib/geocoding}/geocoding.service.ts +5 -1
- package/src/libs/feature/search/src/lib/location-search/location-search.component.html +8 -0
- package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +40 -0
- package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +18 -8
- package/src/libs/feature/search/src/lib/sort-by/sort-by.component.ts +1 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +9 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +61 -2
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +6 -7
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +31 -19
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.ts +2 -2
- package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.ts +2 -1
- package/src/libs/ui/inputs/src/index.ts +2 -0
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +10 -1
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +8 -0
- package/src/libs/ui/inputs/src/lib/date-adapter.providers.ts +30 -0
- package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +3 -24
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.css +37 -3
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.html +135 -16
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.ts +166 -29
- package/src/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.ts +3 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.css +1 -0
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.html +20 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.ts +46 -5
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +7 -4
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +12 -9
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.model.ts +2 -2
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.css +0 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +111 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +215 -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/links/link-utils.ts +19 -10
- package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
- package/src/libs/util/shared/src/lib/utils/file.ts +15 -0
- package/src/libs/util/shared/src/lib/utils/geojson.ts +8 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/tailwind.base.css +5 -0
- package/translations/de.json +30 -4
- package/translations/en.json +29 -3
- package/translations/es.json +27 -1
- package/translations/fr.json +30 -4
- package/translations/it.json +28 -2
- package/translations/nl.json +27 -1
- package/translations/pt.json +27 -1
- package/translations/sk.json +28 -2
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +0 -41
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +0 -112
- package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +0 -14
- /package/src/libs/feature/{map/src/lib/geocoding/geocoding.component.css → editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.css} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { parseXml, XmlDocument, XmlElement, XmlText } from '@rgrove/parse-xml';
|
|
2
2
|
export { XmlDocument, XmlElement } from '@rgrove/parse-xml';
|
|
3
|
+
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
|
|
3
4
|
import GML32 from 'ol/format/GML32.js';
|
|
4
5
|
import GeoJSON from 'ol/format/GeoJSON.js';
|
|
5
6
|
import { parse as parse$1 } from 'ol/xml.js';
|
|
6
|
-
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
|
|
7
7
|
import { format } from 'date-fns/format';
|
|
8
8
|
import { Namespace, Literal, lit, parse as parse$2, sym, BlankNode, graph } from 'rdflib';
|
|
9
|
-
import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, combineLatest, from, exhaustMap, throwError,
|
|
9
|
+
import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, forkJoin, combineLatest, from, exhaustMap, throwError, takeLast, firstValueFrom, merge, BehaviorSubject, timer, ReplaySubject, Subscription, first, distinctUntilChanged as distinctUntilChanged$1, animationFrameScheduler, debounceTime as debounceTime$1, Observable, buffer, tap as tap$2, combineLatestWith, take as take$1, catchError as catchError$1, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1, takeUntil } from 'rxjs';
|
|
10
10
|
import * as i0 from '@angular/core';
|
|
11
|
-
import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef,
|
|
11
|
+
import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef, afterNextRender, booleanAttribute, Input, Directive, HostListener, Renderer2, DestroyRef, EventEmitter, Output, ViewChild, ChangeDetectionStrategy, Component, ViewEncapsulation, ChangeDetectorRef, HostBinding, ViewContainerRef, TemplateRef, ViewChildren, ContentChild, input, output, signal, viewChild, computed, ContentChildren, NgZone, ComponentFactoryResolver, viewChildren } from '@angular/core';
|
|
12
12
|
import { HttpClient, HttpHeaders, HttpParams, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, HttpEventType } from '@angular/common/http';
|
|
13
13
|
import * as i4 from '@ngx-translate/core';
|
|
14
14
|
import { TranslateLoader, TranslateCompiler, TranslateDefaultParser, TranslateParser, TranslateService, provideTranslateService, TranslateDirective, TranslatePipe, TranslateModule } from '@ngx-translate/core';
|
|
@@ -18,7 +18,7 @@ import { map as map$1, shareReplay as shareReplay$1, catchError, tap as tap$1, f
|
|
|
18
18
|
import { lt, valid, coerce, satisfies, ltr } from 'semver';
|
|
19
19
|
import chroma from 'chroma-js';
|
|
20
20
|
import * as i1$1 from '@angular/common';
|
|
21
|
-
import { Location, CommonModule,
|
|
21
|
+
import { Location, CommonModule, NgTemplateOutlet, NgClass, AsyncPipe } from '@angular/common';
|
|
22
22
|
import { formatDistance } from 'date-fns/formatDistance';
|
|
23
23
|
import { Scroll, NavigationEnd, Router, RouteReuseStrategy } from '@angular/router';
|
|
24
24
|
import { WmtsEndpoint, WmsEndpoint, WfsEndpoint, OgcApiEndpoint, sharedFetch, useCache, StacEndpoint, TmsEndpoint } from '@camptocamp/ogc-client';
|
|
@@ -26,7 +26,6 @@ import { getLength } from 'ol/sphere.js';
|
|
|
26
26
|
import { LineString } from 'ol/geom.js';
|
|
27
27
|
import * as i1 from '@ngrx/store';
|
|
28
28
|
import { createAction, props, createReducer, on, createFeatureSelector, createSelector, Store, select, StoreModule } from '@ngrx/store';
|
|
29
|
-
import { queryDataGouvFr, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
|
|
30
29
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
31
30
|
import { FeaturesClickEventType, FeaturesHoverEventType, MapClickEventType, MapExtentChangeEventType, SourceLoadErrorType, computeMapContextDiff, createViewFromLayer } from '@geospatial-sdk/core';
|
|
32
31
|
import { createMapFromContext, applyContextDiffToMap, listen } from '@geospatial-sdk/openlayers';
|
|
@@ -41,10 +40,10 @@ import * as TOML from '@ltd/j-toml';
|
|
|
41
40
|
import { Style, Stroke, Fill, Circle } from 'ol/style.js';
|
|
42
41
|
import CircleStyle from 'ol/style/Circle.js';
|
|
43
42
|
import EmblaCarousel from 'embla-carousel';
|
|
44
|
-
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn,
|
|
43
|
+
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirTrash, iconoirSquareDashed, iconoirImport, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
|
|
45
44
|
import { MatButtonModule } from '@angular/material/button';
|
|
46
|
-
import * as i1$
|
|
47
|
-
import {
|
|
45
|
+
import * as i1$7 from '@angular/cdk/overlay';
|
|
46
|
+
import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
48
47
|
import * as i1$3 from '@angular/forms';
|
|
49
48
|
import { UntypedFormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
50
49
|
import * as i1$2 from '@angular/material/autocomplete';
|
|
@@ -52,16 +51,18 @@ import { MatAutocompleteModule, MatAutocompleteTrigger, MatAutocomplete } from '
|
|
|
52
51
|
import tippy from 'tippy.js';
|
|
53
52
|
import * as i2 from '@angular/material/progress-spinner';
|
|
54
53
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
55
|
-
import { matClose, matContentCopy,
|
|
54
|
+
import { matClose, matContentCopy, matExpandMore, matExpandLess, matSearch, matStarBorder, matStar, matRemove, matAdd, matChevronRight, matChevronLeft, matArrowForwardIos, matArrowBackIos, matMoodBad, matQuestionMark, matFace, matZoomOutMap, matOpenInNew, matPersonOutline, matMailOutline, matWarningAmber, matCheck, matCheckCircleOutline, matWarning, matMoreVert } from '@ng-icons/material-icons/baseline';
|
|
56
55
|
import * as i1$4 from '@angular/material/checkbox';
|
|
57
56
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
58
57
|
import * as i1$5 from '@angular/material/tooltip';
|
|
59
58
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
60
|
-
import {
|
|
59
|
+
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
|
|
60
|
+
import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
|
61
|
+
import { enUS } from 'date-fns/locale/en-US';
|
|
61
62
|
import * as i1$6 from '@angular/material/datepicker';
|
|
62
63
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
63
|
-
import * as i1$
|
|
64
|
-
import { NgxDropzoneModule } from 'ngx-dropzone';
|
|
64
|
+
import * as i1$8 from 'ngx-dropzone';
|
|
65
|
+
import { NgxDropzoneModule, NgxDropzoneComponent } from 'ngx-dropzone';
|
|
65
66
|
import * as i1$9 from '@angular/material/button-toggle';
|
|
66
67
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
67
68
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -72,6 +73,7 @@ import { MatTabsModule } from '@angular/material/tabs';
|
|
|
72
73
|
import * as i2$2 from '@ngrx/effects';
|
|
73
74
|
import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
|
|
74
75
|
import { valid as valid$1 } from 'geojson-validation';
|
|
76
|
+
import { queryDataGouvFr, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
|
|
75
77
|
import { TemplatePortal } from '@angular/cdk/portal';
|
|
76
78
|
import { parse as parse$3 } from 'marked';
|
|
77
79
|
import * as i2$3 from '@angular/cdk/scrolling';
|
|
@@ -79,10 +81,10 @@ import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
|
|
|
79
81
|
import Duration from 'duration-relativetimeformat';
|
|
80
82
|
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
|
|
81
83
|
import { trigger, transition, animate, keyframes, style } from '@angular/animations';
|
|
82
|
-
import * as
|
|
83
|
-
import {
|
|
84
|
-
import
|
|
85
|
-
import
|
|
84
|
+
import * as duckdb from '@duckdb/duckdb-wasm';
|
|
85
|
+
import { Vector, DataType } from 'apache-arrow';
|
|
86
|
+
import WFS from 'ol/format/WFS';
|
|
87
|
+
import GeoJSON$1 from 'ol/format/GeoJSON';
|
|
86
88
|
import { Chart, BarController, BarElement, CategoryScale, LinearScale, LineController, LineElement, PointElement, PieController, ArcElement, ScatterController, Tooltip, Colors, Legend } from 'chart.js';
|
|
87
89
|
import * as i2$4 from '@angular/material/sort';
|
|
88
90
|
import { MatSortModule, MatSort } from '@angular/material/sort';
|
|
@@ -90,7 +92,6 @@ import * as i1$b from '@angular/material/table';
|
|
|
90
92
|
import { MatTableModule } from '@angular/material/table';
|
|
91
93
|
import * as i3 from '@angular/material/paginator';
|
|
92
94
|
import { MatPaginatorIntl, MatPaginatorModule, MatPaginator } from '@angular/material/paginator';
|
|
93
|
-
import { LetDirective } from '@ngrx/component';
|
|
94
95
|
import { Meta } from '@angular/platform-browser';
|
|
95
96
|
import { tablerFolderOpen } from '@ng-icons/tabler-icons';
|
|
96
97
|
import * as i3$1 from '@angular/material/radio';
|
|
@@ -674,6 +675,149 @@ function matchMimeType(format) {
|
|
|
674
675
|
return format || null;
|
|
675
676
|
}
|
|
676
677
|
|
|
678
|
+
const RoleValues = [
|
|
679
|
+
'unspecified',
|
|
680
|
+
'other',
|
|
681
|
+
'author', // Party who authored the resource
|
|
682
|
+
'collaborator', // party who assists with the generation of the resource other than the principal investigator
|
|
683
|
+
'contributor', // party contributing to the resource
|
|
684
|
+
'custodian', // Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource
|
|
685
|
+
'distributor', // Party who distributes the resource
|
|
686
|
+
'editor', // party who reviewed or modified the resource to improve the content
|
|
687
|
+
'funder', // party providing monetary support for the resource
|
|
688
|
+
'mediator', // a class of entity that mediates access to the resource and for whom the resource is intended or useful
|
|
689
|
+
'originator', // Party who created the resource
|
|
690
|
+
'owner', // Party that owns the resource
|
|
691
|
+
'point_of_contact', // Party who can be contacted for acquiring knowledge about or acquisition of the resource
|
|
692
|
+
'principal_investigator', // Key party responsible for gathering information and conducting research
|
|
693
|
+
'processor', // Party who has processed the data in a manner such that the resource has been modified
|
|
694
|
+
'publisher', // Party who published the resource
|
|
695
|
+
'resource_provider', // Party that supplies the resource
|
|
696
|
+
'rights_holder', // party owning or managing rights over the resource
|
|
697
|
+
'sponsor', // party that sponsors the resource
|
|
698
|
+
'stakeholder', // party who has an interest in the resource or the use of the resource
|
|
699
|
+
'user', // Party who uses the resource
|
|
700
|
+
];
|
|
701
|
+
const RoleLabels = new Map([
|
|
702
|
+
['unspecified', marker('domain.contact.role.unspecified')],
|
|
703
|
+
['other', marker('domain.contact.role.other')],
|
|
704
|
+
['author', marker('domain.contact.role.author')],
|
|
705
|
+
['collaborator', marker('domain.contact.role.collaborator')],
|
|
706
|
+
['contributor', marker('domain.contact.role.contributor')],
|
|
707
|
+
['custodian', marker('domain.contact.role.custodian')],
|
|
708
|
+
['distributor', marker('domain.contact.role.distributor')],
|
|
709
|
+
['editor', marker('domain.contact.role.editor')],
|
|
710
|
+
['funder', marker('domain.contact.role.funder')],
|
|
711
|
+
['mediator', marker('domain.contact.role.mediator')],
|
|
712
|
+
['originator', marker('domain.contact.role.originator')],
|
|
713
|
+
['owner', marker('domain.contact.role.owner')],
|
|
714
|
+
['point_of_contact', marker('domain.contact.role.point_of_contact')],
|
|
715
|
+
[
|
|
716
|
+
'principal_investigator',
|
|
717
|
+
marker('domain.contact.role.principal_investigator'),
|
|
718
|
+
],
|
|
719
|
+
['processor', marker('domain.contact.role.processor')],
|
|
720
|
+
['publisher', marker('domain.contact.role.publisher')],
|
|
721
|
+
['resource_provider', marker('domain.contact.role.resource_provider')],
|
|
722
|
+
['rights_holder', marker('domain.contact.role.rights_holder')],
|
|
723
|
+
['sponsor', marker('domain.contact.role.sponsor')],
|
|
724
|
+
['stakeholder', marker('domain.contact.role.stakeholder')],
|
|
725
|
+
['user', marker('domain.contact.role.user')],
|
|
726
|
+
]);
|
|
727
|
+
|
|
728
|
+
marker('domain.record.updateFrequency.unknown');
|
|
729
|
+
marker('domain.record.updateFrequency.notPlanned');
|
|
730
|
+
marker('domain.record.updateFrequency.asNeeded');
|
|
731
|
+
marker('domain.record.updateFrequency.irregular');
|
|
732
|
+
marker('domain.record.updateFrequency.continual');
|
|
733
|
+
marker('domain.record.updateFrequency.periodic');
|
|
734
|
+
const updateFrequencyCodeValues = [
|
|
735
|
+
'unknown',
|
|
736
|
+
'notPlanned',
|
|
737
|
+
'asNeeded',
|
|
738
|
+
'irregular',
|
|
739
|
+
'continual',
|
|
740
|
+
'periodic',
|
|
741
|
+
'daily',
|
|
742
|
+
'weekly',
|
|
743
|
+
'fortnightly',
|
|
744
|
+
'semimonthly',
|
|
745
|
+
'monthly',
|
|
746
|
+
'quarterly',
|
|
747
|
+
'biannually',
|
|
748
|
+
'annually',
|
|
749
|
+
'biennially',
|
|
750
|
+
];
|
|
751
|
+
marker('domain.record.updateFrequency.day');
|
|
752
|
+
marker('domain.record.updateFrequency.week');
|
|
753
|
+
marker('domain.record.updateFrequency.month');
|
|
754
|
+
marker('domain.record.updateFrequency.year');
|
|
755
|
+
marker('domain.record.updateFrequency.daily');
|
|
756
|
+
marker('domain.record.updateFrequency.weekly');
|
|
757
|
+
marker('domain.record.updateFrequency.fortnightly');
|
|
758
|
+
marker('domain.record.updateFrequency.monthly');
|
|
759
|
+
marker('domain.record.updateFrequency.quarterly');
|
|
760
|
+
marker('domain.record.updateFrequency.biannually');
|
|
761
|
+
marker('domain.record.updateFrequency.annually');
|
|
762
|
+
marker('domain.record.updateFrequency.semimonthly');
|
|
763
|
+
marker('domain.record.updateFrequency.biennially');
|
|
764
|
+
marker('domain.record.status.completed');
|
|
765
|
+
marker('domain.record.status.ongoing');
|
|
766
|
+
marker('domain.record.status.under_development');
|
|
767
|
+
marker('domain.record.status.deprecated');
|
|
768
|
+
marker('domain.record.status.removed');
|
|
769
|
+
marker('domain.record.status.planned');
|
|
770
|
+
marker('domain.record.status.required');
|
|
771
|
+
const RecordStatusValues = [
|
|
772
|
+
'completed',
|
|
773
|
+
'ongoing',
|
|
774
|
+
'under_development',
|
|
775
|
+
'deprecated',
|
|
776
|
+
'removed',
|
|
777
|
+
'planned',
|
|
778
|
+
'required',
|
|
779
|
+
];
|
|
780
|
+
marker('record.metadata.api.accessServiceProtocol.wms');
|
|
781
|
+
marker('record.metadata.api.accessServiceProtocol.wfs');
|
|
782
|
+
marker('record.metadata.api.accessServiceProtocol.wps');
|
|
783
|
+
marker('record.metadata.api.accessServiceProtocol.wmts');
|
|
784
|
+
marker('record.metadata.api.accessServiceProtocol.esriRest');
|
|
785
|
+
marker('record.metadata.api.accessServiceProtocol.ogcFeatures');
|
|
786
|
+
marker('record.metadata.api.accessServiceProtocol.GPFDL');
|
|
787
|
+
marker('record.metadata.api.accessServiceProtocol.tms');
|
|
788
|
+
marker('record.metadata.api.accessServiceProtocol.maplibre-style');
|
|
789
|
+
marker('record.metadata.api.accessServiceProtocol.postgis');
|
|
790
|
+
marker('record.metadata.api.accessServiceProtocol.stac');
|
|
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');
|
|
801
|
+
// DS_AssociationTypeCode values of the ISO19115-3 codelist, any unrecognized value
|
|
802
|
+
// being mapped to 'crossReference'
|
|
803
|
+
const associationTypeValues = [
|
|
804
|
+
'crossReference',
|
|
805
|
+
'largerWorkCitation',
|
|
806
|
+
'partOfSeamlessDatabase',
|
|
807
|
+
'stereoMate',
|
|
808
|
+
'isComposedOf',
|
|
809
|
+
'collectiveTitle',
|
|
810
|
+
'series',
|
|
811
|
+
'dependency',
|
|
812
|
+
'revisionOf',
|
|
813
|
+
];
|
|
814
|
+
|
|
815
|
+
function getAssociationTypeFromCode(associationTypeCode) {
|
|
816
|
+
return associationTypeValues.includes(associationTypeCode)
|
|
817
|
+
? associationTypeCode
|
|
818
|
+
: 'crossReference';
|
|
819
|
+
}
|
|
820
|
+
|
|
677
821
|
function readGeometry(el) {
|
|
678
822
|
const xmlDoc = createDocument(el);
|
|
679
823
|
xmlDoc.root.attributes['xmlns'] = 'http://www.opengis.net/gml/3.2';
|
|
@@ -802,121 +946,6 @@ function getStatusFromStatusCode(statusCode) {
|
|
|
802
946
|
}
|
|
803
947
|
}
|
|
804
948
|
|
|
805
|
-
const RoleValues = [
|
|
806
|
-
'unspecified',
|
|
807
|
-
'other',
|
|
808
|
-
'author', // Party who authored the resource
|
|
809
|
-
'collaborator', // party who assists with the generation of the resource other than the principal investigator
|
|
810
|
-
'contributor', // party contributing to the resource
|
|
811
|
-
'custodian', // Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource
|
|
812
|
-
'distributor', // Party who distributes the resource
|
|
813
|
-
'editor', // party who reviewed or modified the resource to improve the content
|
|
814
|
-
'funder', // party providing monetary support for the resource
|
|
815
|
-
'mediator', // a class of entity that mediates access to the resource and for whom the resource is intended or useful
|
|
816
|
-
'originator', // Party who created the resource
|
|
817
|
-
'owner', // Party that owns the resource
|
|
818
|
-
'point_of_contact', // Party who can be contacted for acquiring knowledge about or acquisition of the resource
|
|
819
|
-
'principal_investigator', // Key party responsible for gathering information and conducting research
|
|
820
|
-
'processor', // Party who has processed the data in a manner such that the resource has been modified
|
|
821
|
-
'publisher', // Party who published the resource
|
|
822
|
-
'resource_provider', // Party that supplies the resource
|
|
823
|
-
'rights_holder', // party owning or managing rights over the resource
|
|
824
|
-
'sponsor', // party that sponsors the resource
|
|
825
|
-
'stakeholder', // party who has an interest in the resource or the use of the resource
|
|
826
|
-
'user', // Party who uses the resource
|
|
827
|
-
];
|
|
828
|
-
const RoleLabels = new Map([
|
|
829
|
-
['unspecified', marker('domain.contact.role.unspecified')],
|
|
830
|
-
['other', marker('domain.contact.role.other')],
|
|
831
|
-
['author', marker('domain.contact.role.author')],
|
|
832
|
-
['collaborator', marker('domain.contact.role.collaborator')],
|
|
833
|
-
['contributor', marker('domain.contact.role.contributor')],
|
|
834
|
-
['custodian', marker('domain.contact.role.custodian')],
|
|
835
|
-
['distributor', marker('domain.contact.role.distributor')],
|
|
836
|
-
['editor', marker('domain.contact.role.editor')],
|
|
837
|
-
['funder', marker('domain.contact.role.funder')],
|
|
838
|
-
['mediator', marker('domain.contact.role.mediator')],
|
|
839
|
-
['originator', marker('domain.contact.role.originator')],
|
|
840
|
-
['owner', marker('domain.contact.role.owner')],
|
|
841
|
-
['point_of_contact', marker('domain.contact.role.point_of_contact')],
|
|
842
|
-
[
|
|
843
|
-
'principal_investigator',
|
|
844
|
-
marker('domain.contact.role.principal_investigator'),
|
|
845
|
-
],
|
|
846
|
-
['processor', marker('domain.contact.role.processor')],
|
|
847
|
-
['publisher', marker('domain.contact.role.publisher')],
|
|
848
|
-
['resource_provider', marker('domain.contact.role.resource_provider')],
|
|
849
|
-
['rights_holder', marker('domain.contact.role.rights_holder')],
|
|
850
|
-
['sponsor', marker('domain.contact.role.sponsor')],
|
|
851
|
-
['stakeholder', marker('domain.contact.role.stakeholder')],
|
|
852
|
-
['user', marker('domain.contact.role.user')],
|
|
853
|
-
]);
|
|
854
|
-
|
|
855
|
-
marker('domain.record.updateFrequency.unknown');
|
|
856
|
-
marker('domain.record.updateFrequency.notPlanned');
|
|
857
|
-
marker('domain.record.updateFrequency.asNeeded');
|
|
858
|
-
marker('domain.record.updateFrequency.irregular');
|
|
859
|
-
marker('domain.record.updateFrequency.continual');
|
|
860
|
-
marker('domain.record.updateFrequency.periodic');
|
|
861
|
-
const updateFrequencyCodeValues = [
|
|
862
|
-
'unknown',
|
|
863
|
-
'notPlanned',
|
|
864
|
-
'asNeeded',
|
|
865
|
-
'irregular',
|
|
866
|
-
'continual',
|
|
867
|
-
'periodic',
|
|
868
|
-
'daily',
|
|
869
|
-
'weekly',
|
|
870
|
-
'fortnightly',
|
|
871
|
-
'semimonthly',
|
|
872
|
-
'monthly',
|
|
873
|
-
'quarterly',
|
|
874
|
-
'biannually',
|
|
875
|
-
'annually',
|
|
876
|
-
'biennially',
|
|
877
|
-
];
|
|
878
|
-
marker('domain.record.updateFrequency.day');
|
|
879
|
-
marker('domain.record.updateFrequency.week');
|
|
880
|
-
marker('domain.record.updateFrequency.month');
|
|
881
|
-
marker('domain.record.updateFrequency.year');
|
|
882
|
-
marker('domain.record.updateFrequency.daily');
|
|
883
|
-
marker('domain.record.updateFrequency.weekly');
|
|
884
|
-
marker('domain.record.updateFrequency.fortnightly');
|
|
885
|
-
marker('domain.record.updateFrequency.monthly');
|
|
886
|
-
marker('domain.record.updateFrequency.quarterly');
|
|
887
|
-
marker('domain.record.updateFrequency.biannually');
|
|
888
|
-
marker('domain.record.updateFrequency.annually');
|
|
889
|
-
marker('domain.record.updateFrequency.semimonthly');
|
|
890
|
-
marker('domain.record.updateFrequency.biennially');
|
|
891
|
-
marker('domain.record.status.completed');
|
|
892
|
-
marker('domain.record.status.ongoing');
|
|
893
|
-
marker('domain.record.status.under_development');
|
|
894
|
-
marker('domain.record.status.deprecated');
|
|
895
|
-
marker('domain.record.status.removed');
|
|
896
|
-
marker('domain.record.status.planned');
|
|
897
|
-
marker('domain.record.status.required');
|
|
898
|
-
const RecordStatusValues = [
|
|
899
|
-
'completed',
|
|
900
|
-
'ongoing',
|
|
901
|
-
'under_development',
|
|
902
|
-
'deprecated',
|
|
903
|
-
'removed',
|
|
904
|
-
'planned',
|
|
905
|
-
'required',
|
|
906
|
-
];
|
|
907
|
-
marker('record.metadata.api.accessServiceProtocol.wms');
|
|
908
|
-
marker('record.metadata.api.accessServiceProtocol.wfs');
|
|
909
|
-
marker('record.metadata.api.accessServiceProtocol.wps');
|
|
910
|
-
marker('record.metadata.api.accessServiceProtocol.wmts');
|
|
911
|
-
marker('record.metadata.api.accessServiceProtocol.esriRest');
|
|
912
|
-
marker('record.metadata.api.accessServiceProtocol.ogcFeatures');
|
|
913
|
-
marker('record.metadata.api.accessServiceProtocol.GPFDL');
|
|
914
|
-
marker('record.metadata.api.accessServiceProtocol.tms');
|
|
915
|
-
marker('record.metadata.api.accessServiceProtocol.maplibre-style');
|
|
916
|
-
marker('record.metadata.api.accessServiceProtocol.postgis');
|
|
917
|
-
marker('record.metadata.api.accessServiceProtocol.stac');
|
|
918
|
-
marker('record.metadata.api.accessServiceProtocol.other');
|
|
919
|
-
|
|
920
949
|
function getUpdateFrequencyFromFrequencyCode(frequencyCode) {
|
|
921
950
|
return frequencyCode &&
|
|
922
951
|
updateFrequencyCodeValues.includes(frequencyCode)
|
|
@@ -1484,14 +1513,17 @@ function extractSourceRecords(liLineageEl) {
|
|
|
1484
1513
|
function readSourceRecords$1(rootEl) {
|
|
1485
1514
|
return extractSourceRecords(pipe(findNestedElement('gmd:dataQualityInfo', 'gmd:DQ_DataQuality', 'gmd:lineage', 'gmd:LI_Lineage'))(rootEl));
|
|
1486
1515
|
}
|
|
1487
|
-
function extractAssociatedRecords(containerName, aggregateName,
|
|
1516
|
+
function extractAssociatedRecords(containerName, aggregateName, readIdentifier) {
|
|
1488
1517
|
return pipe(findChildrenElement(containerName, false), mapArray((el) => {
|
|
1489
1518
|
const aggregateEl = findChildElement(aggregateName, false)(el);
|
|
1490
|
-
const
|
|
1491
|
-
const
|
|
1492
|
-
if (!
|
|
1519
|
+
const uniqueIdentifier = readIdentifier(aggregateEl);
|
|
1520
|
+
const associationTypeCode = pipe(findNestedElement('gmd:associationType', 'gmd:DS_AssociationTypeCode'), readAttribute('codeListValue'))(aggregateEl);
|
|
1521
|
+
if (!uniqueIdentifier || !associationTypeCode)
|
|
1493
1522
|
return null;
|
|
1494
|
-
return {
|
|
1523
|
+
return {
|
|
1524
|
+
uniqueIdentifier,
|
|
1525
|
+
associationType: getAssociationTypeFromCode(associationTypeCode),
|
|
1526
|
+
};
|
|
1495
1527
|
}), filterArray((r) => r !== null));
|
|
1496
1528
|
}
|
|
1497
1529
|
function readAssociatedRecords$1(rootEl) {
|
|
@@ -2039,8 +2071,8 @@ function writeSourceRecords$1(record, rootEl) {
|
|
|
2039
2071
|
}
|
|
2040
2072
|
function writeAssociatedRecords$1(record, rootEl) {
|
|
2041
2073
|
pipe(findOrCreateIdentification(), removeChildrenByName('gmd:aggregationInfo'), appendChildren(...record.associatedRecords
|
|
2042
|
-
.filter((assoc) => assoc.
|
|
2043
|
-
.map((assoc) => pipe(createNestedElement('gmd:aggregationInfo', 'gmd:MD_AggregateInformation'), appendChildren(pipe(createNestedElement('gmd:aggregateDataSetIdentifier', 'gmd:MD_Identifier', 'gmd:code'), writeCharacterString(assoc.
|
|
2074
|
+
.filter((assoc) => assoc.uniqueIdentifier && assoc.associationType)
|
|
2075
|
+
.map((assoc) => pipe(createNestedElement('gmd:aggregationInfo', 'gmd:MD_AggregateInformation'), appendChildren(pipe(createNestedElement('gmd:aggregateDataSetIdentifier', 'gmd:MD_Identifier', 'gmd:code'), writeCharacterString(assoc.uniqueIdentifier)), pipe(createNestedElement('gmd:associationType', 'gmd:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)))))))(rootEl);
|
|
2044
2076
|
}
|
|
2045
2077
|
function getServiceEndpointProtocol(endpoint) {
|
|
2046
2078
|
switch (endpoint.accessServiceProtocol.toLowerCase()) {
|
|
@@ -2752,8 +2784,8 @@ function writeSourceRecords(record, rootEl) {
|
|
|
2752
2784
|
}
|
|
2753
2785
|
function writeAssociatedRecords(record, rootEl) {
|
|
2754
2786
|
pipe(findOrCreateIdentification(), removeChildrenByName('mri:associatedResource'), appendChildren(...record.associatedRecords
|
|
2755
|
-
.filter((assoc) => assoc.
|
|
2756
|
-
.map((assoc) => pipe(createNestedElement('mri:associatedResource', 'mri:MD_AssociatedResource'), appendChildren(pipe(createNestedElement('mri:associationType', 'mri:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)), pipe(createElement('mri:metadataReference'), writeAttribute('uuidref', assoc.
|
|
2787
|
+
.filter((assoc) => assoc.uniqueIdentifier && assoc.associationType)
|
|
2788
|
+
.map((assoc) => pipe(createNestedElement('mri:associatedResource', 'mri:MD_AssociatedResource'), appendChildren(pipe(createNestedElement('mri:associationType', 'mri:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)), pipe(createElement('mri:metadataReference'), writeAttribute('uuidref', assoc.uniqueIdentifier)))))))(rootEl);
|
|
2757
2789
|
}
|
|
2758
2790
|
|
|
2759
2791
|
class Iso191153Converter extends Iso19139Converter {
|
|
@@ -18876,14 +18908,29 @@ class Gn4FieldMapper {
|
|
|
18876
18908
|
featureTypes: selectField(source, 'featureTypes'),
|
|
18877
18909
|
}, output),
|
|
18878
18910
|
related: (output, source) => {
|
|
18879
|
-
const
|
|
18911
|
+
const related = selectField(source, 'related');
|
|
18912
|
+
const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
|
|
18880
18913
|
const featureCatalogIdentifier = selectField(fcatSource, 'uuid');
|
|
18881
|
-
const sourceOfLinks = getAsArray(selectField(
|
|
18914
|
+
const sourceOfLinks = getAsArray(selectField(related, 'hassources'));
|
|
18882
18915
|
const sourceOfIdentifiers = sourceOfLinks
|
|
18883
18916
|
.filter((link) => link['origin'] === 'catalog')
|
|
18884
18917
|
.map((link) => {
|
|
18885
18918
|
return selectField(selectField(link, '_source'), 'uuid');
|
|
18886
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));
|
|
18887
18934
|
const extraValues = {};
|
|
18888
18935
|
if (featureCatalogIdentifier) {
|
|
18889
18936
|
extraValues.featureCatalogIdentifier = featureCatalogIdentifier;
|
|
@@ -18891,6 +18938,12 @@ class Gn4FieldMapper {
|
|
|
18891
18938
|
if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
|
|
18892
18939
|
extraValues.sourceOfIdentifiers = sourceOfIdentifiers;
|
|
18893
18940
|
}
|
|
18941
|
+
if (associatedIdentifiers && associatedIdentifiers.length > 0) {
|
|
18942
|
+
extraValues.associatedIdentifiers = associatedIdentifiers;
|
|
18943
|
+
}
|
|
18944
|
+
if (siblings && siblings.length > 0) {
|
|
18945
|
+
extraValues.siblings = siblings;
|
|
18946
|
+
}
|
|
18894
18947
|
return Object.keys(extraValues).length > 0
|
|
18895
18948
|
? this.addExtra(extraValues, output)
|
|
18896
18949
|
: output;
|
|
@@ -19416,10 +19469,10 @@ class DateService {
|
|
|
19416
19469
|
const dateObj = this.getDateObject(date);
|
|
19417
19470
|
return { locale, dateObj };
|
|
19418
19471
|
}
|
|
19419
|
-
async
|
|
19472
|
+
async getDateFnsLocale() {
|
|
19420
19473
|
const lang = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE;
|
|
19421
19474
|
const locales = await this.dateLocales;
|
|
19422
|
-
return locales[lang];
|
|
19475
|
+
return locales[lang] ?? locales[DEFAULT_LANGUAGE];
|
|
19423
19476
|
}
|
|
19424
19477
|
formatDate(date, options) {
|
|
19425
19478
|
const { locale, dateObj } = this.getLocaleAndDate(date);
|
|
@@ -19432,7 +19485,7 @@ class DateService {
|
|
|
19432
19485
|
async formatRelativeDateTime(date) {
|
|
19433
19486
|
const dateObj = this.getDateObject(date);
|
|
19434
19487
|
const now = new Date();
|
|
19435
|
-
const locale = await this.
|
|
19488
|
+
const locale = await this.getDateFnsLocale();
|
|
19436
19489
|
return formatDistance(dateObj, now, {
|
|
19437
19490
|
addSuffix: true,
|
|
19438
19491
|
locale: locale,
|
|
@@ -19467,6 +19520,18 @@ function propagateToDocumentOnly(event) {
|
|
|
19467
19520
|
}, 0);
|
|
19468
19521
|
}
|
|
19469
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
|
+
|
|
19470
19535
|
function formatUserInfo(userInfo, displayCount = false) {
|
|
19471
19536
|
const infos = (typeof userInfo === 'string' ? userInfo : '').split('|');
|
|
19472
19537
|
const count = displayCount ? ` ${infos[3].split(' ')[1]}` : '';
|
|
@@ -19526,6 +19591,11 @@ function getGeometryFromGeoJSON(data) {
|
|
|
19526
19591
|
}
|
|
19527
19592
|
return null;
|
|
19528
19593
|
}
|
|
19594
|
+
function isBoundingBox(value) {
|
|
19595
|
+
return (Array.isArray(value) &&
|
|
19596
|
+
value.length === 4 &&
|
|
19597
|
+
value.every((item) => typeof item === 'number'));
|
|
19598
|
+
}
|
|
19529
19599
|
function getGeometryBoundingBox(geometry) {
|
|
19530
19600
|
// use the bounding box if specified in the GeoJSON object
|
|
19531
19601
|
if (geometry.bbox) {
|
|
@@ -20194,7 +20264,7 @@ function getLinkLabel(link) {
|
|
|
20194
20264
|
const label = link.description || ('name' in link ? link.name : '');
|
|
20195
20265
|
return format ? `${label} (${format})` : label;
|
|
20196
20266
|
}
|
|
20197
|
-
async function getLayers(url, serviceProtocol) {
|
|
20267
|
+
async function getLayers(url, serviceProtocol, deep = false) {
|
|
20198
20268
|
switch (serviceProtocol) {
|
|
20199
20269
|
case 'ogcFeatures': {
|
|
20200
20270
|
const layers = await new OgcApiEndpoint(url).allCollections;
|
|
@@ -20202,7 +20272,10 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20202
20272
|
}
|
|
20203
20273
|
case 'wfs': {
|
|
20204
20274
|
const endpointWfs = await new WfsEndpoint(url).isReady();
|
|
20205
|
-
const featureTypes =
|
|
20275
|
+
const featureTypes = endpointWfs.getFeatureTypes();
|
|
20276
|
+
if (!deep) {
|
|
20277
|
+
return featureTypes;
|
|
20278
|
+
}
|
|
20206
20279
|
const layers = (await Promise.allSettled(featureTypes.map((collection) => {
|
|
20207
20280
|
return endpointWfs.getFeatureTypeFull(collection.name);
|
|
20208
20281
|
})))
|
|
@@ -20212,12 +20285,14 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20212
20285
|
}
|
|
20213
20286
|
case 'wms': {
|
|
20214
20287
|
const endpointWms = await new WmsEndpoint(url).isReady();
|
|
20215
|
-
const
|
|
20288
|
+
const layersSummary = endpointWms
|
|
20216
20289
|
.getLayers()
|
|
20217
20290
|
.flatMap(wmsLayerFlatten)
|
|
20218
|
-
.filter((l) => l.name)
|
|
20219
|
-
|
|
20220
|
-
|
|
20291
|
+
.filter((l) => l.name);
|
|
20292
|
+
if (!deep) {
|
|
20293
|
+
return layersSummary;
|
|
20294
|
+
}
|
|
20295
|
+
const layers = layersSummary.map((collection) => endpointWms.getLayerByName(collection.name));
|
|
20221
20296
|
return layers;
|
|
20222
20297
|
}
|
|
20223
20298
|
case 'wmts': {
|
|
@@ -20311,6 +20386,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20311
20386
|
}]
|
|
20312
20387
|
}] });
|
|
20313
20388
|
|
|
20389
|
+
class AutofocusDirective {
|
|
20390
|
+
constructor() {
|
|
20391
|
+
this.el = inject(ElementRef);
|
|
20392
|
+
this.injector = inject(Injector);
|
|
20393
|
+
}
|
|
20394
|
+
set autofocus(active) {
|
|
20395
|
+
if (!active)
|
|
20396
|
+
return;
|
|
20397
|
+
afterNextRender(() => this.el.nativeElement.focus(), {
|
|
20398
|
+
injector: this.injector,
|
|
20399
|
+
});
|
|
20400
|
+
}
|
|
20401
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
20402
|
+
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 }); }
|
|
20403
|
+
}
|
|
20404
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, decorators: [{
|
|
20405
|
+
type: Directive,
|
|
20406
|
+
args: [{
|
|
20407
|
+
selector: '[gnUiAutofocus]',
|
|
20408
|
+
standalone: true,
|
|
20409
|
+
}]
|
|
20410
|
+
}], propDecorators: { autofocus: [{
|
|
20411
|
+
type: Input,
|
|
20412
|
+
args: [{ alias: 'gnUiAutofocus', transform: booleanAttribute }]
|
|
20413
|
+
}] } });
|
|
20414
|
+
|
|
20314
20415
|
class ImageFallbackDirective {
|
|
20315
20416
|
constructor() {
|
|
20316
20417
|
this.el = inject(ElementRef);
|
|
@@ -20338,7 +20439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20338
20439
|
}] } });
|
|
20339
20440
|
|
|
20340
20441
|
var name = "geonetwork-ui";
|
|
20341
|
-
var version = "2.11.0-dev.
|
|
20442
|
+
var version = "2.11.0-dev.a63e6e32a";
|
|
20342
20443
|
var engines = {
|
|
20343
20444
|
node: ">=24"
|
|
20344
20445
|
};
|
|
@@ -20359,6 +20460,7 @@ var peerDependencies = {
|
|
|
20359
20460
|
"@angular/core": "19.x || 20.x || 21.x",
|
|
20360
20461
|
"@angular/forms": "19.x || 20.x || 21.x",
|
|
20361
20462
|
"@angular/material": "19.x || 20.x || 21.x",
|
|
20463
|
+
"@angular/material-date-fns-adapter": "19.x || 20.x",
|
|
20362
20464
|
"@angular/platform-browser": "19.x || 20.x || 21.x",
|
|
20363
20465
|
"@angular/platform-browser-dynamic": "19.x || 20.x || 21.x",
|
|
20364
20466
|
"@angular/router": "19.x || 20.x || 21.x",
|
|
@@ -20368,20 +20470,21 @@ var peerDependencies = {
|
|
|
20368
20470
|
"@ngrx/store": "19.x || 20.x || 21.x",
|
|
20369
20471
|
"@ngrx/store-devtools": "19.x || 20.x || 21.x",
|
|
20370
20472
|
"@ngrx/operators": "19.x || 20.x || 21.x",
|
|
20371
|
-
"@ngx-translate/core": "
|
|
20372
|
-
"@ngx-translate/http-loader": "
|
|
20373
|
-
"flag-icons": "
|
|
20473
|
+
"@ngx-translate/core": "17.x",
|
|
20474
|
+
"@ngx-translate/http-loader": "17.x",
|
|
20475
|
+
"flag-icons": "~7.5.0",
|
|
20374
20476
|
rxjs: "7.x",
|
|
20375
20477
|
"zone.js": "*",
|
|
20376
20478
|
tailwindcss: "3.x"
|
|
20377
20479
|
};
|
|
20378
20480
|
var dependencies = {
|
|
20379
20481
|
"@biesbjerg/ngx-translate-extract-marker": "~1.0.0",
|
|
20380
|
-
"@camptocamp/ogc-client": "1.3.1-dev.
|
|
20381
|
-
"@
|
|
20382
|
-
"@geospatial-sdk/
|
|
20383
|
-
"@geospatial-sdk/
|
|
20384
|
-
"@geospatial-sdk/
|
|
20482
|
+
"@camptocamp/ogc-client": "1.3.1-dev.200c02a",
|
|
20483
|
+
"@duckdb/duckdb-wasm": "~1.32.0",
|
|
20484
|
+
"@geospatial-sdk/core": "0.0.5-dev.78",
|
|
20485
|
+
"@geospatial-sdk/geocoding": "0.0.5-dev.78",
|
|
20486
|
+
"@geospatial-sdk/legend": "0.0.5-dev.78",
|
|
20487
|
+
"@geospatial-sdk/openlayers": "0.0.5-dev.78",
|
|
20385
20488
|
"@ltd/j-toml": "~1.38.0",
|
|
20386
20489
|
"@messageformat/core": "~3.4.0",
|
|
20387
20490
|
"@ng-icons/core": "~32.5.0",
|
|
@@ -20389,7 +20492,7 @@ var dependencies = {
|
|
|
20389
20492
|
"@ng-icons/material-icons": "~32.5.0",
|
|
20390
20493
|
"@ng-icons/tabler-icons": "~32.4.0",
|
|
20391
20494
|
"@rgrove/parse-xml": "4.2.0",
|
|
20392
|
-
|
|
20495
|
+
"apache-arrow": "~17.0.0",
|
|
20393
20496
|
"chart.js": "~4.5.1",
|
|
20394
20497
|
"chroma-js": "~3.2.0",
|
|
20395
20498
|
"date-fns": "4.1.0",
|
|
@@ -20402,7 +20505,6 @@ var dependencies = {
|
|
|
20402
20505
|
"ngx-dropzone": "~3.1.0",
|
|
20403
20506
|
"ngx-translate-messageformat-compiler": "~7.2.0",
|
|
20404
20507
|
ol: "~10.8.0",
|
|
20405
|
-
papaparse: "~5.5.3",
|
|
20406
20508
|
proj4: "~2.20.4",
|
|
20407
20509
|
rdflib: "~2.3.5",
|
|
20408
20510
|
semver: "~7.7.4",
|
|
@@ -20600,8 +20702,8 @@ class ElasticsearchService {
|
|
|
20600
20702
|
if (!payload.runtime_mappings)
|
|
20601
20703
|
payload.runtime_mappings = {};
|
|
20602
20704
|
payload.runtime_mappings[fieldName] = {
|
|
20603
|
-
type:
|
|
20604
|
-
script: this.runtimeFields[fieldName],
|
|
20705
|
+
type: this.runtimeFields[fieldName].type,
|
|
20706
|
+
script: this.runtimeFields[fieldName].script,
|
|
20605
20707
|
};
|
|
20606
20708
|
};
|
|
20607
20709
|
const lookForField = (node) => {
|
|
@@ -20621,6 +20723,12 @@ class ElasticsearchService {
|
|
|
20621
20723
|
(node[runtimeField] === 'asc' || node[runtimeField] === 'desc')) {
|
|
20622
20724
|
addMapping(runtimeField);
|
|
20623
20725
|
}
|
|
20726
|
+
if (runtimeField in node &&
|
|
20727
|
+
typeof node[runtimeField] === 'object' &&
|
|
20728
|
+
node[runtimeField] !== null &&
|
|
20729
|
+
('gte' in node[runtimeField] || 'lte' in node[runtimeField])) {
|
|
20730
|
+
addMapping(runtimeField);
|
|
20731
|
+
}
|
|
20624
20732
|
if ('query' in node &&
|
|
20625
20733
|
typeof node.query === 'string' &&
|
|
20626
20734
|
node.query.indexOf(runtimeField + ':') > -1) {
|
|
@@ -20637,8 +20745,8 @@ class ElasticsearchService {
|
|
|
20637
20745
|
lookForField(payload.query);
|
|
20638
20746
|
return payload;
|
|
20639
20747
|
}
|
|
20640
|
-
registerRuntimeField(fieldName, expression) {
|
|
20641
|
-
this.runtimeFields[fieldName] = expression;
|
|
20748
|
+
registerRuntimeField(fieldName, expression, type = 'keyword') {
|
|
20749
|
+
this.runtimeFields[fieldName] = { script: expression, type };
|
|
20642
20750
|
}
|
|
20643
20751
|
getMetadataByIdsPayload(uuids) {
|
|
20644
20752
|
return {
|
|
@@ -20647,6 +20755,7 @@ class ElasticsearchService {
|
|
|
20647
20755
|
values: uuids,
|
|
20648
20756
|
},
|
|
20649
20757
|
},
|
|
20758
|
+
size: uuids.length,
|
|
20650
20759
|
};
|
|
20651
20760
|
}
|
|
20652
20761
|
getRelatedRecordPayload(record, size = 6, _source = [...ES_SOURCE_SUMMARY, 'createDate']) {
|
|
@@ -20697,10 +20806,28 @@ class ElasticsearchService {
|
|
|
20697
20806
|
};
|
|
20698
20807
|
}
|
|
20699
20808
|
buildPayloadSort(sortBy) {
|
|
20700
|
-
if (sortBy ===
|
|
20809
|
+
if (!sortBy || sortBy.length === 0)
|
|
20701
20810
|
return undefined;
|
|
20702
|
-
const fields = Array.isArray(sortBy[0])
|
|
20703
|
-
|
|
20811
|
+
const fields = Array.isArray(sortBy[0])
|
|
20812
|
+
? sortBy
|
|
20813
|
+
: [sortBy];
|
|
20814
|
+
return fields.map((field) => {
|
|
20815
|
+
// Sort by nested array of dates only works with the explicit syntax
|
|
20816
|
+
if (field[1].endsWith('.date')) {
|
|
20817
|
+
const nestedPath = field[1].slice(0, field[1].lastIndexOf('.date'));
|
|
20818
|
+
return {
|
|
20819
|
+
[field[1]]: {
|
|
20820
|
+
order: field[0],
|
|
20821
|
+
mode: field[0] === 'desc' ? 'max' : 'min',
|
|
20822
|
+
missing: '_last',
|
|
20823
|
+
nested: {
|
|
20824
|
+
path: nestedPath,
|
|
20825
|
+
},
|
|
20826
|
+
},
|
|
20827
|
+
};
|
|
20828
|
+
}
|
|
20829
|
+
return { [field[1]]: field[0] };
|
|
20830
|
+
});
|
|
20704
20831
|
}
|
|
20705
20832
|
injectLangInQueryStringFields(queryFieldsPriority) {
|
|
20706
20833
|
const queryLang = this.getQueryLang();
|
|
@@ -20736,7 +20863,49 @@ class ElasticsearchService {
|
|
|
20736
20863
|
isCurrentSearchLang() {
|
|
20737
20864
|
return this.metadataLang === 'current';
|
|
20738
20865
|
}
|
|
20739
|
-
|
|
20866
|
+
findSpatialFilterExtent(filters) {
|
|
20867
|
+
if (typeof filters === 'string') {
|
|
20868
|
+
return undefined;
|
|
20869
|
+
}
|
|
20870
|
+
return Object.values(filters).find(isBoundingBox);
|
|
20871
|
+
}
|
|
20872
|
+
// if a field registered min/max runtime fields, its dates form an interval
|
|
20873
|
+
// the record matches if that interval intersects the filter range
|
|
20874
|
+
buildDateRangeQuery(searchField, dateRange) {
|
|
20875
|
+
const minField = `${searchField}Min`;
|
|
20876
|
+
const maxField = `${searchField}Max`;
|
|
20877
|
+
if (minField in this.runtimeFields && maxField in this.runtimeFields) {
|
|
20878
|
+
const filter = [
|
|
20879
|
+
dateRange.start && {
|
|
20880
|
+
range: {
|
|
20881
|
+
[maxField]: {
|
|
20882
|
+
gte: formatDate(dateRange.start),
|
|
20883
|
+
format: 'yyyy-MM-dd',
|
|
20884
|
+
},
|
|
20885
|
+
},
|
|
20886
|
+
},
|
|
20887
|
+
dateRange.end && {
|
|
20888
|
+
range: {
|
|
20889
|
+
[minField]: {
|
|
20890
|
+
lte: formatDate(dateRange.end),
|
|
20891
|
+
format: 'yyyy-MM-dd',
|
|
20892
|
+
},
|
|
20893
|
+
},
|
|
20894
|
+
},
|
|
20895
|
+
].filter(Boolean);
|
|
20896
|
+
return { bool: { filter } };
|
|
20897
|
+
}
|
|
20898
|
+
return {
|
|
20899
|
+
range: {
|
|
20900
|
+
[searchField]: {
|
|
20901
|
+
...(dateRange.start && { gte: formatDate(dateRange.start) }),
|
|
20902
|
+
...(dateRange.end && { lte: formatDate(dateRange.end) }),
|
|
20903
|
+
format: 'yyyy-MM-dd',
|
|
20904
|
+
},
|
|
20905
|
+
},
|
|
20906
|
+
};
|
|
20907
|
+
}
|
|
20908
|
+
filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
|
|
20740
20909
|
const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
|
|
20741
20910
|
const makeQuery = (filter) => {
|
|
20742
20911
|
if (typeof filter === 'string') {
|
|
@@ -20755,7 +20924,9 @@ class ElasticsearchService {
|
|
|
20755
20924
|
? filters
|
|
20756
20925
|
: Object.keys(filters)
|
|
20757
20926
|
.filter((fieldname) => fieldname !== 'gn-ui-crossFieldFilter')
|
|
20927
|
+
.filter((fieldname) => !isBoundingBox(filters[fieldname]))
|
|
20758
20928
|
.filter((fieldname) => !isDateRange(filters[fieldname]))
|
|
20929
|
+
.filter((fieldname) => !Array.isArray(filters[fieldname]))
|
|
20759
20930
|
.filter((fieldname) => filters[fieldname] &&
|
|
20760
20931
|
JSON.stringify(filters[fieldname]) !== '{}')
|
|
20761
20932
|
.map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
|
|
@@ -20763,31 +20934,26 @@ class ElasticsearchService {
|
|
|
20763
20934
|
if (filters['gn-ui-crossFieldFilter']) {
|
|
20764
20935
|
queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
|
|
20765
20936
|
}
|
|
20766
|
-
const
|
|
20767
|
-
.filter(([, value]) => isDateRange(value))
|
|
20768
|
-
.map(([searchField, dateRange]) => {
|
|
20769
|
-
return {
|
|
20770
|
-
searchField,
|
|
20771
|
-
dateRange,
|
|
20772
|
-
};
|
|
20773
|
-
})[0];
|
|
20937
|
+
const queryRanges = Object.entries(filters).filter(([, value]) => isDateRange(value));
|
|
20774
20938
|
const queryParts = [
|
|
20775
20939
|
queryString && {
|
|
20776
20940
|
query_string: {
|
|
20777
20941
|
query: queryString,
|
|
20778
20942
|
},
|
|
20779
20943
|
},
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20944
|
+
...queryRanges.map(([searchField, dateRange]) => this.buildDateRangeQuery(searchField, dateRange)),
|
|
20945
|
+
spatialFilterExtent && {
|
|
20946
|
+
geo_shape: {
|
|
20947
|
+
geom: {
|
|
20948
|
+
shape: {
|
|
20949
|
+
type: 'envelope',
|
|
20950
|
+
// spatialFilterExtent is [minX, minY, maxX, maxY]; envelope coordinates are [top-left, bottom-right]
|
|
20951
|
+
coordinates: [
|
|
20952
|
+
[spatialFilterExtent[0], spatialFilterExtent[3]],
|
|
20953
|
+
[spatialFilterExtent[2], spatialFilterExtent[1]],
|
|
20954
|
+
],
|
|
20955
|
+
},
|
|
20956
|
+
relation: 'intersects',
|
|
20791
20957
|
},
|
|
20792
20958
|
},
|
|
20793
20959
|
},
|
|
@@ -20817,7 +20983,9 @@ class ElasticsearchService {
|
|
|
20817
20983
|
},
|
|
20818
20984
|
});
|
|
20819
20985
|
}
|
|
20820
|
-
|
|
20986
|
+
// a spatial extent filter takes precedence over the preference geometry for boosting
|
|
20987
|
+
const spatialFilterExtent = this.findSpatialFilterExtent(fieldSearchFilters);
|
|
20988
|
+
const queryFilters = this.filtersToQuery(fieldSearchFilters, spatialFilterExtent);
|
|
20821
20989
|
if (queryFilters) {
|
|
20822
20990
|
filter.push(...queryFilters);
|
|
20823
20991
|
}
|
|
@@ -20828,7 +20996,10 @@ class ElasticsearchService {
|
|
|
20828
20996
|
},
|
|
20829
20997
|
});
|
|
20830
20998
|
}
|
|
20831
|
-
|
|
20999
|
+
const boostGeometry = spatialFilterExtent
|
|
21000
|
+
? bboxToPolygon(spatialFilterExtent)
|
|
21001
|
+
: geometry;
|
|
21002
|
+
if (boostGeometry) {
|
|
20832
21003
|
// boosts applied using the filter geometry:
|
|
20833
21004
|
// * records completely within the geometry receive a boost of 5
|
|
20834
21005
|
// * records intersecting the geometry receive a boost of 2
|
|
@@ -20837,7 +21008,7 @@ class ElasticsearchService {
|
|
|
20837
21008
|
should.push({
|
|
20838
21009
|
geo_shape: {
|
|
20839
21010
|
geom: {
|
|
20840
|
-
shape:
|
|
21011
|
+
shape: boostGeometry,
|
|
20841
21012
|
relation: 'within',
|
|
20842
21013
|
},
|
|
20843
21014
|
boost: 5.0,
|
|
@@ -20845,7 +21016,7 @@ class ElasticsearchService {
|
|
|
20845
21016
|
}, {
|
|
20846
21017
|
geo_shape: {
|
|
20847
21018
|
geom: {
|
|
20848
|
-
shape:
|
|
21019
|
+
shape: boostGeometry,
|
|
20849
21020
|
relation: 'intersects',
|
|
20850
21021
|
},
|
|
20851
21022
|
boost: 2.0,
|
|
@@ -20854,7 +21025,7 @@ class ElasticsearchService {
|
|
|
20854
21025
|
// this will boost the results variably depending on their distance from the given geometry
|
|
20855
21026
|
// note: this takes into account the `location` field of a record; this is generally the center of all spatial extents
|
|
20856
21027
|
// combined, and thus the actual size/coverage of the record spatial extent isn't relevant here
|
|
20857
|
-
const bbox = getGeometryBoundingBox(
|
|
21028
|
+
const bbox = getGeometryBoundingBox(boostGeometry);
|
|
20858
21029
|
const center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
|
20859
21030
|
const northToCenter = new LineString([
|
|
20860
21031
|
[center[0], bbox[3]],
|
|
@@ -21180,7 +21351,7 @@ class Gn4Repository {
|
|
|
21180
21351
|
}
|
|
21181
21352
|
getRecord(uniqueIdentifier) {
|
|
21182
21353
|
return this.gn4SearchApi
|
|
21183
|
-
.search('bucket', ['fcats', 'hassources'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21354
|
+
.search('bucket', ['fcats', 'hassources', 'siblings', 'associated'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21184
21355
|
.pipe(map$1((results) => results.hits.hits[0]), switchMap((record) => record ? this.gn4Mapper.readRecord(record) : of(null)));
|
|
21185
21356
|
}
|
|
21186
21357
|
getMultipleRecords(uniqueIdentifiers) {
|
|
@@ -21234,19 +21405,28 @@ class Gn4Repository {
|
|
|
21234
21405
|
.search('bucket', null, JSON.stringify(this.gn4SearchHelper.getRelatedRecordPayload(similarTo, 3)))
|
|
21235
21406
|
.pipe(switchMap((results) => this.gn4Mapper.readRecords(results.hits.hits)));
|
|
21236
21407
|
}
|
|
21237
|
-
|
|
21238
|
-
const
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
|
|
21245
|
-
|
|
21246
|
-
|
|
21247
|
-
|
|
21408
|
+
getLinkedRecords(record) {
|
|
21409
|
+
const siblings = (record.extras?.['siblings'] ?? []);
|
|
21410
|
+
const relations = [
|
|
21411
|
+
['source', (record.extras?.['sourcesIdentifiers'] ?? [])],
|
|
21412
|
+
['sourceOf', (record.extras?.['sourceOfIdentifiers'] ?? [])],
|
|
21413
|
+
['sibling', siblings.map(({ uniqueIdentifier }) => uniqueIdentifier)],
|
|
21414
|
+
[
|
|
21415
|
+
'associated',
|
|
21416
|
+
(record.extras?.['associatedIdentifiers'] ?? []),
|
|
21417
|
+
],
|
|
21418
|
+
];
|
|
21419
|
+
const requested = relations.filter(([, identifiers]) => identifiers.length > 0);
|
|
21420
|
+
if (requested.length === 0) {
|
|
21421
|
+
return of([]);
|
|
21248
21422
|
}
|
|
21249
|
-
return
|
|
21423
|
+
return forkJoin(requested.map(([relation, identifiers]) => this.getMultipleRecords(identifiers).pipe(map$1((records) => (records ?? []).map((record) => ({
|
|
21424
|
+
record,
|
|
21425
|
+
relation,
|
|
21426
|
+
associationType: relation === 'sibling'
|
|
21427
|
+
? siblings.find(({ uniqueIdentifier }) => uniqueIdentifier === record.uniqueIdentifier)?.associationType
|
|
21428
|
+
: undefined,
|
|
21429
|
+
}))), catchError(() => of([]))))).pipe(map$1((groups) => groups.flat()));
|
|
21250
21430
|
}
|
|
21251
21431
|
aggregate(params) {
|
|
21252
21432
|
// if aggregations are empty, return an empty object right away
|
|
@@ -22435,48 +22615,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22435
22615
|
type: Injectable
|
|
22436
22616
|
}] });
|
|
22437
22617
|
|
|
22438
|
-
const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider');
|
|
22439
|
-
class GeocodingService {
|
|
22440
|
-
constructor() {
|
|
22441
|
-
this.provider = inject(GEOCODING_PROVIDER);
|
|
22442
|
-
}
|
|
22443
|
-
query(text) {
|
|
22444
|
-
let queryObservable;
|
|
22445
|
-
switch (this.provider[0]) {
|
|
22446
|
-
case 'geoadmin':
|
|
22447
|
-
queryObservable = from(queryGeoadmin(text, this.provider[1]));
|
|
22448
|
-
break;
|
|
22449
|
-
case 'geonames':
|
|
22450
|
-
queryObservable = from(queryGeonames(text, this.provider[1]));
|
|
22451
|
-
break;
|
|
22452
|
-
case 'data-gouv-fr':
|
|
22453
|
-
queryObservable = from(queryDataGouvFr(text, this.provider[1]));
|
|
22454
|
-
break;
|
|
22455
|
-
default:
|
|
22456
|
-
return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
|
|
22457
|
-
}
|
|
22458
|
-
return queryObservable.pipe(catchError((error) => throwError(error)));
|
|
22459
|
-
}
|
|
22460
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
22461
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
|
|
22462
|
-
}
|
|
22463
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
|
|
22464
|
-
type: Injectable,
|
|
22465
|
-
args: [{
|
|
22466
|
-
providedIn: 'root',
|
|
22467
|
-
}]
|
|
22468
|
-
}] });
|
|
22469
|
-
|
|
22470
22618
|
class FeatureMapModule {
|
|
22471
22619
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
22472
22620
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, imports: [i1.StoreFeatureModule] }); }
|
|
22473
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [
|
|
22474
|
-
MapFacade,
|
|
22475
|
-
{
|
|
22476
|
-
provide: GEOCODING_PROVIDER,
|
|
22477
|
-
useValue: ['geonames', { maxRows: 5 }],
|
|
22478
|
-
},
|
|
22479
|
-
], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
|
|
22621
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [MapFacade], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
|
|
22480
22622
|
}
|
|
22481
22623
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, decorators: [{
|
|
22482
22624
|
type: NgModule,
|
|
@@ -22484,13 +22626,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22484
22626
|
imports: [
|
|
22485
22627
|
StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
|
|
22486
22628
|
],
|
|
22487
|
-
providers: [
|
|
22488
|
-
MapFacade,
|
|
22489
|
-
{
|
|
22490
|
-
provide: GEOCODING_PROVIDER,
|
|
22491
|
-
useValue: ['geonames', { maxRows: 5 }],
|
|
22492
|
-
},
|
|
22493
|
-
],
|
|
22629
|
+
providers: [MapFacade],
|
|
22494
22630
|
}]
|
|
22495
22631
|
}] });
|
|
22496
22632
|
|
|
@@ -22507,9 +22643,10 @@ const VECTOR_STYLE_DEFAULT = new InjectionToken('vectorStyleDefault', {
|
|
|
22507
22643
|
});
|
|
22508
22644
|
|
|
22509
22645
|
const DEFAULT_BASEMAP_LAYER = {
|
|
22510
|
-
type: '
|
|
22511
|
-
|
|
22512
|
-
|
|
22646
|
+
type: 'maplibre-style',
|
|
22647
|
+
styleUrl: `https://basemaps.cartocdn.com/gl/positron-gl-style/style.json`,
|
|
22648
|
+
clickable: false,
|
|
22649
|
+
hoverable: false,
|
|
22513
22650
|
};
|
|
22514
22651
|
const DEFAULT_VIEW = {
|
|
22515
22652
|
center: [0, 15],
|
|
@@ -23224,6 +23361,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23224
23361
|
'search_preset',
|
|
23225
23362
|
'advanced_filters',
|
|
23226
23363
|
'limit',
|
|
23364
|
+
'spatial_extent_max_file_size',
|
|
23227
23365
|
], warnings, errors);
|
|
23228
23366
|
const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
|
|
23229
23367
|
searchConfig =
|
|
@@ -23241,6 +23379,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23241
23379
|
})),
|
|
23242
23380
|
ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
|
|
23243
23381
|
LIMIT: parsedSearchSection.limit,
|
|
23382
|
+
SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
|
|
23244
23383
|
};
|
|
23245
23384
|
const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
|
|
23246
23385
|
metadataQualityConfig =
|
|
@@ -24298,7 +24437,7 @@ class AutocompleteComponent {
|
|
|
24298
24437
|
this.enterBtnPosition = event.target['value'].length * 8 + 80;
|
|
24299
24438
|
}
|
|
24300
24439
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24301
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
|
|
24440
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithTemplate: "displayWithTemplate", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
|
|
24302
24441
|
provideIcons({
|
|
24303
24442
|
iconoirSearch,
|
|
24304
24443
|
matClose,
|
|
@@ -24307,7 +24446,7 @@ class AutocompleteComponent {
|
|
|
24307
24446
|
provideNgIconsConfig({
|
|
24308
24447
|
size: '1.75rem',
|
|
24309
24448
|
}),
|
|
24310
|
-
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: MatAutocompleteTrigger, descendants: true }, { propertyName: "autocomplete", first: true, predicate: MatAutocomplete, descendants: true }, { propertyName: "inputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"], dependencies: [{ kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i1$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i1$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i1$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24449
|
+
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: MatAutocompleteTrigger, descendants: true }, { propertyName: "autocomplete", first: true, predicate: MatAutocomplete, descendants: true }, { propertyName: "inputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n @if (displayWithTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n displayWithTemplate;\n context: { $implicit: suggestion }\n \"\n ></ng-container>\n } @else {\n {{ displayWithFnInternal(suggestion) }}\n }\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"], dependencies: [{ kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i1$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i1$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i1$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24311
24450
|
}
|
|
24312
24451
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
|
|
24313
24452
|
type: Component,
|
|
@@ -24328,7 +24467,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24328
24467
|
provideNgIconsConfig({
|
|
24329
24468
|
size: '1.75rem',
|
|
24330
24469
|
}),
|
|
24331
|
-
], template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"] }]
|
|
24470
|
+
], template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n @if (displayWithTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n displayWithTemplate;\n context: { $implicit: suggestion }\n \"\n ></ng-container>\n } @else {\n {{ displayWithFnInternal(suggestion) }}\n }\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"] }]
|
|
24332
24471
|
}], propDecorators: { placeholder: [{
|
|
24333
24472
|
type: Input
|
|
24334
24473
|
}], enterButton: [{
|
|
@@ -24366,6 +24505,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24366
24505
|
}], inputRef: [{
|
|
24367
24506
|
type: ViewChild,
|
|
24368
24507
|
args: ['searchInput']
|
|
24508
|
+
}], displayWithTemplate: [{
|
|
24509
|
+
type: Input
|
|
24369
24510
|
}], displayWithFn: [{
|
|
24370
24511
|
type: Input
|
|
24371
24512
|
}] } });
|
|
@@ -24498,12 +24639,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24498
24639
|
type: Input
|
|
24499
24640
|
}] } });
|
|
24500
24641
|
|
|
24642
|
+
function provideLocalizedDateAdapter() {
|
|
24643
|
+
return [
|
|
24644
|
+
{ provide: MAT_DATE_LOCALE, useValue: enUS },
|
|
24645
|
+
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
|
|
24646
|
+
{
|
|
24647
|
+
provide: DateAdapter,
|
|
24648
|
+
useFactory: () => {
|
|
24649
|
+
const dateService = inject(DateService);
|
|
24650
|
+
const adapter = new DateFnsAdapter();
|
|
24651
|
+
dateService
|
|
24652
|
+
.getDateFnsLocale()
|
|
24653
|
+
.then((locale) => adapter.setLocale(locale));
|
|
24654
|
+
return adapter;
|
|
24655
|
+
},
|
|
24656
|
+
},
|
|
24657
|
+
];
|
|
24658
|
+
}
|
|
24659
|
+
|
|
24501
24660
|
class DatePickerComponent {
|
|
24502
24661
|
constructor() {
|
|
24503
|
-
this.dateAdapter = inject(DateAdapter);
|
|
24504
|
-
this.translate = inject(TranslateService);
|
|
24505
24662
|
this.dateChange = new EventEmitter();
|
|
24506
|
-
this.dateAdapter.setLocale(this.translate.getCurrentLang());
|
|
24507
24663
|
}
|
|
24508
24664
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24509
24665
|
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: [
|
|
@@ -24511,30 +24667,19 @@ class DatePickerComponent {
|
|
|
24511
24667
|
provideNgIconsConfig({
|
|
24512
24668
|
size: '1.5rem',
|
|
24513
24669
|
}),
|
|
24514
|
-
|
|
24515
|
-
|
|
24516
|
-
useFactory: (locale) => locale,
|
|
24517
|
-
},
|
|
24518
|
-
], 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 }); }
|
|
24670
|
+
provideLocalizedDateAdapter(),
|
|
24671
|
+
], 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 }); }
|
|
24519
24672
|
}
|
|
24520
24673
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
24521
24674
|
type: Component,
|
|
24522
|
-
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24523
|
-
MatNativeDateModule,
|
|
24524
|
-
MatDatepickerModule,
|
|
24525
|
-
ButtonComponent,
|
|
24526
|
-
NgIconComponent,
|
|
24527
|
-
], providers: [
|
|
24675
|
+
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24528
24676
|
provideIcons({ iconoirCalendar }),
|
|
24529
24677
|
provideNgIconsConfig({
|
|
24530
24678
|
size: '1.5rem',
|
|
24531
24679
|
}),
|
|
24532
|
-
|
|
24533
|
-
provide: MAT_DATE_LOCALE,
|
|
24534
|
-
useFactory: (locale) => locale,
|
|
24535
|
-
},
|
|
24680
|
+
provideLocalizedDateAdapter(),
|
|
24536
24681
|
], 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"] }]
|
|
24537
|
-
}],
|
|
24682
|
+
}], propDecorators: { date: [{
|
|
24538
24683
|
type: Input
|
|
24539
24684
|
}], dateChange: [{
|
|
24540
24685
|
type: Output
|
|
@@ -24542,58 +24687,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24542
24687
|
|
|
24543
24688
|
class DateRangeDropdownComponent {
|
|
24544
24689
|
constructor() {
|
|
24545
|
-
this.
|
|
24690
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
24691
|
+
this.dateAdapter = inject(DateAdapter);
|
|
24692
|
+
this.dateFormats = inject(MAT_DATE_FORMATS);
|
|
24546
24693
|
this.cdr = inject(ChangeDetectorRef);
|
|
24547
|
-
this.
|
|
24548
|
-
this.
|
|
24549
|
-
this.
|
|
24694
|
+
this.dateRange = {};
|
|
24695
|
+
this.dateRangeChange = new EventEmitter();
|
|
24696
|
+
this.overlayPositions = [
|
|
24697
|
+
{
|
|
24698
|
+
originX: 'start',
|
|
24699
|
+
originY: 'bottom',
|
|
24700
|
+
overlayX: 'start',
|
|
24701
|
+
overlayY: 'top',
|
|
24702
|
+
offsetY: 8,
|
|
24703
|
+
},
|
|
24704
|
+
{
|
|
24705
|
+
originX: 'start',
|
|
24706
|
+
originY: 'top',
|
|
24707
|
+
overlayX: 'start',
|
|
24708
|
+
overlayY: 'bottom',
|
|
24709
|
+
offsetY: -8,
|
|
24710
|
+
},
|
|
24711
|
+
];
|
|
24712
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
24713
|
+
this.overlayOpen = false;
|
|
24714
|
+
this.expandedBound = 'start';
|
|
24715
|
+
this.invalidBounds = { start: false, end: false };
|
|
24716
|
+
// redraw when the lazily loaded UI locale reaches the adapter
|
|
24717
|
+
this.dateAdapter.localeChanges
|
|
24718
|
+
.pipe(takeUntilDestroyed())
|
|
24719
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
24550
24720
|
}
|
|
24551
|
-
|
|
24552
|
-
this.
|
|
24721
|
+
get startDate() {
|
|
24722
|
+
return this.dateRange.start;
|
|
24553
24723
|
}
|
|
24554
|
-
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24724
|
+
get endDate() {
|
|
24725
|
+
return this.dateRange.end;
|
|
24726
|
+
}
|
|
24727
|
+
get selectedDatesCount() {
|
|
24728
|
+
return (this.startDate ? 1 : 0) + (this.endDate ? 1 : 0);
|
|
24729
|
+
}
|
|
24730
|
+
openOverlay() {
|
|
24731
|
+
this.expandedBound = 'start';
|
|
24732
|
+
this.overlayOpen = true;
|
|
24733
|
+
}
|
|
24734
|
+
closeOverlay() {
|
|
24735
|
+
this.overlayOpen = false;
|
|
24736
|
+
}
|
|
24737
|
+
toggleBound(bound) {
|
|
24738
|
+
this.expandedBound = this.expandedBound === bound ? null : bound;
|
|
24739
|
+
}
|
|
24740
|
+
formatDate(date) {
|
|
24741
|
+
return this.dateAdapter.format(date, this.dateFormats.display.dateInput);
|
|
24742
|
+
}
|
|
24743
|
+
onDateInput(bound, event) {
|
|
24744
|
+
const typedText = event.target.value.trim();
|
|
24745
|
+
const date = typedText
|
|
24746
|
+
? this.dateAdapter.parse(typedText, this.dateFormats.parse.dateInput)
|
|
24747
|
+
: null;
|
|
24748
|
+
if (!this.isAcceptable(bound, typedText, date)) {
|
|
24749
|
+
// keep the text as typed and flag it; the filter stays on its last value
|
|
24750
|
+
this.invalidBounds = { ...this.invalidBounds, [bound]: true };
|
|
24751
|
+
return;
|
|
24752
|
+
}
|
|
24753
|
+
if (bound === 'start')
|
|
24754
|
+
this.setStartDate(date);
|
|
24755
|
+
else
|
|
24756
|
+
this.setEndDate(date);
|
|
24757
|
+
}
|
|
24758
|
+
normalizeDateInput(bound, event) {
|
|
24759
|
+
if (this.invalidBounds[bound])
|
|
24760
|
+
return;
|
|
24761
|
+
const date = bound === 'start' ? this.startDate : this.endDate;
|
|
24762
|
+
const input = event.target;
|
|
24763
|
+
input.value = date ? this.formatDate(date) : '';
|
|
24764
|
+
}
|
|
24765
|
+
isAcceptable(bound, typedText, date) {
|
|
24766
|
+
if (!typedText)
|
|
24767
|
+
return true;
|
|
24768
|
+
if (!date || !this.dateAdapter.isValid(date))
|
|
24769
|
+
return false;
|
|
24770
|
+
return bound === 'start'
|
|
24771
|
+
? !this.endDate || date <= this.endDate
|
|
24772
|
+
: !this.startDate || date >= this.startDate;
|
|
24773
|
+
}
|
|
24774
|
+
setStartDate(date) {
|
|
24775
|
+
this.invalidBounds = { ...this.invalidBounds, start: false };
|
|
24776
|
+
this.applyDateRange({ ...this.dateRange, start: date });
|
|
24777
|
+
this.expandedBound = 'end';
|
|
24778
|
+
}
|
|
24779
|
+
setEndDate(date) {
|
|
24780
|
+
this.invalidBounds = { ...this.invalidBounds, end: false };
|
|
24781
|
+
this.applyDateRange({ ...this.dateRange, end: date });
|
|
24782
|
+
this.expandedBound = null;
|
|
24783
|
+
}
|
|
24784
|
+
clearDates(event) {
|
|
24785
|
+
this.invalidBounds = { start: false, end: false };
|
|
24786
|
+
this.expandedBound = 'start';
|
|
24787
|
+
this.applyDateRange({});
|
|
24788
|
+
propagateToDocumentOnly(event);
|
|
24789
|
+
}
|
|
24790
|
+
applyDateRange(dateRange) {
|
|
24791
|
+
this.dateRange = {
|
|
24792
|
+
...(dateRange.start && { start: dateRange.start }),
|
|
24793
|
+
...(dateRange.end && { end: dateRange.end }),
|
|
24794
|
+
};
|
|
24795
|
+
this.dateRangeChange.emit(this.dateRange);
|
|
24562
24796
|
}
|
|
24563
24797
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24564
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
24798
|
+
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: [
|
|
24565
24799
|
provideIcons({
|
|
24566
|
-
|
|
24800
|
+
iconoirCalendar,
|
|
24801
|
+
matClose,
|
|
24567
24802
|
matExpandLess,
|
|
24803
|
+
matExpandMore,
|
|
24568
24804
|
}),
|
|
24569
|
-
|
|
24805
|
+
provideNgIconsConfig({
|
|
24806
|
+
size: '1.5rem',
|
|
24807
|
+
}),
|
|
24808
|
+
provideLocalizedDateAdapter(),
|
|
24809
|
+
], 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 }); }
|
|
24570
24810
|
}
|
|
24571
24811
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, decorators: [{
|
|
24572
24812
|
type: Component,
|
|
24573
24813
|
args: [{ selector: 'gn-ui-date-range-dropdown', standalone: true, imports: [
|
|
24574
|
-
|
|
24575
|
-
MatNativeDateModule,
|
|
24576
|
-
MatDatepickerModule,
|
|
24814
|
+
AutofocusDirective,
|
|
24577
24815
|
ButtonComponent,
|
|
24816
|
+
MatDatepickerModule,
|
|
24817
|
+
NgIcon,
|
|
24818
|
+
NgTemplateOutlet,
|
|
24819
|
+
OverlayModule,
|
|
24820
|
+
TranslateDirective,
|
|
24821
|
+
TranslatePipe,
|
|
24578
24822
|
], providers: [
|
|
24579
24823
|
provideIcons({
|
|
24580
|
-
|
|
24824
|
+
iconoirCalendar,
|
|
24825
|
+
matClose,
|
|
24581
24826
|
matExpandLess,
|
|
24827
|
+
matExpandMore,
|
|
24582
24828
|
}),
|
|
24583
|
-
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24829
|
+
provideNgIconsConfig({
|
|
24830
|
+
size: '1.5rem',
|
|
24831
|
+
}),
|
|
24832
|
+
provideLocalizedDateAdapter(),
|
|
24833
|
+
], 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"] }]
|
|
24834
|
+
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
24587
24835
|
type: Input
|
|
24588
|
-
}],
|
|
24836
|
+
}], dateRange: [{
|
|
24589
24837
|
type: Input
|
|
24590
|
-
}],
|
|
24591
|
-
type: Output
|
|
24592
|
-
}], endDateChange: [{
|
|
24838
|
+
}], dateRangeChange: [{
|
|
24593
24839
|
type: Output
|
|
24594
|
-
}],
|
|
24840
|
+
}], overlayOrigin: [{
|
|
24595
24841
|
type: ViewChild,
|
|
24596
|
-
args: ['
|
|
24842
|
+
args: ['overlayOrigin']
|
|
24597
24843
|
}] } });
|
|
24598
24844
|
|
|
24599
24845
|
class DateRangePickerComponent {
|
|
@@ -24607,20 +24853,17 @@ class DateRangePickerComponent {
|
|
|
24607
24853
|
provideNgIconsConfig({
|
|
24608
24854
|
size: '1.5rem',
|
|
24609
24855
|
}),
|
|
24610
|
-
|
|
24856
|
+
provideLocalizedDateAdapter(),
|
|
24857
|
+
], 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 }); }
|
|
24611
24858
|
}
|
|
24612
24859
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
24613
24860
|
type: Component,
|
|
24614
|
-
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24615
|
-
MatNativeDateModule,
|
|
24616
|
-
MatDatepickerModule,
|
|
24617
|
-
ButtonComponent,
|
|
24618
|
-
NgIconComponent,
|
|
24619
|
-
], providers: [
|
|
24861
|
+
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24620
24862
|
provideIcons({ iconoirCalendar }),
|
|
24621
24863
|
provideNgIconsConfig({
|
|
24622
24864
|
size: '1.5rem',
|
|
24623
24865
|
}),
|
|
24866
|
+
provideLocalizedDateAdapter(),
|
|
24624
24867
|
], 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"] }]
|
|
24625
24868
|
}], propDecorators: { startDate: [{
|
|
24626
24869
|
type: Input
|
|
@@ -24638,28 +24881,68 @@ class DragAndDropFileInputComponent {
|
|
|
24638
24881
|
constructor() {
|
|
24639
24882
|
this.placeholder = placeholder;
|
|
24640
24883
|
this.accept = '*';
|
|
24884
|
+
this.maxFileSizeMb = null;
|
|
24885
|
+
this.icon = null;
|
|
24886
|
+
this.dropzoneBackgroundColor = null;
|
|
24887
|
+
this.textClass = '';
|
|
24888
|
+
this.extraClass = '';
|
|
24889
|
+
this.showFileName = true;
|
|
24641
24890
|
this.fileChange = new EventEmitter();
|
|
24891
|
+
this.errorChange = new EventEmitter();
|
|
24642
24892
|
this.selectedFile = null;
|
|
24643
24893
|
}
|
|
24644
24894
|
get fileName() {
|
|
24645
24895
|
return this.selectedFile && this.selectedFile.name;
|
|
24646
24896
|
}
|
|
24897
|
+
get maxFileSizeBytes() {
|
|
24898
|
+
return typeof this.maxFileSizeMb === 'number'
|
|
24899
|
+
? megabytesToBytes(this.maxFileSizeMb)
|
|
24900
|
+
: null;
|
|
24901
|
+
}
|
|
24647
24902
|
selectFile(event) {
|
|
24903
|
+
if (event.rejectedFiles?.length) {
|
|
24904
|
+
const reason = event.rejectedFiles[0].reason;
|
|
24905
|
+
this.errorChange.emit(reason === 'size' ? 'file-too-large' : 'invalid-extension');
|
|
24906
|
+
return;
|
|
24907
|
+
}
|
|
24648
24908
|
this.selectedFile = event.addedFiles[0];
|
|
24649
24909
|
this.fileChange.emit(this.selectedFile);
|
|
24650
24910
|
}
|
|
24911
|
+
openFileSelector() {
|
|
24912
|
+
this.dropzone.showFileSelector();
|
|
24913
|
+
}
|
|
24914
|
+
clear() {
|
|
24915
|
+
this.selectedFile = null;
|
|
24916
|
+
}
|
|
24651
24917
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24652
|
-
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
|
|
24918
|
+
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"] }] }); }
|
|
24653
24919
|
}
|
|
24654
24920
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, decorators: [{
|
|
24655
24921
|
type: Component,
|
|
24656
|
-
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule], template: "<div
|
|
24922
|
+
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"] }]
|
|
24657
24923
|
}], propDecorators: { placeholder: [{
|
|
24658
24924
|
type: Input
|
|
24659
24925
|
}], accept: [{
|
|
24660
24926
|
type: Input
|
|
24927
|
+
}], maxFileSizeMb: [{
|
|
24928
|
+
type: Input
|
|
24929
|
+
}], icon: [{
|
|
24930
|
+
type: Input
|
|
24931
|
+
}], dropzoneBackgroundColor: [{
|
|
24932
|
+
type: Input
|
|
24933
|
+
}], textClass: [{
|
|
24934
|
+
type: Input
|
|
24935
|
+
}], extraClass: [{
|
|
24936
|
+
type: Input
|
|
24937
|
+
}], showFileName: [{
|
|
24938
|
+
type: Input
|
|
24661
24939
|
}], fileChange: [{
|
|
24662
24940
|
type: Output
|
|
24941
|
+
}], errorChange: [{
|
|
24942
|
+
type: Output
|
|
24943
|
+
}], dropzone: [{
|
|
24944
|
+
type: ViewChild,
|
|
24945
|
+
args: [NgxDropzoneComponent]
|
|
24663
24946
|
}] } });
|
|
24664
24947
|
|
|
24665
24948
|
class DropdownMultiselectComponent {
|
|
@@ -24708,7 +24991,7 @@ class DropdownMultiselectComponent {
|
|
|
24708
24991
|
}
|
|
24709
24992
|
setFocus() {
|
|
24710
24993
|
setTimeout(() => {
|
|
24711
|
-
this.searchFieldInput
|
|
24994
|
+
this.searchFieldInput?.nativeElement.focus();
|
|
24712
24995
|
}, 0);
|
|
24713
24996
|
}
|
|
24714
24997
|
openOverlay() {
|
|
@@ -24814,7 +25097,10 @@ class DropdownMultiselectComponent {
|
|
|
24814
25097
|
matExpandMore,
|
|
24815
25098
|
matExpandLess,
|
|
24816
25099
|
}),
|
|
24817
|
-
|
|
25100
|
+
provideNgIconsConfig({
|
|
25101
|
+
size: '1.5rem',
|
|
25102
|
+
}),
|
|
25103
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24818
25104
|
}
|
|
24819
25105
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
|
|
24820
25106
|
type: Component,
|
|
@@ -24824,7 +25110,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24824
25110
|
matExpandMore,
|
|
24825
25111
|
matExpandLess,
|
|
24826
25112
|
}),
|
|
24827
|
-
|
|
25113
|
+
provideNgIconsConfig({
|
|
25114
|
+
size: '1.5rem',
|
|
25115
|
+
}),
|
|
25116
|
+
], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
|
|
24828
25117
|
}], propDecorators: { title: [{
|
|
24829
25118
|
type: Input
|
|
24830
25119
|
}], choices: [{
|
|
@@ -24996,7 +25285,7 @@ class DropdownSelectorComponent {
|
|
|
24996
25285
|
provideNgIconsConfig({
|
|
24997
25286
|
size: '1.5em',
|
|
24998
25287
|
}),
|
|
24999
|
-
], 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$
|
|
25288
|
+
], 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 }); }
|
|
25000
25289
|
}
|
|
25001
25290
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownSelectorComponent, decorators: [{
|
|
25002
25291
|
type: Component,
|
|
@@ -25736,6 +26025,175 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
25736
26025
|
type: Output
|
|
25737
26026
|
}] } });
|
|
25738
26027
|
|
|
26028
|
+
marker('search.filters.spatialExtent.import');
|
|
26029
|
+
marker('search.filters.spatialExtent.helpText');
|
|
26030
|
+
marker('search.filters.spatialExtent.error.title');
|
|
26031
|
+
const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
|
|
26032
|
+
const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
|
|
26033
|
+
const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
|
|
26034
|
+
const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
|
|
26035
|
+
class SpatialExtentDropdownComponent {
|
|
26036
|
+
constructor() {
|
|
26037
|
+
this.cd = inject(ChangeDetectorRef);
|
|
26038
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
26039
|
+
this.maxFileSizeMb = null;
|
|
26040
|
+
this.bboxChange = new EventEmitter();
|
|
26041
|
+
this.errorChange = new EventEmitter();
|
|
26042
|
+
this.bbox = null;
|
|
26043
|
+
this.fileName = '';
|
|
26044
|
+
this.overlayPositions = [
|
|
26045
|
+
{
|
|
26046
|
+
originX: 'start',
|
|
26047
|
+
originY: 'bottom',
|
|
26048
|
+
overlayX: 'start',
|
|
26049
|
+
overlayY: 'top',
|
|
26050
|
+
offsetY: 8,
|
|
26051
|
+
},
|
|
26052
|
+
{
|
|
26053
|
+
originX: 'start',
|
|
26054
|
+
originY: 'top',
|
|
26055
|
+
overlayX: 'start',
|
|
26056
|
+
overlayY: 'bottom',
|
|
26057
|
+
offsetY: -8,
|
|
26058
|
+
},
|
|
26059
|
+
];
|
|
26060
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
26061
|
+
this.overlayOpen = false;
|
|
26062
|
+
this.overlayMinWidth = 'none';
|
|
26063
|
+
this.errorKey = null;
|
|
26064
|
+
}
|
|
26065
|
+
set initialBbox(value) {
|
|
26066
|
+
if (!this.bbox && value) {
|
|
26067
|
+
this.bbox = value;
|
|
26068
|
+
}
|
|
26069
|
+
}
|
|
26070
|
+
get hasSelection() {
|
|
26071
|
+
return !!this.bbox;
|
|
26072
|
+
}
|
|
26073
|
+
get selectionLabelKey() {
|
|
26074
|
+
return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
|
|
26075
|
+
}
|
|
26076
|
+
get selectionDeleteLabelKey() {
|
|
26077
|
+
return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
|
|
26078
|
+
}
|
|
26079
|
+
get selectionLabelParams() {
|
|
26080
|
+
return { fileName: this.fileName };
|
|
26081
|
+
}
|
|
26082
|
+
openOverlay() {
|
|
26083
|
+
this.overlayMinWidth =
|
|
26084
|
+
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
|
|
26085
|
+
.width + 'px';
|
|
26086
|
+
this.overlayOpen = true;
|
|
26087
|
+
}
|
|
26088
|
+
closeOverlay() {
|
|
26089
|
+
this.overlayOpen = false;
|
|
26090
|
+
}
|
|
26091
|
+
toggleOverlay() {
|
|
26092
|
+
if (this.overlayOpen) {
|
|
26093
|
+
this.closeOverlay();
|
|
26094
|
+
}
|
|
26095
|
+
else {
|
|
26096
|
+
this.openOverlay();
|
|
26097
|
+
}
|
|
26098
|
+
}
|
|
26099
|
+
async handleFileSelected(file) {
|
|
26100
|
+
this.errorKey = null;
|
|
26101
|
+
let content;
|
|
26102
|
+
try {
|
|
26103
|
+
content = await readFileAsText(file);
|
|
26104
|
+
const parsed = JSON.parse(content);
|
|
26105
|
+
const geometry = getGeometryFromGeoJSON(parsed);
|
|
26106
|
+
if (!geometry) {
|
|
26107
|
+
this.setError(marker('search.filters.spatialExtent.error.noGeometry'));
|
|
26108
|
+
return;
|
|
26109
|
+
}
|
|
26110
|
+
const bbox = getGeometryBoundingBox(geometry);
|
|
26111
|
+
this.bbox = bbox;
|
|
26112
|
+
this.fileName = file.name;
|
|
26113
|
+
this.bboxChange.emit(bbox);
|
|
26114
|
+
this.cd.markForCheck();
|
|
26115
|
+
}
|
|
26116
|
+
catch {
|
|
26117
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26118
|
+
return;
|
|
26119
|
+
}
|
|
26120
|
+
}
|
|
26121
|
+
handleFileError(error) {
|
|
26122
|
+
if (error === 'file-too-large') {
|
|
26123
|
+
this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
|
|
26124
|
+
maxSize: this.maxFileSizeMb,
|
|
26125
|
+
});
|
|
26126
|
+
}
|
|
26127
|
+
else {
|
|
26128
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26129
|
+
}
|
|
26130
|
+
}
|
|
26131
|
+
setError(errorKey, params) {
|
|
26132
|
+
this.errorKey = errorKey;
|
|
26133
|
+
this.errorChange.emit({ key: errorKey, params });
|
|
26134
|
+
this.cd.markForCheck();
|
|
26135
|
+
}
|
|
26136
|
+
removeSelection(event) {
|
|
26137
|
+
this.bbox = null;
|
|
26138
|
+
this.fileName = '';
|
|
26139
|
+
this.errorKey = null;
|
|
26140
|
+
this.fileInput?.clear();
|
|
26141
|
+
this.bboxChange.emit(null);
|
|
26142
|
+
propagateToDocumentOnly(event);
|
|
26143
|
+
}
|
|
26144
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26145
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SpatialExtentDropdownComponent, isStandalone: true, selector: "gn-ui-spatial-extent-dropdown", inputs: { title: "title", maxFileSizeMb: "maxFileSizeMb", initialBbox: "initialBbox" }, outputs: { bboxChange: "bboxChange", errorChange: "errorChange" }, providers: [
|
|
26146
|
+
provideIcons({
|
|
26147
|
+
iconoirCheckCircle,
|
|
26148
|
+
iconoirImport,
|
|
26149
|
+
iconoirSquareDashed,
|
|
26150
|
+
iconoirTrash,
|
|
26151
|
+
matClose,
|
|
26152
|
+
matExpandLess,
|
|
26153
|
+
matExpandMore,
|
|
26154
|
+
}),
|
|
26155
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
26156
|
+
}
|
|
26157
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
|
|
26158
|
+
type: Component,
|
|
26159
|
+
args: [{ selector: 'gn-ui-spatial-extent-dropdown', standalone: true, imports: [
|
|
26160
|
+
ButtonComponent,
|
|
26161
|
+
NgIcon,
|
|
26162
|
+
OverlayModule,
|
|
26163
|
+
TranslatePipe,
|
|
26164
|
+
DragAndDropFileInputComponent,
|
|
26165
|
+
], providers: [
|
|
26166
|
+
provideIcons({
|
|
26167
|
+
iconoirCheckCircle,
|
|
26168
|
+
iconoirImport,
|
|
26169
|
+
iconoirSquareDashed,
|
|
26170
|
+
iconoirTrash,
|
|
26171
|
+
matClose,
|
|
26172
|
+
matExpandLess,
|
|
26173
|
+
matExpandMore,
|
|
26174
|
+
}),
|
|
26175
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
|
|
26176
|
+
}], propDecorators: { title: [{
|
|
26177
|
+
type: Input
|
|
26178
|
+
}], maxFileSizeMb: [{
|
|
26179
|
+
type: Input
|
|
26180
|
+
}], initialBbox: [{
|
|
26181
|
+
type: Input
|
|
26182
|
+
}], bboxChange: [{
|
|
26183
|
+
type: Output
|
|
26184
|
+
}], errorChange: [{
|
|
26185
|
+
type: Output
|
|
26186
|
+
}], overlayOrigin: [{
|
|
26187
|
+
type: ViewChild,
|
|
26188
|
+
args: ['overlayOrigin']
|
|
26189
|
+
}], overlay: [{
|
|
26190
|
+
type: ViewChild,
|
|
26191
|
+
args: [CdkConnectedOverlay]
|
|
26192
|
+
}], fileInput: [{
|
|
26193
|
+
type: ViewChild,
|
|
26194
|
+
args: [DragAndDropFileInputComponent]
|
|
26195
|
+
}] } });
|
|
26196
|
+
|
|
25739
26197
|
class CellPopinComponent {
|
|
25740
26198
|
constructor() {
|
|
25741
26199
|
this.scrollDispatcher = inject(ScrollDispatcher);
|
|
@@ -25812,7 +26270,7 @@ class CellPopinComponent {
|
|
|
25812
26270
|
this.isOpen = false;
|
|
25813
26271
|
}
|
|
25814
26272
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25815
|
-
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$
|
|
26273
|
+
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"] }] }); }
|
|
25816
26274
|
}
|
|
25817
26275
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, decorators: [{
|
|
25818
26276
|
type: Component,
|
|
@@ -27434,6 +27892,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
27434
27892
|
}]
|
|
27435
27893
|
}] });
|
|
27436
27894
|
|
|
27895
|
+
const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
|
|
27896
|
+
providedIn: 'root',
|
|
27897
|
+
factory: () => ['geonames', { maxRows: 5 }],
|
|
27898
|
+
});
|
|
27899
|
+
class GeocodingService {
|
|
27900
|
+
constructor() {
|
|
27901
|
+
this.provider = inject(GEOCODING_PROVIDER);
|
|
27902
|
+
}
|
|
27903
|
+
query(text) {
|
|
27904
|
+
let queryObservable;
|
|
27905
|
+
switch (this.provider[0]) {
|
|
27906
|
+
case 'geoadmin':
|
|
27907
|
+
queryObservable = from(queryGeoadmin(text, this.provider[1]));
|
|
27908
|
+
break;
|
|
27909
|
+
case 'geonames':
|
|
27910
|
+
queryObservable = from(queryGeonames(text, this.provider[1]));
|
|
27911
|
+
break;
|
|
27912
|
+
case 'data-gouv-fr':
|
|
27913
|
+
queryObservable = from(queryDataGouvFr(text, this.provider[1]));
|
|
27914
|
+
break;
|
|
27915
|
+
default:
|
|
27916
|
+
return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
|
|
27917
|
+
}
|
|
27918
|
+
return queryObservable.pipe(catchError((error) => throwError(error)));
|
|
27919
|
+
}
|
|
27920
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
27921
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
|
|
27922
|
+
}
|
|
27923
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
|
|
27924
|
+
type: Injectable,
|
|
27925
|
+
args: [{
|
|
27926
|
+
providedIn: 'root',
|
|
27927
|
+
}]
|
|
27928
|
+
}] });
|
|
27929
|
+
|
|
27930
|
+
class LocationSearchComponent {
|
|
27931
|
+
constructor() {
|
|
27932
|
+
this.geocodingService = inject(GeocodingService);
|
|
27933
|
+
this.placeholder = '';
|
|
27934
|
+
this.resultSelected = new EventEmitter();
|
|
27935
|
+
this.displayWithFn = (item) => item.label;
|
|
27936
|
+
this.searchAction = (text) => this.geocodingService.query(text);
|
|
27937
|
+
}
|
|
27938
|
+
handleItemSelected(item) {
|
|
27939
|
+
this.resultSelected.emit(item);
|
|
27940
|
+
}
|
|
27941
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
27942
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: LocationSearchComponent, isStandalone: true, selector: "gn-ui-location-search", inputs: { placeholder: "placeholder", displayWithTemplate: "displayWithTemplate" }, outputs: { resultSelected: "resultSelected" }, ngImport: i0, template: "<gn-ui-autocomplete\n [action]=\"searchAction\"\n [displayWithFn]=\"displayWithFn\"\n [placeholder]=\"placeholder\"\n [displayWithTemplate]=\"displayWithTemplate\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
27943
|
+
}
|
|
27944
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
|
|
27945
|
+
type: Component,
|
|
27946
|
+
args: [{ selector: 'gn-ui-location-search', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [AutocompleteComponent], template: "<gn-ui-autocomplete\n [action]=\"searchAction\"\n [displayWithFn]=\"displayWithFn\"\n [placeholder]=\"placeholder\"\n [displayWithTemplate]=\"displayWithTemplate\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\n" }]
|
|
27947
|
+
}], propDecorators: { placeholder: [{
|
|
27948
|
+
type: Input
|
|
27949
|
+
}], displayWithTemplate: [{
|
|
27950
|
+
type: Input
|
|
27951
|
+
}], resultSelected: [{
|
|
27952
|
+
type: Output
|
|
27953
|
+
}] } });
|
|
27954
|
+
|
|
27437
27955
|
// expects the replacement key ${uuid}
|
|
27438
27956
|
const RECORD_DATASET_URL_TOKEN = new InjectionToken('record-dataset-url-token');
|
|
27439
27957
|
const RECORD_SERVICE_URL_TOKEN = new InjectionToken('record-service-url-token');
|
|
@@ -27902,6 +28420,45 @@ class DateRangeSearchField extends SimpleSearchField {
|
|
|
27902
28420
|
return 'dateRange';
|
|
27903
28421
|
}
|
|
27904
28422
|
}
|
|
28423
|
+
// treats a resource's creation/revision dates as an interval (its min and max), so a record matches
|
|
28424
|
+
// when that interval intersects the filter range, not just when a single date falls inside it
|
|
28425
|
+
class ResourceCreationRevisionDateSearchField extends DateRangeSearchField {
|
|
28426
|
+
constructor(injector, order = 'desc') {
|
|
28427
|
+
super('resourceCreationRevisionDate', injector, order);
|
|
28428
|
+
const dateSourceFields = [
|
|
28429
|
+
'creationDateForResource',
|
|
28430
|
+
'revisionDateForResource',
|
|
28431
|
+
];
|
|
28432
|
+
const collectSortedDates = dateSourceFields
|
|
28433
|
+
.map((field) => `if (doc.containsKey('${field}')) {
|
|
28434
|
+
for (def date : doc['${field}']) { dates.add(date.millis); }
|
|
28435
|
+
}`)
|
|
28436
|
+
.join('\n');
|
|
28437
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMin', `def dates = [];
|
|
28438
|
+
${collectSortedDates}
|
|
28439
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[0]); }`, 'date');
|
|
28440
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMax', `def dates = [];
|
|
28441
|
+
${collectSortedDates}
|
|
28442
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[dates.length - 1]); }`, 'date');
|
|
28443
|
+
}
|
|
28444
|
+
}
|
|
28445
|
+
class BoundingBoxSearchField extends SimpleSearchField {
|
|
28446
|
+
getAvailableValues() {
|
|
28447
|
+
return of([]);
|
|
28448
|
+
}
|
|
28449
|
+
getFiltersForValues(values) {
|
|
28450
|
+
return of({
|
|
28451
|
+
[this.esFieldName]: values.map(Number),
|
|
28452
|
+
});
|
|
28453
|
+
}
|
|
28454
|
+
getValuesForFilter(filters) {
|
|
28455
|
+
const filter = filters[this.esFieldName];
|
|
28456
|
+
return of(isBoundingBox(filter) ? filter : []);
|
|
28457
|
+
}
|
|
28458
|
+
getType() {
|
|
28459
|
+
return 'spatialExtent';
|
|
28460
|
+
}
|
|
28461
|
+
}
|
|
27905
28462
|
marker('search.filters.availableServices.view');
|
|
27906
28463
|
marker('search.filters.availableServices.download');
|
|
27907
28464
|
class AvailableServicesField extends SimpleSearchField {
|
|
@@ -28046,6 +28603,8 @@ marker('search.filters.producerOrg');
|
|
|
28046
28603
|
marker('search.filters.publisherOrg');
|
|
28047
28604
|
marker('search.filters.user');
|
|
28048
28605
|
marker('search.filters.changeDate');
|
|
28606
|
+
marker('search.filters.resourceCreationRevisionDate');
|
|
28607
|
+
marker('search.filters.spatialExtent');
|
|
28049
28608
|
class FieldsService {
|
|
28050
28609
|
constructor() {
|
|
28051
28610
|
this.injector = inject(Injector);
|
|
@@ -28068,7 +28627,9 @@ class FieldsService {
|
|
|
28068
28627
|
publisherOrg: new MultilingualSearchField('distributorOrgForResourceObject', this.injector, 'asc', 'key'),
|
|
28069
28628
|
user: new UserSearchField(this.injector),
|
|
28070
28629
|
changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
|
|
28630
|
+
resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
|
|
28071
28631
|
availableServices: new AvailableServicesField(this.injector),
|
|
28632
|
+
spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
|
|
28072
28633
|
};
|
|
28073
28634
|
}
|
|
28074
28635
|
get supportedFields() {
|
|
@@ -29331,7 +29892,7 @@ class ContactPillComponent {
|
|
|
29331
29892
|
this.overlayOpen = false;
|
|
29332
29893
|
}
|
|
29333
29894
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29334
|
-
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$
|
|
29895
|
+
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 }); }
|
|
29335
29896
|
}
|
|
29336
29897
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, decorators: [{
|
|
29337
29898
|
type: Component,
|
|
@@ -30057,7 +30618,7 @@ class ServiceCapabilitiesComponent {
|
|
|
30057
30618
|
if (this.apiLinks.length > 0 &&
|
|
30058
30619
|
this.apiLinks[0].accessServiceProtocol !== 'ogcFeatures') {
|
|
30059
30620
|
this.loading = true;
|
|
30060
|
-
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol);
|
|
30621
|
+
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol, true);
|
|
30061
30622
|
this.loading = false;
|
|
30062
30623
|
this.cdr.detectChanges();
|
|
30063
30624
|
this.filteredLayers = this.availableLayers;
|
|
@@ -31253,19 +31814,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31253
31814
|
type: Output
|
|
31254
31815
|
}] } });
|
|
31255
31816
|
|
|
31817
|
+
class NotificationsService {
|
|
31818
|
+
constructor() {
|
|
31819
|
+
this.notifications$ = new BehaviorSubject([]);
|
|
31820
|
+
}
|
|
31821
|
+
showNotification(content, timeoutMs, error) {
|
|
31822
|
+
error && console.error(error);
|
|
31823
|
+
const id = Math.floor(Math.random() * 1000000);
|
|
31824
|
+
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31825
|
+
if (typeof timeoutMs !== 'undefined') {
|
|
31826
|
+
setTimeout(() => {
|
|
31827
|
+
this.removeNotificationById(id);
|
|
31828
|
+
}, timeoutMs);
|
|
31829
|
+
}
|
|
31830
|
+
return id;
|
|
31831
|
+
}
|
|
31832
|
+
removeNotificationById(id) {
|
|
31833
|
+
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31834
|
+
}
|
|
31835
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31836
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31837
|
+
}
|
|
31838
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31839
|
+
type: Injectable,
|
|
31840
|
+
args: [{
|
|
31841
|
+
providedIn: 'root',
|
|
31842
|
+
}]
|
|
31843
|
+
}] });
|
|
31844
|
+
|
|
31845
|
+
class NotificationsContainerComponent {
|
|
31846
|
+
constructor() {
|
|
31847
|
+
this.notificationsService = inject(NotificationsService);
|
|
31848
|
+
}
|
|
31849
|
+
trackById(index, notification) {
|
|
31850
|
+
return notification.id;
|
|
31851
|
+
}
|
|
31852
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31853
|
+
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: [
|
|
31854
|
+
trigger('enterExit', [
|
|
31855
|
+
transition(':enter', [
|
|
31856
|
+
animate('150ms', keyframes([
|
|
31857
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31858
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31859
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31860
|
+
])),
|
|
31861
|
+
]),
|
|
31862
|
+
transition(':leave', [
|
|
31863
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31864
|
+
]),
|
|
31865
|
+
]),
|
|
31866
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31867
|
+
}
|
|
31868
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31869
|
+
type: Component,
|
|
31870
|
+
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31871
|
+
trigger('enterExit', [
|
|
31872
|
+
transition(':enter', [
|
|
31873
|
+
animate('150ms', keyframes([
|
|
31874
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31875
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31876
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31877
|
+
])),
|
|
31878
|
+
]),
|
|
31879
|
+
transition(':leave', [
|
|
31880
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31881
|
+
]),
|
|
31882
|
+
]),
|
|
31883
|
+
], template: "<div class=\"flex flex-col gap-6 p-6 items-start pointer-events-none\">\n @for (\n notification of notificationsService.notifications$ | async;\n track trackById($index, notification)\n ) {\n <gn-ui-notification\n class=\"max-w-full pointer-events-auto\"\n [text]=\"notification.text\"\n [type]=\"notification.type\"\n [title]=\"notification.title\"\n [closeMessage]=\"notification.closeMessage\"\n (notificationClose)=\"\n notificationsService.removeNotificationById(notification.id)\n \"\n [@enterExit]\n ></gn-ui-notification>\n }\n</div>\n" }]
|
|
31884
|
+
}] });
|
|
31885
|
+
|
|
31256
31886
|
class FilterDropdownComponent {
|
|
31257
31887
|
constructor() {
|
|
31258
31888
|
this.searchFacade = inject(SearchFacade);
|
|
31259
31889
|
this.searchService = inject(SearchService);
|
|
31260
31890
|
this.fieldsService = inject(FieldsService);
|
|
31891
|
+
this.notificationsService = inject(NotificationsService);
|
|
31892
|
+
this.translateService = inject(TranslateService);
|
|
31893
|
+
this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
|
|
31261
31894
|
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([])));
|
|
31262
|
-
this.selectedDateRange$ = this.selected$.pipe(map$1((
|
|
31895
|
+
this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
|
|
31896
|
+
this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
|
|
31897
|
+
? selected
|
|
31898
|
+
: null));
|
|
31899
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31263
31900
|
}
|
|
31264
31901
|
onSelectedValues(values) {
|
|
31265
31902
|
this.fieldsService
|
|
31266
31903
|
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
31267
31904
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31268
31905
|
}
|
|
31906
|
+
onBboxChange(bbox) {
|
|
31907
|
+
this.fieldsService
|
|
31908
|
+
.buildFiltersFromFieldValues({
|
|
31909
|
+
[this.fieldName]: bbox,
|
|
31910
|
+
})
|
|
31911
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31912
|
+
this.clearSpatialExtentErrorNotification();
|
|
31913
|
+
}
|
|
31914
|
+
onSpatialExtentError(error) {
|
|
31915
|
+
this.clearSpatialExtentErrorNotification();
|
|
31916
|
+
this.spatialExtentErrorNotificationId =
|
|
31917
|
+
this.notificationsService.showNotification({
|
|
31918
|
+
type: 'error',
|
|
31919
|
+
title: this.translateService.instant('search.filters.spatialExtent.error.title'),
|
|
31920
|
+
text: this.translateService.instant(error.key, error.params),
|
|
31921
|
+
});
|
|
31922
|
+
}
|
|
31923
|
+
clearSpatialExtentErrorNotification() {
|
|
31924
|
+
if (this.spatialExtentErrorNotificationId === null)
|
|
31925
|
+
return;
|
|
31926
|
+
this.notificationsService.removeNotificationById(this.spatialExtentErrorNotificationId);
|
|
31927
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31928
|
+
}
|
|
31269
31929
|
ngOnInit() {
|
|
31270
31930
|
this.fieldType = this.fieldsService.getFieldType(this.fieldName);
|
|
31271
31931
|
this.choices$ = this.fieldsService.getAvailableValues(this.fieldName).pipe(startWith$1([]), map$1((values) => values.map((v) => ({
|
|
@@ -31273,27 +31933,15 @@ class FilterDropdownComponent {
|
|
|
31273
31933
|
value: v.value.toString(), // converting to string for the dropdown
|
|
31274
31934
|
}))), catchError(() => of([])));
|
|
31275
31935
|
}
|
|
31276
|
-
|
|
31277
|
-
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31282
|
-
if (!end)
|
|
31283
|
-
return;
|
|
31284
|
-
this.dateRange = { ...this.dateRange, end };
|
|
31285
|
-
if (this.dateRange.start && this.dateRange.end) {
|
|
31286
|
-
this.fieldsService
|
|
31287
|
-
.buildFiltersFromFieldValues({
|
|
31288
|
-
[this.fieldName]: this.dateRange,
|
|
31289
|
-
})
|
|
31290
|
-
.subscribe((filters) => {
|
|
31291
|
-
return this.searchService.updateFilters(filters);
|
|
31292
|
-
});
|
|
31293
|
-
}
|
|
31936
|
+
onDateRangeChange(dateRange) {
|
|
31937
|
+
this.fieldsService
|
|
31938
|
+
.buildFiltersFromFieldValues({
|
|
31939
|
+
[this.fieldName]: dateRange,
|
|
31940
|
+
})
|
|
31941
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31294
31942
|
}
|
|
31295
31943
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31296
|
-
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 [
|
|
31944
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FilterDropdownComponent, isStandalone: true, selector: "gn-ui-filter-dropdown", inputs: { fieldName: "fieldName", title: "title" }, ngImport: i0, template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DateRangeDropdownComponent, selector: "gn-ui-date-range-dropdown", inputs: ["title", "dateRange"], outputs: ["dateRangeChange"] }, { kind: "component", type: DropdownMultiselectComponent, selector: "gn-ui-dropdown-multiselect", inputs: ["title", "choices", "selected", "allowSearch", "maxRows", "searchInputValue"], outputs: ["selectValues"] }, { kind: "component", type: SpatialExtentDropdownComponent, selector: "gn-ui-spatial-extent-dropdown", inputs: ["title", "maxFileSizeMb", "initialBbox"], outputs: ["bboxChange", "errorChange"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31297
31945
|
}
|
|
31298
31946
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
|
|
31299
31947
|
type: Component,
|
|
@@ -31301,7 +31949,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31301
31949
|
CommonModule,
|
|
31302
31950
|
DateRangeDropdownComponent,
|
|
31303
31951
|
DropdownMultiselectComponent,
|
|
31304
|
-
|
|
31952
|
+
SpatialExtentDropdownComponent,
|
|
31953
|
+
], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n" }]
|
|
31305
31954
|
}], propDecorators: { fieldName: [{
|
|
31306
31955
|
type: Input
|
|
31307
31956
|
}], title: [{
|
|
@@ -31362,7 +32011,7 @@ class FuzzySearchComponent {
|
|
|
31362
32011
|
this.isSearchActive.emit(event);
|
|
31363
32012
|
}
|
|
31364
32013
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31365
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
32014
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31366
32015
|
}
|
|
31367
32016
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, decorators: [{
|
|
31368
32017
|
type: Component,
|
|
@@ -31771,11 +32420,7 @@ const SortByEnum = {
|
|
|
31771
32420
|
RELEVANCY: ['desc', '_score'],
|
|
31772
32421
|
QUALITY_SCORE: ['desc', 'qualityScore'],
|
|
31773
32422
|
CHANGE_DATE: ['desc', 'changeDate'],
|
|
31774
|
-
|
|
31775
|
-
['desc', 'revisionDateForResource'],
|
|
31776
|
-
['desc', 'publicationDateForResource'],
|
|
31777
|
-
['desc', 'creationDateForResource'],
|
|
31778
|
-
],
|
|
32423
|
+
RESOURCE_DATE: ['desc', 'resourceDate.date'],
|
|
31779
32424
|
};
|
|
31780
32425
|
|
|
31781
32426
|
class SortByComponent {
|
|
@@ -31789,7 +32434,7 @@ class SortByComponent {
|
|
|
31789
32434
|
},
|
|
31790
32435
|
{
|
|
31791
32436
|
label: marker('results.sortBy.dateStamp'),
|
|
31792
|
-
value: SortByEnum.
|
|
32437
|
+
value: SortByEnum.RESOURCE_DATE,
|
|
31793
32438
|
},
|
|
31794
32439
|
{
|
|
31795
32440
|
label: marker('results.sortBy.popularity'),
|
|
@@ -31841,74 +32486,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31841
32486
|
args: ['gnUiSearchStateContainer']
|
|
31842
32487
|
}] } });
|
|
31843
32488
|
|
|
31844
|
-
class NotificationsService {
|
|
31845
|
-
constructor() {
|
|
31846
|
-
this.notifications$ = new BehaviorSubject([]);
|
|
31847
|
-
}
|
|
31848
|
-
showNotification(content, timeoutMs, error) {
|
|
31849
|
-
error && console.error(error);
|
|
31850
|
-
const id = Math.floor(Math.random() * 1000000);
|
|
31851
|
-
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31852
|
-
if (typeof timeoutMs === 'undefined')
|
|
31853
|
-
return;
|
|
31854
|
-
setTimeout(() => {
|
|
31855
|
-
this.removeNotificationById(id);
|
|
31856
|
-
}, timeoutMs);
|
|
31857
|
-
}
|
|
31858
|
-
removeNotificationById(id) {
|
|
31859
|
-
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31860
|
-
}
|
|
31861
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31862
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31863
|
-
}
|
|
31864
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31865
|
-
type: Injectable,
|
|
31866
|
-
args: [{
|
|
31867
|
-
providedIn: 'root',
|
|
31868
|
-
}]
|
|
31869
|
-
}] });
|
|
31870
|
-
|
|
31871
|
-
class NotificationsContainerComponent {
|
|
31872
|
-
constructor() {
|
|
31873
|
-
this.notificationsService = inject(NotificationsService);
|
|
31874
|
-
}
|
|
31875
|
-
trackById(index, notification) {
|
|
31876
|
-
return notification.id;
|
|
31877
|
-
}
|
|
31878
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31879
|
-
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: [
|
|
31880
|
-
trigger('enterExit', [
|
|
31881
|
-
transition(':enter', [
|
|
31882
|
-
animate('150ms', keyframes([
|
|
31883
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31884
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31885
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31886
|
-
])),
|
|
31887
|
-
]),
|
|
31888
|
-
transition(':leave', [
|
|
31889
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31890
|
-
]),
|
|
31891
|
-
]),
|
|
31892
|
-
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31893
|
-
}
|
|
31894
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31895
|
-
type: Component,
|
|
31896
|
-
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31897
|
-
trigger('enterExit', [
|
|
31898
|
-
transition(':enter', [
|
|
31899
|
-
animate('150ms', keyframes([
|
|
31900
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31901
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31902
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31903
|
-
])),
|
|
31904
|
-
]),
|
|
31905
|
-
transition(':leave', [
|
|
31906
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31907
|
-
]),
|
|
31908
|
-
]),
|
|
31909
|
-
], 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" }]
|
|
31910
|
-
}] });
|
|
31911
|
-
|
|
31912
32489
|
class ResultsTableContainerComponent {
|
|
31913
32490
|
constructor() {
|
|
31914
32491
|
this.searchFacade = inject(SearchFacade);
|
|
@@ -31993,12 +32570,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31993
32570
|
|
|
31994
32571
|
marker('search.filters.summaryLabel.user');
|
|
31995
32572
|
marker('search.filters.summaryLabel.changeDate');
|
|
32573
|
+
marker('search.filters.summaryLabel.resourceCreationRevisionDate');
|
|
32574
|
+
const OPEN_BOUND = '…';
|
|
31996
32575
|
class SearchFiltersSummaryItemComponent {
|
|
31997
32576
|
constructor() {
|
|
31998
32577
|
this.searchFacade = inject(SearchFacade);
|
|
31999
32578
|
this.searchService = inject(SearchService);
|
|
32000
32579
|
this.fieldsService = inject(FieldsService);
|
|
32001
|
-
this.
|
|
32580
|
+
this.dateService = inject(DateService);
|
|
32002
32581
|
this.translate = inject(TranslateService);
|
|
32003
32582
|
this.fieldValues$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$2((fieldValues) => Array.isArray(fieldValues[this.fieldName])
|
|
32004
32583
|
? fieldValues[this.fieldName]
|
|
@@ -32025,9 +32604,10 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32025
32604
|
getReadableValues(fieldValues) {
|
|
32026
32605
|
return fieldValues.map((value) => {
|
|
32027
32606
|
if (this.fieldType === 'dateRange') {
|
|
32607
|
+
const { start, end } = value;
|
|
32028
32608
|
return {
|
|
32029
32609
|
value,
|
|
32030
|
-
label: `${this.
|
|
32610
|
+
label: `${this.formatBound(start)} - ${this.formatBound(end)}`,
|
|
32031
32611
|
};
|
|
32032
32612
|
}
|
|
32033
32613
|
else if (this.fieldName === 'user') {
|
|
@@ -32038,6 +32618,15 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32038
32618
|
}
|
|
32039
32619
|
});
|
|
32040
32620
|
}
|
|
32621
|
+
formatBound(date) {
|
|
32622
|
+
return date
|
|
32623
|
+
? this.dateService.formatDate(date, {
|
|
32624
|
+
day: '2-digit',
|
|
32625
|
+
month: '2-digit',
|
|
32626
|
+
year: 'numeric',
|
|
32627
|
+
})
|
|
32628
|
+
: OPEN_BOUND;
|
|
32629
|
+
}
|
|
32041
32630
|
async removeFilterValue(fieldValue) {
|
|
32042
32631
|
const currentFieldValues = await firstValueFrom(this.fieldValues$);
|
|
32043
32632
|
const updatedFieldValues = currentFieldValues
|
|
@@ -32050,11 +32639,11 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32050
32639
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
32051
32640
|
}
|
|
32052
32641
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32053
|
-
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" },
|
|
32642
|
+
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" }] }); }
|
|
32054
32643
|
}
|
|
32055
32644
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, decorators: [{
|
|
32056
32645
|
type: Component,
|
|
32057
|
-
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent],
|
|
32646
|
+
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" }]
|
|
32058
32647
|
}], propDecorators: { fieldName: [{
|
|
32059
32648
|
type: Input
|
|
32060
32649
|
}] } });
|
|
@@ -32298,11 +32887,11 @@ class AddLayerFromFileComponent {
|
|
|
32298
32887
|
}, 5000);
|
|
32299
32888
|
}
|
|
32300
32889
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32301
|
-
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" }] }); }
|
|
32890
|
+
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" }] }); }
|
|
32302
32891
|
}
|
|
32303
32892
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, decorators: [{
|
|
32304
32893
|
type: Component,
|
|
32305
|
-
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" }]
|
|
32894
|
+
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" }]
|
|
32306
32895
|
}] });
|
|
32307
32896
|
|
|
32308
32897
|
class LayersPanelComponent {
|
|
@@ -32363,95 +32952,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
32363
32952
|
], template: "<div\n class=\"bg-white rounded shadow shadow-lg relative h-full w-[400px] overflow-hidden\"\n>\n <div class=\"p-3 border-b border-gray-300 flex items-center\">\n <ng-icon class=\"mr-2\" name=\"matLayersOutline\"></ng-icon>\n <span translate>map.layers.list</span>\n </div>\n <div class=\"flex flex-col px-4 divide-y divide-y-gray-50\">\n @for (layer of layers$ | async; track layer; let index = $index) {\n <div class=\"flex flex-row py-3\">\n <ng-icon class=\"-ml-2 mr-2 shrink-0\" name=\"matChevronRight\"></ng-icon>\n <span class=\"mr-2 grow\">{{ layer.label }}</span>\n <a\n href\n class=\"underline text-sm text-red-700 hover:text-red-900\"\n (click)=\"deleteLayer(index); $event.preventDefault()\"\n >\n delete\n </a>\n </div>\n }\n </div>\n <gn-ui-expandable-panel-button [titleTemplate]=\"addLayerTitle\">\n <mat-tab-group animationDuration=\"200ms\" class=\"h-full\">\n <mat-tab [label]=\"'map.add.layer.catalog' | translate\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-catalog></gn-ui-add-layer-from-catalog>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wms' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wms></gn-ui-add-layer-from-wms>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wfs' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wfs></gn-ui-add-layer-from-wfs>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.ogc.api' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-ogc-api\n [ogcUrl]=\"ogcUrl\"\n (layerAdded)=\"addLayer($event)\"\n ></gn-ui-add-layer-from-ogc-api>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.file' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-file></gn-ui-add-layer-from-file>\n </div>\n </mat-tab>\n </mat-tab-group>\n </gn-ui-expandable-panel-button>\n</div>\n\n<ng-template #addLayerTitle>\n <ng-icon class=\"mr-4\" name=\"matAddCircleOutlineOutline\"> </ng-icon>\n <span translate>map.add.layer</span>\n</ng-template>\n" }]
|
|
32364
32953
|
}] });
|
|
32365
32954
|
|
|
32366
|
-
class GeocodingComponent {
|
|
32367
|
-
constructor() {
|
|
32368
|
-
this.mapFacade = inject(MapFacade);
|
|
32369
|
-
this.geocodingService = inject(GeocodingService);
|
|
32370
|
-
this.searchText = '';
|
|
32371
|
-
this.results = [];
|
|
32372
|
-
this.searchTextChanged = new Subject();
|
|
32373
|
-
this.destroy$ = new Subject();
|
|
32374
|
-
this.errorMessage = null;
|
|
32375
|
-
this.searchTextChanged
|
|
32376
|
-
.pipe(debounceTime(300), switchMap$1((searchText) => {
|
|
32377
|
-
return from(this.geocodingService.query(searchText)).pipe(catchError$1((error) => {
|
|
32378
|
-
this.errorMessage =
|
|
32379
|
-
'An error occurred while searching. Please try again.';
|
|
32380
|
-
console.error(error);
|
|
32381
|
-
return [];
|
|
32382
|
-
}));
|
|
32383
|
-
}), takeUntil(this.destroy$))
|
|
32384
|
-
.subscribe((results) => {
|
|
32385
|
-
this.results = results;
|
|
32386
|
-
});
|
|
32387
|
-
}
|
|
32388
|
-
ngOnDestroy() {
|
|
32389
|
-
this.destroy$.next();
|
|
32390
|
-
this.destroy$.complete();
|
|
32391
|
-
}
|
|
32392
|
-
onSearchChange(searchText) {
|
|
32393
|
-
if (!searchText) {
|
|
32394
|
-
this.clearSearch();
|
|
32395
|
-
return;
|
|
32396
|
-
}
|
|
32397
|
-
else {
|
|
32398
|
-
this.searchTextChanged.next(searchText);
|
|
32399
|
-
}
|
|
32400
|
-
}
|
|
32401
|
-
clearSearch() {
|
|
32402
|
-
this.searchText = '';
|
|
32403
|
-
this.results = [];
|
|
32404
|
-
this.errorMessage = null;
|
|
32405
|
-
}
|
|
32406
|
-
async zoomToLocation(result) {
|
|
32407
|
-
const geometry = result.geom;
|
|
32408
|
-
if (geometry.type === 'Point') {
|
|
32409
|
-
await this.zoomToPoint(geometry.coordinates);
|
|
32410
|
-
}
|
|
32411
|
-
else if (geometry.type === 'Polygon') {
|
|
32412
|
-
await this.zoomToPolygon(geometry.coordinates);
|
|
32413
|
-
}
|
|
32414
|
-
else {
|
|
32415
|
-
console.error(`Unsupported geometry type: ${geometry.type}`);
|
|
32416
|
-
}
|
|
32417
|
-
}
|
|
32418
|
-
async zoomToPoint(pointCoords) {
|
|
32419
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32420
|
-
const view = {
|
|
32421
|
-
center: pointCoords,
|
|
32422
|
-
zoom: 10,
|
|
32423
|
-
};
|
|
32424
|
-
this.mapFacade.applyContext({
|
|
32425
|
-
...context,
|
|
32426
|
-
view,
|
|
32427
|
-
});
|
|
32428
|
-
}
|
|
32429
|
-
async zoomToPolygon(polygonCoords) {
|
|
32430
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32431
|
-
const view = {
|
|
32432
|
-
geometry: {
|
|
32433
|
-
type: 'Polygon',
|
|
32434
|
-
coordinates: polygonCoords,
|
|
32435
|
-
},
|
|
32436
|
-
};
|
|
32437
|
-
this.mapFacade.applyContext({
|
|
32438
|
-
...context,
|
|
32439
|
-
view,
|
|
32440
|
-
});
|
|
32441
|
-
}
|
|
32442
|
-
onEnterPress() {
|
|
32443
|
-
if (this.results && this.results.length > 0) {
|
|
32444
|
-
this.zoomToLocation(this.results[0]);
|
|
32445
|
-
}
|
|
32446
|
-
}
|
|
32447
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32448
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GeocodingComponent, isStandalone: true, selector: "gn-ui-geocoding", ngImport: i0, template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n", styles: [""], dependencies: [{ kind: "component", type: SearchInputComponent, selector: "gn-ui-search-input", inputs: ["value", "placeholder"], outputs: ["valueChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
32449
|
-
}
|
|
32450
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, decorators: [{
|
|
32451
|
-
type: Component,
|
|
32452
|
-
args: [{ selector: 'gn-ui-geocoding', standalone: true, imports: [SearchInputComponent, TranslatePipe], template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n" }]
|
|
32453
|
-
}], ctorParameters: () => [] });
|
|
32454
|
-
|
|
32455
32955
|
/*
|
|
32456
32956
|
Metadata actions
|
|
32457
32957
|
*/
|
|
@@ -32467,8 +32967,7 @@ const closeMetadata = createAction('[Metadata view] close');
|
|
|
32467
32967
|
Related actions
|
|
32468
32968
|
*/
|
|
32469
32969
|
const setRelated = createAction('[Metadata view] Set related records', props());
|
|
32470
|
-
const
|
|
32471
|
-
const setSourceOf = createAction('[Metadata view] Set has sources', props());
|
|
32970
|
+
const setLinkedRecords = createAction('[Metadata view] Set associated records', props());
|
|
32472
32971
|
/*
|
|
32473
32972
|
ChartConfig actions
|
|
32474
32973
|
*/
|
|
@@ -32500,9 +32999,8 @@ var mdview_actions = /*#__PURE__*/Object.freeze({
|
|
|
32500
32999
|
loadUserFeedbacksSuccess: loadUserFeedbacksSuccess,
|
|
32501
33000
|
setChartConfig: setChartConfig,
|
|
32502
33001
|
setIncompleteMetadata: setIncompleteMetadata,
|
|
32503
|
-
|
|
32504
|
-
|
|
32505
|
-
setSources: setSources
|
|
33002
|
+
setLinkedRecords: setLinkedRecords,
|
|
33003
|
+
setRelated: setRelated
|
|
32506
33004
|
});
|
|
32507
33005
|
|
|
32508
33006
|
const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView';
|
|
@@ -32545,12 +33043,9 @@ on(loadFullMetadata, (state) => ({
|
|
|
32545
33043
|
on(setRelated, (state, { related }) => ({
|
|
32546
33044
|
...state,
|
|
32547
33045
|
related,
|
|
32548
|
-
})), on(
|
|
32549
|
-
...state,
|
|
32550
|
-
sources,
|
|
32551
|
-
})), on(setSourceOf, (state, { sourceOf }) => ({
|
|
33046
|
+
})), on(setLinkedRecords, (state, { linkedRecords }) => ({
|
|
32552
33047
|
...state,
|
|
32553
|
-
|
|
33048
|
+
linkedRecords,
|
|
32554
33049
|
})),
|
|
32555
33050
|
/*
|
|
32556
33051
|
ChartConfig reducers
|
|
@@ -32612,8 +33107,7 @@ const getMetadataError = createSelector(getMdViewState, (state) => state.error);
|
|
|
32612
33107
|
Related selectors
|
|
32613
33108
|
*/
|
|
32614
33109
|
const getRelated = createSelector(getMdViewState, (state) => state.related);
|
|
32615
|
-
const
|
|
32616
|
-
const getSourceOf = createSelector(getMdViewState, (state) => state.sourceOf);
|
|
33110
|
+
const getLinkedRecords = createSelector(getMdViewState, (state) => state.linkedRecords);
|
|
32617
33111
|
/*
|
|
32618
33112
|
Metadata selectors
|
|
32619
33113
|
*/
|
|
@@ -32714,212 +33208,10 @@ function parseHeaders(httpHeaders) {
|
|
|
32714
33208
|
return result;
|
|
32715
33209
|
}
|
|
32716
33210
|
|
|
32717
|
-
|
|
32718
|
-
|
|
32719
|
-
|
|
32720
|
-
? fileExtensionMatches[1].toLowerCase()
|
|
32721
|
-
: null;
|
|
32722
|
-
// 1. type hint
|
|
32723
|
-
if (typeHint)
|
|
32724
|
-
return Promise.resolve(typeHint);
|
|
32725
|
-
// 2. content-type header
|
|
32726
|
-
const headers = await fetchHeaders(url);
|
|
32727
|
-
if ('supportedType' in headers)
|
|
32728
|
-
return headers.supportedType;
|
|
32729
|
-
// 3. file extension from url
|
|
32730
|
-
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
32731
|
-
return fileExtension;
|
|
32732
|
-
// no type inferred or hinted
|
|
32733
|
-
if ('mimeType' in headers)
|
|
32734
|
-
throw FetchError.unsupportedType(headers.mimeType);
|
|
32735
|
-
else
|
|
32736
|
-
throw FetchError.unknownType();
|
|
33211
|
+
const GEOMETRY_COLUMN_ALIAS = '__geometry__';
|
|
33212
|
+
function fieldToSql(name) {
|
|
33213
|
+
return `"${name.replace(/"/g, '""')}"`; // escape double quotes in field names
|
|
32737
33214
|
}
|
|
32738
|
-
function fetchHeaders(url) {
|
|
32739
|
-
return sharedFetch(url, 'HEAD')
|
|
32740
|
-
.catch((error) => {
|
|
32741
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32742
|
-
})
|
|
32743
|
-
.then((response) => {
|
|
32744
|
-
if (!response.ok) {
|
|
32745
|
-
throw FetchError.http(response.status);
|
|
32746
|
-
}
|
|
32747
|
-
return parseHeaders(response.headers);
|
|
32748
|
-
});
|
|
32749
|
-
}
|
|
32750
|
-
function fetchDataAsText(url, cacheActive) {
|
|
32751
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32752
|
-
.catch((error) => {
|
|
32753
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32754
|
-
})
|
|
32755
|
-
.then(async (response) => {
|
|
32756
|
-
if (!response.ok) {
|
|
32757
|
-
const clonedResponse = response.clone();
|
|
32758
|
-
throw FetchError.http(response.status, await clonedResponse.text());
|
|
32759
|
-
}
|
|
32760
|
-
const clonedResponse = response.clone();
|
|
32761
|
-
return clonedResponse.text();
|
|
32762
|
-
});
|
|
32763
|
-
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
32764
|
-
}
|
|
32765
|
-
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
32766
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32767
|
-
.catch((error) => {
|
|
32768
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32769
|
-
})
|
|
32770
|
-
.then(async (response) => {
|
|
32771
|
-
if (!response.ok) {
|
|
32772
|
-
throw FetchError.http(response.status, await response.text());
|
|
32773
|
-
}
|
|
32774
|
-
// convert to a numeric array so that we can store the response in cache
|
|
32775
|
-
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
32776
|
-
});
|
|
32777
|
-
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
32778
|
-
return new Uint8Array(array).buffer;
|
|
32779
|
-
});
|
|
32780
|
-
}
|
|
32781
|
-
function tryParseDate(input) {
|
|
32782
|
-
if (typeof input !== 'string')
|
|
32783
|
-
return null;
|
|
32784
|
-
function tryIso(value) {
|
|
32785
|
-
const parsed = parseISO(value);
|
|
32786
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32787
|
-
}
|
|
32788
|
-
function tryFormat(value, format) {
|
|
32789
|
-
const parsed = parse$4(value, format, new Date());
|
|
32790
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32791
|
-
}
|
|
32792
|
-
return (tryIso(input) ||
|
|
32793
|
-
tryFormat(input, 'dd/MM/yyyy') ||
|
|
32794
|
-
tryFormat(input, 'dd.MM.yyyy') ||
|
|
32795
|
-
tryFormat(input, 'MM/dd/yyyy') ||
|
|
32796
|
-
null);
|
|
32797
|
-
}
|
|
32798
|
-
function tryParseNumber(input) {
|
|
32799
|
-
if (isNaN(input))
|
|
32800
|
-
return null;
|
|
32801
|
-
const parsed = parseFloat(input);
|
|
32802
|
-
return isNaN(parsed) ? null : parsed;
|
|
32803
|
-
}
|
|
32804
|
-
function jsonToGeojsonFeature(object) {
|
|
32805
|
-
const { id, properties } = Object.keys(object)
|
|
32806
|
-
.map((property) => (property ? property : 'unknown')) //prevent empty strings
|
|
32807
|
-
.reduce((prev, curr) => curr.toLowerCase().endsWith('id')
|
|
32808
|
-
? {
|
|
32809
|
-
...prev,
|
|
32810
|
-
id: object[curr],
|
|
32811
|
-
}
|
|
32812
|
-
: {
|
|
32813
|
-
...prev,
|
|
32814
|
-
properties: { ...prev.properties, [curr]: object[curr] },
|
|
32815
|
-
}, { id: undefined, properties: {} });
|
|
32816
|
-
return {
|
|
32817
|
-
type: 'Feature',
|
|
32818
|
-
geometry: null,
|
|
32819
|
-
properties,
|
|
32820
|
-
...(id !== undefined && { id }),
|
|
32821
|
-
};
|
|
32822
|
-
}
|
|
32823
|
-
function mutateProperties(items, mutators) {
|
|
32824
|
-
const mutatorKeys = Object.keys(mutators);
|
|
32825
|
-
for (let i = 0, ii = items.length; i < ii; i++) {
|
|
32826
|
-
const item = items[i];
|
|
32827
|
-
for (const mutatorField of mutatorKeys) {
|
|
32828
|
-
if (!(mutatorField in item.properties))
|
|
32829
|
-
continue;
|
|
32830
|
-
item.properties[mutatorField] = mutators[mutatorField](item.properties[mutatorField]);
|
|
32831
|
-
}
|
|
32832
|
-
}
|
|
32833
|
-
return items;
|
|
32834
|
-
}
|
|
32835
|
-
const SAMPLE_SIZE = 20;
|
|
32836
|
-
/**
|
|
32837
|
-
* This will infer field types from a list of data items and cast the values accordingly
|
|
32838
|
-
* @param items
|
|
32839
|
-
* @param inferTypes
|
|
32840
|
-
*/
|
|
32841
|
-
function processItemProperties(items, inferTypes = false) {
|
|
32842
|
-
const foundFields = {};
|
|
32843
|
-
for (let i = 0, ii = Math.min(SAMPLE_SIZE, items.length); i < ii; i++) {
|
|
32844
|
-
const item = items[i];
|
|
32845
|
-
const fields = Object.keys(item.properties);
|
|
32846
|
-
for (const field of fields) {
|
|
32847
|
-
if (!(field in foundFields)) {
|
|
32848
|
-
foundFields[field] = {
|
|
32849
|
-
label: field,
|
|
32850
|
-
name: field,
|
|
32851
|
-
type: null,
|
|
32852
|
-
};
|
|
32853
|
-
}
|
|
32854
|
-
const value = item.properties[field];
|
|
32855
|
-
const info = foundFields[field];
|
|
32856
|
-
if (value === undefined || value === '' || value === null)
|
|
32857
|
-
continue;
|
|
32858
|
-
if (!inferTypes) {
|
|
32859
|
-
if (info.type === null && typeof value === 'number') {
|
|
32860
|
-
info.type = 'number';
|
|
32861
|
-
}
|
|
32862
|
-
else if (info.type === 'number' && typeof value !== 'number') {
|
|
32863
|
-
info.type = 'string';
|
|
32864
|
-
}
|
|
32865
|
-
continue;
|
|
32866
|
-
}
|
|
32867
|
-
const parsedNumber = tryParseNumber(value);
|
|
32868
|
-
if (info.type === null && parsedNumber !== null) {
|
|
32869
|
-
info.type = 'number';
|
|
32870
|
-
continue;
|
|
32871
|
-
}
|
|
32872
|
-
else if (info.type === 'number' && parsedNumber === null) {
|
|
32873
|
-
info.type = 'string';
|
|
32874
|
-
continue;
|
|
32875
|
-
}
|
|
32876
|
-
const parsedDate = tryParseDate(value);
|
|
32877
|
-
if (info.type === null && parsedDate !== null) {
|
|
32878
|
-
info.type = 'date';
|
|
32879
|
-
}
|
|
32880
|
-
else if (info.type === 'date' && parsedDate === null) {
|
|
32881
|
-
info.type = 'string';
|
|
32882
|
-
}
|
|
32883
|
-
}
|
|
32884
|
-
}
|
|
32885
|
-
const properties = [];
|
|
32886
|
-
const mutators = {};
|
|
32887
|
-
for (const field in foundFields) {
|
|
32888
|
-
const info = foundFields[field];
|
|
32889
|
-
if (info.type === 'number') {
|
|
32890
|
-
mutators[field] = tryParseNumber;
|
|
32891
|
-
}
|
|
32892
|
-
else if (info.type === 'date') {
|
|
32893
|
-
mutators[field] = tryParseDate;
|
|
32894
|
-
}
|
|
32895
|
-
properties.push({ ...info, type: info.type || 'string' });
|
|
32896
|
-
}
|
|
32897
|
-
if (inferTypes) {
|
|
32898
|
-
mutateProperties(items, mutators);
|
|
32899
|
-
}
|
|
32900
|
-
return { items, properties };
|
|
32901
|
-
}
|
|
32902
|
-
/**
|
|
32903
|
-
* This creates a Proxy that allows reading and writing to the data item properties
|
|
32904
|
-
* as if it was a simple array of JSON objects
|
|
32905
|
-
* @param items
|
|
32906
|
-
*/
|
|
32907
|
-
function getJsonDataItemsProxy(items) {
|
|
32908
|
-
return new Proxy(items, {
|
|
32909
|
-
get(target, p) {
|
|
32910
|
-
if (typeof p === 'string' &&
|
|
32911
|
-
!Number.isNaN(parseInt(p)) &&
|
|
32912
|
-
target[p]?.properties) {
|
|
32913
|
-
return target[p].properties;
|
|
32914
|
-
}
|
|
32915
|
-
return target[p];
|
|
32916
|
-
},
|
|
32917
|
-
set() {
|
|
32918
|
-
throw new Error('This object is read-only');
|
|
32919
|
-
},
|
|
32920
|
-
});
|
|
32921
|
-
}
|
|
32922
|
-
|
|
32923
33215
|
function filterToSql(filter) {
|
|
32924
33216
|
const operator = filter[0];
|
|
32925
33217
|
const args = filter.slice(1);
|
|
@@ -32934,10 +33226,10 @@ function filterToSql(filter) {
|
|
|
32934
33226
|
case '=':
|
|
32935
33227
|
case '!=':
|
|
32936
33228
|
case 'like':
|
|
32937
|
-
return
|
|
33229
|
+
return `${fieldToSql(args[0])} ${operator.toUpperCase()} ${valueToSql(args[1])}`;
|
|
32938
33230
|
case 'in': {
|
|
32939
33231
|
const values = args.slice(1);
|
|
32940
|
-
return
|
|
33232
|
+
return `${fieldToSql(args[0])} IN (${values.map(valueToSql).join(', ')})`;
|
|
32941
33233
|
}
|
|
32942
33234
|
case 'and':
|
|
32943
33235
|
case 'or': {
|
|
@@ -32956,17 +33248,18 @@ function aggregationToSql(aggregation) {
|
|
|
32956
33248
|
const field = aggregation[1];
|
|
32957
33249
|
switch (operation) {
|
|
32958
33250
|
case 'average':
|
|
32959
|
-
return `AVG(
|
|
33251
|
+
return `CAST(AVG(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`average(${field})`)}`;
|
|
32960
33252
|
case 'sum':
|
|
32961
33253
|
case 'max':
|
|
32962
33254
|
case 'min':
|
|
32963
|
-
return
|
|
33255
|
+
return `CAST(${operation.toUpperCase()}(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`${operation}(${field})`)}`;
|
|
32964
33256
|
case 'count':
|
|
32965
|
-
return 'COUNT(*) as
|
|
33257
|
+
return 'CAST(COUNT(*) AS INTEGER) as "count()"'; // we don't need Bigint precision here
|
|
32966
33258
|
}
|
|
32967
33259
|
}
|
|
32968
33260
|
/**
|
|
32969
33261
|
* Leave arguments at null if not used
|
|
33262
|
+
* @param tableName
|
|
32970
33263
|
* @param selected
|
|
32971
33264
|
* @param filter
|
|
32972
33265
|
* @param sort
|
|
@@ -32975,22 +33268,25 @@ function aggregationToSql(aggregation) {
|
|
|
32975
33268
|
* @param groupBy
|
|
32976
33269
|
* @param aggregations
|
|
32977
33270
|
*/
|
|
32978
|
-
function generateSqlQuery(selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null) {
|
|
33271
|
+
function generateSqlQuery(tableName, selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null, geometryColumn = null) {
|
|
32979
33272
|
let sqlSelect = 'SELECT *';
|
|
32980
|
-
const sqlFrom =
|
|
33273
|
+
const sqlFrom = ` FROM ${tableName}`;
|
|
32981
33274
|
let sqlOrderBy = '';
|
|
32982
33275
|
let sqlWhere = '';
|
|
32983
33276
|
let sqlLimit = '';
|
|
32984
33277
|
let sqlGroupBy = '';
|
|
32985
33278
|
if (selected !== null) {
|
|
32986
|
-
sqlSelect = `SELECT ${selected.map(
|
|
33279
|
+
sqlSelect = `SELECT ${selected.map(fieldToSql).join(', ')}`;
|
|
33280
|
+
}
|
|
33281
|
+
if (geometryColumn !== null) {
|
|
33282
|
+
sqlSelect += `, ST_AsGeoJSON(${fieldToSql(geometryColumn)}) as ${GEOMETRY_COLUMN_ALIAS}`;
|
|
32987
33283
|
}
|
|
32988
33284
|
if (filter !== null) {
|
|
32989
33285
|
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
32990
33286
|
}
|
|
32991
33287
|
if (sort?.length) {
|
|
32992
33288
|
sqlOrderBy = ` ORDER BY ${sort
|
|
32993
|
-
.map((sort) =>
|
|
33289
|
+
.map((sort) => `${fieldToSql(sort[1])} ${sort[0].toUpperCase()}`)
|
|
32994
33290
|
.join(', ')}`;
|
|
32995
33291
|
}
|
|
32996
33292
|
if (startIndex !== null && count !== null) {
|
|
@@ -33000,17 +33296,212 @@ function generateSqlQuery(selected = null, filter = null, sort = null, startInde
|
|
|
33000
33296
|
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33001
33297
|
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33002
33298
|
const sqlGroupByFields = groupedByDistinct
|
|
33003
|
-
.map((group) =>
|
|
33299
|
+
.map((group) => fieldToSql(group[1]))
|
|
33004
33300
|
.join(', ');
|
|
33005
33301
|
const sqlGroupBySelect = groupedByDistinct
|
|
33006
|
-
.map((group) =>
|
|
33302
|
+
.map((group) => `${fieldToSql(group[1])} as ${fieldToSql(`distinct(${group[1]})`)}`)
|
|
33007
33303
|
.join(', ');
|
|
33008
33304
|
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33009
33305
|
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33010
33306
|
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33011
33307
|
}
|
|
33012
33308
|
}
|
|
33013
|
-
return sqlSelect + sqlFrom + sqlGroupBy +
|
|
33309
|
+
return sqlSelect + sqlFrom + sqlGroupBy + sqlWhere + sqlOrderBy + sqlLimit;
|
|
33310
|
+
}
|
|
33311
|
+
|
|
33312
|
+
function arrowTableToDataItems(table) {
|
|
33313
|
+
const fields = table.schema.fields;
|
|
33314
|
+
return table.toArray().map((row) => {
|
|
33315
|
+
const rowJson = row.toJSON();
|
|
33316
|
+
const feature = {
|
|
33317
|
+
type: 'Feature',
|
|
33318
|
+
geometry: null,
|
|
33319
|
+
properties: {},
|
|
33320
|
+
};
|
|
33321
|
+
const keys = Object.keys(rowJson);
|
|
33322
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33323
|
+
const key = keys[i];
|
|
33324
|
+
const dataType = fields[i].type;
|
|
33325
|
+
let value = rowJson[key];
|
|
33326
|
+
// this might happen if we get an array inside a field
|
|
33327
|
+
if (value instanceof Vector) {
|
|
33328
|
+
value = Array.from(value);
|
|
33329
|
+
}
|
|
33330
|
+
// cast bigints to ints
|
|
33331
|
+
if (typeof value === 'bigint') {
|
|
33332
|
+
value = Number(value);
|
|
33333
|
+
}
|
|
33334
|
+
// rename columns with empty name
|
|
33335
|
+
if (!key) {
|
|
33336
|
+
feature.properties['unknown'] = value;
|
|
33337
|
+
continue;
|
|
33338
|
+
}
|
|
33339
|
+
// assign properties that look like an id to the geojson `id` field
|
|
33340
|
+
if (/^(object|feature)?_?id$/.test(key.toLowerCase()) &&
|
|
33341
|
+
(typeof value == 'string' || typeof value === 'number')) {
|
|
33342
|
+
feature.id = value;
|
|
33343
|
+
}
|
|
33344
|
+
// if a date is in timestamp (number) format, convert it to native
|
|
33345
|
+
if (typeof value === 'number' &&
|
|
33346
|
+
(DataType.isTimestamp(dataType) || DataType.isDate(dataType))) {
|
|
33347
|
+
value = new Date(value);
|
|
33348
|
+
}
|
|
33349
|
+
// if a binary field (most likely a geometry column): skip
|
|
33350
|
+
if (DataType.isBinary(dataType)) {
|
|
33351
|
+
continue;
|
|
33352
|
+
}
|
|
33353
|
+
// geometry column
|
|
33354
|
+
if (key === GEOMETRY_COLUMN_ALIAS && DataType.isUtf8(dataType)) {
|
|
33355
|
+
feature.geometry = JSON.parse(value);
|
|
33356
|
+
continue;
|
|
33357
|
+
}
|
|
33358
|
+
feature.properties[key] = value;
|
|
33359
|
+
}
|
|
33360
|
+
return feature;
|
|
33361
|
+
});
|
|
33362
|
+
}
|
|
33363
|
+
|
|
33364
|
+
// init code taken from https://github.com/duckdb/duckdb-wasm/blob/main/packages/duckdb-wasm/README.md
|
|
33365
|
+
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
|
33366
|
+
// from https://duckdb.org/docs/current/sql/data_types/overview
|
|
33367
|
+
const typesMapping = {
|
|
33368
|
+
INTEGER: 'number',
|
|
33369
|
+
SMALLINT: 'number',
|
|
33370
|
+
TINYINT: 'number',
|
|
33371
|
+
BIGINT: 'number',
|
|
33372
|
+
HUGEINT: 'number',
|
|
33373
|
+
UINTEGER: 'number',
|
|
33374
|
+
USMALLINT: 'number',
|
|
33375
|
+
UTINYINT: 'number',
|
|
33376
|
+
UBIGINT: 'number',
|
|
33377
|
+
UHUGEINT: 'number',
|
|
33378
|
+
DOUBLE: 'number',
|
|
33379
|
+
BIGNUM: 'number',
|
|
33380
|
+
DECIMAL: 'number',
|
|
33381
|
+
NUMERIC: 'number',
|
|
33382
|
+
FLOAT: 'number',
|
|
33383
|
+
REAL: 'number',
|
|
33384
|
+
'TIMESTAMP WITH TIME ZONE': 'date',
|
|
33385
|
+
TIMESTAMP: 'date',
|
|
33386
|
+
DATE: 'date',
|
|
33387
|
+
CHAR: 'string',
|
|
33388
|
+
VARCHAR: 'string',
|
|
33389
|
+
TEXT: 'string',
|
|
33390
|
+
UUID: 'string',
|
|
33391
|
+
BLOB: 'string',
|
|
33392
|
+
BIT: 'string',
|
|
33393
|
+
INTERVAL: 'string',
|
|
33394
|
+
LIST: 'string',
|
|
33395
|
+
BOOLEAN: 'boolean',
|
|
33396
|
+
};
|
|
33397
|
+
class Engine {
|
|
33398
|
+
async makeInit() {
|
|
33399
|
+
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
|
|
33400
|
+
let worker_url = bundle.mainWorker;
|
|
33401
|
+
// this is necessary to let browsers execute WASM code coming from a cross-origin host
|
|
33402
|
+
if (worker_url.startsWith('https://')) {
|
|
33403
|
+
worker_url = URL.createObjectURL(new Blob([`importScripts("${worker_url}");`], {
|
|
33404
|
+
type: 'text/javascript',
|
|
33405
|
+
}));
|
|
33406
|
+
}
|
|
33407
|
+
const worker = new Worker(worker_url);
|
|
33408
|
+
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
|
|
33409
|
+
this.db = new duckdb.AsyncDuckDB(logger, worker);
|
|
33410
|
+
await this.db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
33411
|
+
// setup duckdb options
|
|
33412
|
+
const conn = await this.db.connect();
|
|
33413
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33414
|
+
await conn.query(`INSTALL spatial; LOAD spatial;`);
|
|
33415
|
+
await conn.query(`SET TimeZone = '${timezone}';`);
|
|
33416
|
+
await conn.query(`SET threads = 1;`);
|
|
33417
|
+
// await conn.query(`SET memory_limit = '2GB';`) // used for experimenting when we encounter memory issues
|
|
33418
|
+
await conn.query(`SET preserve_insertion_order = false;`); // this reduces memory usage when loading a dataset
|
|
33419
|
+
conn.close();
|
|
33420
|
+
return this;
|
|
33421
|
+
}
|
|
33422
|
+
isReady() {
|
|
33423
|
+
if (!this.init_) {
|
|
33424
|
+
this.init_ = this.makeInit();
|
|
33425
|
+
}
|
|
33426
|
+
return this.init_;
|
|
33427
|
+
}
|
|
33428
|
+
/**
|
|
33429
|
+
* Returns information about a dataset once it's loaded:
|
|
33430
|
+
* - a list of properties description
|
|
33431
|
+
* - the name of the dataset geometry column (null if no geometry present)
|
|
33432
|
+
* @param datasetId name of the table under which the dataset will be stored
|
|
33433
|
+
* @param loadQuery duckdb-specific query for creating a table out of the data
|
|
33434
|
+
* @param forceReload if true, any existing data will be dropped and redownloaded
|
|
33435
|
+
*/
|
|
33436
|
+
async loadFile(datasetId, loadQuery, forceReload = false) {
|
|
33437
|
+
const conn = await this.db.connect();
|
|
33438
|
+
let results;
|
|
33439
|
+
// either we want to recreate the table, or we keep it if it already exists
|
|
33440
|
+
const safeLoadQuery = forceReload
|
|
33441
|
+
? `DROP TABLE IF EXISTS ${datasetId};
|
|
33442
|
+
${loadQuery}`
|
|
33443
|
+
: loadQuery.replace(/CREATE TABLE(?! IF NOT EXISTS)/gi, 'CREATE TABLE IF NOT EXISTS');
|
|
33444
|
+
// create the table
|
|
33445
|
+
try {
|
|
33446
|
+
results = await conn.query(safeLoadQuery);
|
|
33447
|
+
}
|
|
33448
|
+
catch (e) {
|
|
33449
|
+
throw new FetchError('parse', `DuckDB encountered an error when loading the data: ${e.message}`);
|
|
33450
|
+
}
|
|
33451
|
+
// read rows count
|
|
33452
|
+
results = await conn.query(`SELECT count(*) FROM ${datasetId}`);
|
|
33453
|
+
const { 'count_star()': recordsCount } = results.toArray()[0].toJSON();
|
|
33454
|
+
// read columns
|
|
33455
|
+
results = await conn.query(`SELECT * FROM information_schema.columns WHERE table_name = '${datasetId}';`);
|
|
33456
|
+
let geometryColumn = null;
|
|
33457
|
+
const properties = results
|
|
33458
|
+
.toArray()
|
|
33459
|
+
.map((row) => {
|
|
33460
|
+
const rowObj = row.toJSON();
|
|
33461
|
+
if (rowObj['data_type'] === 'GEOMETRY') {
|
|
33462
|
+
// the geometry is not part of the properties
|
|
33463
|
+
// note: right now we only keep one geometry column name, but if there are multiple they will
|
|
33464
|
+
// all get discarded
|
|
33465
|
+
geometryColumn = rowObj['column_name'];
|
|
33466
|
+
return null;
|
|
33467
|
+
}
|
|
33468
|
+
return {
|
|
33469
|
+
name: rowObj['column_name'],
|
|
33470
|
+
label: rowObj['column_name'],
|
|
33471
|
+
type: typesMapping[rowObj['data_type']] ?? 'other',
|
|
33472
|
+
};
|
|
33473
|
+
})
|
|
33474
|
+
.filter((prop) => prop !== null);
|
|
33475
|
+
conn.close();
|
|
33476
|
+
return {
|
|
33477
|
+
properties,
|
|
33478
|
+
geometryColumn,
|
|
33479
|
+
rowsCount: Number(recordsCount),
|
|
33480
|
+
};
|
|
33481
|
+
}
|
|
33482
|
+
// register a Uint8 buffer using a handle in the duckdb instance
|
|
33483
|
+
async registerData(name, buffer) {
|
|
33484
|
+
return this.db.registerFileBuffer(name, buffer);
|
|
33485
|
+
}
|
|
33486
|
+
/**
|
|
33487
|
+
* @param query duckdb-specific query for fetching items
|
|
33488
|
+
*/
|
|
33489
|
+
async queryItems(query) {
|
|
33490
|
+
const conn = await this.db.connect();
|
|
33491
|
+
const results = await conn.query(query);
|
|
33492
|
+
conn.close();
|
|
33493
|
+
return arrowTableToDataItems(results);
|
|
33494
|
+
}
|
|
33495
|
+
close() {
|
|
33496
|
+
this.db?.terminate();
|
|
33497
|
+
}
|
|
33498
|
+
}
|
|
33499
|
+
let engine = null;
|
|
33500
|
+
async function getEngine() {
|
|
33501
|
+
if (!engine) {
|
|
33502
|
+
engine = new Engine();
|
|
33503
|
+
}
|
|
33504
|
+
return engine.isReady();
|
|
33014
33505
|
}
|
|
33015
33506
|
|
|
33016
33507
|
class BaseReader {
|
|
@@ -33023,10 +33514,18 @@ class BaseReader {
|
|
|
33023
33514
|
this.sort = null;
|
|
33024
33515
|
this.startIndex = null;
|
|
33025
33516
|
this.count = null;
|
|
33517
|
+
this.loadPromise_ = Promise.resolve();
|
|
33518
|
+
this.cacheEnabled = false;
|
|
33519
|
+
}
|
|
33520
|
+
enableCache(enabled) {
|
|
33521
|
+
this.cacheEnabled = enabled;
|
|
33026
33522
|
}
|
|
33027
33523
|
load() {
|
|
33028
33524
|
throw new Error('not implemented');
|
|
33029
33525
|
}
|
|
33526
|
+
get isLoaded() {
|
|
33527
|
+
return this.loadPromise_;
|
|
33528
|
+
}
|
|
33030
33529
|
get properties() {
|
|
33031
33530
|
throw new Error('not implemented');
|
|
33032
33531
|
}
|
|
@@ -33075,178 +33574,237 @@ class BaseReader {
|
|
|
33075
33574
|
}
|
|
33076
33575
|
}
|
|
33077
33576
|
|
|
33078
|
-
|
|
33079
|
-
|
|
33080
|
-
|
|
33081
|
-
|
|
33082
|
-
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33577
|
+
/**
|
|
33578
|
+
* This reader handles file formats supported natively by DuckDB
|
|
33579
|
+
*/
|
|
33580
|
+
class BaseFileReader extends BaseReader {
|
|
33581
|
+
// a table id should not exceed 63 chars
|
|
33582
|
+
generateDatasetId() {
|
|
33583
|
+
// generate a hash out of the url
|
|
33584
|
+
let hash = 0;
|
|
33585
|
+
for (const char of this.url) {
|
|
33586
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
33587
|
+
hash = hash >>> 0; // make it unsigned
|
|
33588
|
+
}
|
|
33589
|
+
return `datafetcher_${hash.toString(16)}`;
|
|
33590
|
+
}
|
|
33591
|
+
async getLoadQuery() {
|
|
33091
33592
|
throw new Error('not implemented');
|
|
33092
33593
|
}
|
|
33093
|
-
load() {
|
|
33094
|
-
this.
|
|
33594
|
+
async load() {
|
|
33595
|
+
this.datasetId = this.generateDatasetId();
|
|
33596
|
+
this.loadPromise_ = getEngine()
|
|
33597
|
+
.then((engine) => {
|
|
33598
|
+
this.engine = engine;
|
|
33599
|
+
return this.getLoadQuery();
|
|
33600
|
+
})
|
|
33601
|
+
.then((loadQuery) => this.engine.loadFile(this.datasetId, loadQuery, !this.cacheEnabled))
|
|
33602
|
+
.then((datasetInfo) => {
|
|
33603
|
+
this.properties_ = datasetInfo.properties;
|
|
33604
|
+
this.geometryColumn = datasetInfo.geometryColumn;
|
|
33605
|
+
this.rowsCount = datasetInfo.rowsCount;
|
|
33606
|
+
// returns void for the loaded promise
|
|
33607
|
+
});
|
|
33095
33608
|
}
|
|
33096
33609
|
get properties() {
|
|
33097
|
-
return this.
|
|
33610
|
+
return this.isLoaded.then(() => this.properties_);
|
|
33098
33611
|
}
|
|
33099
33612
|
get info() {
|
|
33100
|
-
return this.
|
|
33101
|
-
itemsCount:
|
|
33613
|
+
return this.isLoaded.then(() => ({
|
|
33614
|
+
itemsCount: this.rowsCount,
|
|
33615
|
+
hasGeometry: !!this.geometryColumn,
|
|
33102
33616
|
}));
|
|
33103
33617
|
}
|
|
33104
33618
|
async read() {
|
|
33105
|
-
|
|
33106
|
-
//
|
|
33107
|
-
|
|
33108
|
-
|
|
33109
|
-
|
|
33110
|
-
this.sort == null &&
|
|
33111
|
-
this.filter == null &&
|
|
33112
|
-
this.startIndex == null &&
|
|
33113
|
-
this.count == null) {
|
|
33114
|
-
return items;
|
|
33115
|
-
}
|
|
33116
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33117
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33118
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33119
|
-
return result.map(jsonToGeojsonFeature);
|
|
33120
|
-
}
|
|
33121
|
-
}
|
|
33122
|
-
|
|
33123
|
-
function parseCsv(text) {
|
|
33124
|
-
// first parse the header to guess the delimiter
|
|
33125
|
-
// note that we do that to not rely on Papaparse logic for guessing delimiter
|
|
33126
|
-
let delimiter;
|
|
33127
|
-
try {
|
|
33128
|
-
const header = text.split('\n')[0];
|
|
33129
|
-
const result = Papa.parse(header, {
|
|
33130
|
-
header: false,
|
|
33131
|
-
});
|
|
33132
|
-
delimiter = result.meta.delimiter;
|
|
33133
|
-
}
|
|
33134
|
-
catch (e) {
|
|
33135
|
-
throw new Error('CSV parsing failed: the delimiter could not be guessed');
|
|
33136
|
-
}
|
|
33137
|
-
const parsed = Papa.parse(text, {
|
|
33138
|
-
header: true,
|
|
33139
|
-
skipEmptyLines: true,
|
|
33140
|
-
delimiter,
|
|
33141
|
-
});
|
|
33142
|
-
if (parsed.errors.length) {
|
|
33143
|
-
throw new Error('CSV parsing failed for the following reasons:\n' +
|
|
33144
|
-
parsed.errors
|
|
33145
|
-
.map((error) => `* ${error.message} at row ${error.row}, column ${error.index}`)
|
|
33146
|
-
.join('\n'));
|
|
33619
|
+
await this.isLoaded;
|
|
33620
|
+
// if only certain fields are selected, omit the geometry
|
|
33621
|
+
const geometryColumn = this.selected === null ? this.geometryColumn : null;
|
|
33622
|
+
const query = generateSqlQuery(this.datasetId, this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations, geometryColumn);
|
|
33623
|
+
return this.engine.queryItems(query);
|
|
33147
33624
|
}
|
|
33148
|
-
const items = parsed.data.map(jsonToGeojsonFeature);
|
|
33149
|
-
return processItemProperties(items, true);
|
|
33150
33625
|
}
|
|
33626
|
+
|
|
33151
33627
|
class CsvReader extends BaseFileReader {
|
|
33152
|
-
|
|
33153
|
-
|
|
33628
|
+
async getLoadQuery() {
|
|
33629
|
+
// first we get a list of columns hich have a detected type of VARCHAR
|
|
33630
|
+
// 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
|
|
33631
|
+
return `
|
|
33632
|
+
SET VARIABLE strColumns = (SELECT list(name) FROM (SELECT unnest(Columns, recursive := true) FROM sniff_csv("${this.url}")) WHERE type = 'VARCHAR');
|
|
33633
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_csv("${this.url}",
|
|
33634
|
+
force_not_null = getvariable('strColumns'),
|
|
33635
|
+
auto_type_candidates = ['NULL', 'BOOLEAN', 'INTEGER', 'DOUBLE', 'DATE', 'VARCHAR']
|
|
33636
|
+
);`;
|
|
33154
33637
|
}
|
|
33155
33638
|
}
|
|
33156
33639
|
|
|
33157
|
-
/**
|
|
33158
|
-
* This parser only supports arrays of simple flat objects with properties
|
|
33159
|
-
* @param text
|
|
33160
|
-
*/
|
|
33161
|
-
function parseJson(text) {
|
|
33162
|
-
const parsed = JSON.parse(text);
|
|
33163
|
-
if (!Array.isArray(parsed)) {
|
|
33164
|
-
throw new Error('Could not parse JSON, expected an array at root level');
|
|
33165
|
-
}
|
|
33166
|
-
return processItemProperties(parsed.map(jsonToGeojsonFeature));
|
|
33167
|
-
}
|
|
33168
33640
|
class JsonReader extends BaseFileReader {
|
|
33169
|
-
|
|
33170
|
-
return
|
|
33641
|
+
async getLoadQuery() {
|
|
33642
|
+
return `
|
|
33643
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_json("${this.url}",
|
|
33644
|
+
maximum_object_size = 536870912 -- 500MB
|
|
33645
|
+
);`;
|
|
33171
33646
|
}
|
|
33172
33647
|
}
|
|
33173
33648
|
|
|
33174
|
-
/**
|
|
33175
|
-
* This parser supports both Geojson Feature collections or arrays
|
|
33176
|
-
* of Features
|
|
33177
|
-
* @param text
|
|
33178
|
-
*/
|
|
33179
|
-
function parseGeojson(text) {
|
|
33180
|
-
const parsed = JSON.parse(text);
|
|
33181
|
-
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33182
|
-
if (!Array.isArray(features)) {
|
|
33183
|
-
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33184
|
-
}
|
|
33185
|
-
return processItemProperties(features);
|
|
33186
|
-
}
|
|
33187
33649
|
class GeojsonReader extends BaseFileReader {
|
|
33188
|
-
|
|
33189
|
-
return
|
|
33650
|
+
async getLoadQuery() {
|
|
33651
|
+
return `
|
|
33652
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33653
|
+
allowed_drivers = ['GeoJSON']
|
|
33654
|
+
);`;
|
|
33190
33655
|
}
|
|
33191
33656
|
}
|
|
33192
33657
|
|
|
33658
|
+
async function inferDatasetType(url, typeHint) {
|
|
33659
|
+
const fileExtensionMatches = new URL(url, typeof window !== 'undefined' ? window.location.toString() : undefined).pathname.match(/\.(.+)$/);
|
|
33660
|
+
const fileExtension = fileExtensionMatches && fileExtensionMatches.length
|
|
33661
|
+
? fileExtensionMatches[1].toLowerCase()
|
|
33662
|
+
: null;
|
|
33663
|
+
// 1. type hint
|
|
33664
|
+
if (typeHint)
|
|
33665
|
+
return Promise.resolve(typeHint);
|
|
33666
|
+
// 2. content-type header
|
|
33667
|
+
const headers = await fetchHeaders(url);
|
|
33668
|
+
if ('supportedType' in headers)
|
|
33669
|
+
return headers.supportedType;
|
|
33670
|
+
// 3. file extension from url
|
|
33671
|
+
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
33672
|
+
return fileExtension;
|
|
33673
|
+
// no type inferred or hinted
|
|
33674
|
+
if ('mimeType' in headers)
|
|
33675
|
+
throw FetchError.unsupportedType(headers.mimeType);
|
|
33676
|
+
else
|
|
33677
|
+
throw FetchError.unknownType();
|
|
33678
|
+
}
|
|
33679
|
+
function fetchHeaders(url) {
|
|
33680
|
+
return sharedFetch(url, 'HEAD')
|
|
33681
|
+
.catch((error) => {
|
|
33682
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33683
|
+
})
|
|
33684
|
+
.then((response) => {
|
|
33685
|
+
if (!response.ok) {
|
|
33686
|
+
throw FetchError.http(response.status);
|
|
33687
|
+
}
|
|
33688
|
+
return parseHeaders(response.headers);
|
|
33689
|
+
});
|
|
33690
|
+
}
|
|
33691
|
+
function fetchDataAsText(url, cacheActive) {
|
|
33692
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33693
|
+
.catch((error) => {
|
|
33694
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33695
|
+
})
|
|
33696
|
+
.then(async (response) => {
|
|
33697
|
+
if (!response.ok) {
|
|
33698
|
+
const clonedResponse = response.clone();
|
|
33699
|
+
throw FetchError.http(response.status, await clonedResponse.text());
|
|
33700
|
+
}
|
|
33701
|
+
const clonedResponse = response.clone();
|
|
33702
|
+
return clonedResponse.text();
|
|
33703
|
+
});
|
|
33704
|
+
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
33705
|
+
}
|
|
33706
|
+
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
33707
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33708
|
+
.catch((error) => {
|
|
33709
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33710
|
+
})
|
|
33711
|
+
.then(async (response) => {
|
|
33712
|
+
if (!response.ok) {
|
|
33713
|
+
throw FetchError.http(response.status, await response.text());
|
|
33714
|
+
}
|
|
33715
|
+
// convert to a numeric array so that we can store the response in cache
|
|
33716
|
+
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
33717
|
+
});
|
|
33718
|
+
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
33719
|
+
return new Uint8Array(array).buffer;
|
|
33720
|
+
});
|
|
33721
|
+
}
|
|
33193
33722
|
/**
|
|
33194
|
-
* This
|
|
33195
|
-
*
|
|
33196
|
-
* @param
|
|
33723
|
+
* This creates a Proxy that allows reading and writing to the data item properties
|
|
33724
|
+
* as if it was a simple array of JSON objects
|
|
33725
|
+
* @param items
|
|
33197
33726
|
*/
|
|
33198
|
-
function
|
|
33199
|
-
return
|
|
33200
|
-
|
|
33201
|
-
|
|
33202
|
-
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
|
|
33727
|
+
function getJsonDataItemsProxy(items) {
|
|
33728
|
+
return new Proxy(items, {
|
|
33729
|
+
get(target, p) {
|
|
33730
|
+
if (typeof p === 'string' &&
|
|
33731
|
+
!Number.isNaN(parseInt(p)) &&
|
|
33732
|
+
target[p]?.properties) {
|
|
33733
|
+
return target[p].properties;
|
|
33734
|
+
}
|
|
33735
|
+
return target[p];
|
|
33736
|
+
},
|
|
33737
|
+
set() {
|
|
33738
|
+
throw new Error('This object is read-only');
|
|
33739
|
+
},
|
|
33207
33740
|
});
|
|
33208
33741
|
}
|
|
33742
|
+
|
|
33209
33743
|
class ExcelReader extends BaseFileReader {
|
|
33210
|
-
|
|
33211
|
-
|
|
33744
|
+
async getLoadQuery() {
|
|
33745
|
+
// we download the file as an array buffer first, in order to be able to check if it's an XLS file
|
|
33746
|
+
let buffer = await fetchDataAsArrayBuffer(this.url, this.cacheEnabled);
|
|
33747
|
+
const bufferHandle = `B${this.datasetId}`;
|
|
33748
|
+
// checking against the magic number at the beginning of XLS files, see https://en.wikipedia.org/wiki/List_of_file_signatures
|
|
33749
|
+
const magicNumber = new Uint8Array(buffer, 0, 8); // first 8 bytes
|
|
33750
|
+
const isXls = Array.from(magicNumber)
|
|
33751
|
+
.map((n) => n.toString(16).toUpperCase())
|
|
33752
|
+
.join(' ') === 'D0 CF 11 E0 A1 B1 1A E1';
|
|
33753
|
+
// uh oh, this is an XLS file (not supported by duckdb); convert it to CSV using the xlsx package
|
|
33754
|
+
if (isXls) {
|
|
33755
|
+
buffer = await import('xlsx').then(({ read, utils }) => {
|
|
33756
|
+
const workbook = read(buffer);
|
|
33757
|
+
const json = utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
|
|
33758
|
+
return new TextEncoder().encode(JSON.stringify(json)).buffer;
|
|
33759
|
+
});
|
|
33760
|
+
}
|
|
33761
|
+
const duckDbFn = isXls ? 'read_json' : 'read_xlsx';
|
|
33762
|
+
await this.engine.registerData(bufferHandle, new Uint8Array(buffer));
|
|
33763
|
+
return `
|
|
33764
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM ${duckDbFn}("${bufferHandle}", ignore_errors = true);`;
|
|
33212
33765
|
}
|
|
33213
33766
|
}
|
|
33214
33767
|
|
|
33215
|
-
|
|
33216
|
-
|
|
33217
|
-
|
|
33768
|
+
class GmlReader extends BaseFileReader {
|
|
33769
|
+
async getLoadQuery() {
|
|
33770
|
+
return `
|
|
33771
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33772
|
+
allowed_drivers = ['GML']
|
|
33773
|
+
);`;
|
|
33774
|
+
}
|
|
33775
|
+
}
|
|
33776
|
+
|
|
33777
|
+
const formatGeojson = new GeoJSON$1();
|
|
33778
|
+
function parseGeojson(text) {
|
|
33779
|
+
const parsed = JSON.parse(text);
|
|
33780
|
+
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33781
|
+
if (!Array.isArray(features)) {
|
|
33782
|
+
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33783
|
+
}
|
|
33784
|
+
return features;
|
|
33785
|
+
}
|
|
33786
|
+
function parseGml(text, featureType, version) {
|
|
33787
|
+
const parts = featureType.split(':');
|
|
33788
|
+
const regex = new RegExp(`xmlns:${parts[0]}=["']([^'"]*)["']`);
|
|
33218
33789
|
const match = regex.exec(text);
|
|
33219
33790
|
if (match && match.length >= 2) {
|
|
33220
|
-
const
|
|
33791
|
+
const wfs = new WFS({
|
|
33221
33792
|
featureNS: match[1],
|
|
33222
|
-
featureType:
|
|
33793
|
+
featureType: parts[1],
|
|
33223
33794
|
version: version,
|
|
33224
33795
|
});
|
|
33225
33796
|
let features;
|
|
33226
33797
|
try {
|
|
33227
|
-
features =
|
|
33798
|
+
features = wfs.readFeatures(text);
|
|
33228
33799
|
}
|
|
33229
33800
|
catch (e) {
|
|
33230
|
-
throw Error(
|
|
33801
|
+
throw Error(`Couldn't parse WFS with GML features: ${e.message}`);
|
|
33231
33802
|
}
|
|
33232
|
-
const geojsonItem =
|
|
33233
|
-
return
|
|
33803
|
+
const geojsonItem = formatGeojson.writeFeaturesObject(features);
|
|
33804
|
+
return geojsonItem.features;
|
|
33234
33805
|
}
|
|
33235
33806
|
throw Error("Couldn't retrieve namespace url");
|
|
33236
33807
|
}
|
|
33237
|
-
class GmlReader extends BaseFileReader {
|
|
33238
|
-
constructor(url, namespace, version, cacheActive = true) {
|
|
33239
|
-
super(url);
|
|
33240
|
-
this.url = url;
|
|
33241
|
-
this.namespace = namespace;
|
|
33242
|
-
this.version = version;
|
|
33243
|
-
this.cacheActive = cacheActive;
|
|
33244
|
-
}
|
|
33245
|
-
getData() {
|
|
33246
|
-
return fetchDataAsText(this.url, this.cacheActive).then((text) => parseGml(text, this.namespace, this.version));
|
|
33247
|
-
}
|
|
33248
|
-
}
|
|
33249
|
-
|
|
33250
33808
|
async function getWfsEndpoint(wfsUrl) {
|
|
33251
33809
|
try {
|
|
33252
33810
|
return await new WfsEndpoint(wfsUrl).isReady();
|
|
@@ -33274,21 +33832,65 @@ async function getWfsEndpoint(wfsUrl) {
|
|
|
33274
33832
|
}
|
|
33275
33833
|
}
|
|
33276
33834
|
}
|
|
33277
|
-
class WfsReader extends
|
|
33278
|
-
constructor(url,
|
|
33279
|
-
super(url
|
|
33280
|
-
this.endpoint =
|
|
33281
|
-
this.
|
|
33282
|
-
|
|
33835
|
+
class WfsReader extends BaseReader {
|
|
33836
|
+
constructor(url, featureTypeName) {
|
|
33837
|
+
super(url);
|
|
33838
|
+
this.endpoint = getWfsEndpoint(url);
|
|
33839
|
+
this.featureType = this.endpoint
|
|
33840
|
+
.then((endpoint) => {
|
|
33841
|
+
const featureTypes = endpoint.getFeatureTypes();
|
|
33842
|
+
return endpoint.getFeatureTypeFull(featureTypes.length === 1 && !featureTypeName
|
|
33843
|
+
? featureTypes[0].name
|
|
33844
|
+
: featureTypeName);
|
|
33845
|
+
})
|
|
33846
|
+
.then((featureType) => {
|
|
33847
|
+
if (!featureType) {
|
|
33848
|
+
throw new Error('wfs.featuretype.notfound');
|
|
33849
|
+
}
|
|
33850
|
+
return featureType;
|
|
33851
|
+
});
|
|
33852
|
+
}
|
|
33853
|
+
get backupReader() {
|
|
33854
|
+
if (this.backupReader_) {
|
|
33855
|
+
return this.backupReader_;
|
|
33856
|
+
}
|
|
33857
|
+
this.backupReader_ = Promise.all([this.endpoint, this.featureType]).then(([endpoint, featureType]) => {
|
|
33858
|
+
let reader;
|
|
33859
|
+
if (endpoint.supportsJson(featureType.name)) {
|
|
33860
|
+
reader = new GeojsonReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33861
|
+
asJson: true,
|
|
33862
|
+
outputCrs: 'EPSG:4326',
|
|
33863
|
+
}));
|
|
33864
|
+
}
|
|
33865
|
+
else {
|
|
33866
|
+
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33867
|
+
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33868
|
+
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33869
|
+
reader = new GmlReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33870
|
+
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33871
|
+
outputCrs: 'EPSG:4326',
|
|
33872
|
+
}));
|
|
33873
|
+
}
|
|
33874
|
+
}
|
|
33875
|
+
reader.enableCache(this.cacheEnabled);
|
|
33876
|
+
reader.load();
|
|
33877
|
+
return reader;
|
|
33878
|
+
});
|
|
33879
|
+
return this.backupReader_;
|
|
33283
33880
|
}
|
|
33284
33881
|
get properties() {
|
|
33285
|
-
return this.
|
|
33286
|
-
.getFeatureTypeFull(this.featureTypeName)
|
|
33287
|
-
.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33882
|
+
return this.featureType.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33288
33883
|
const originalType = featureType.properties[prop];
|
|
33289
|
-
|
|
33290
|
-
|
|
33291
|
-
|
|
33884
|
+
let type;
|
|
33885
|
+
if (originalType === 'float' || originalType === 'integer') {
|
|
33886
|
+
type = 'number';
|
|
33887
|
+
}
|
|
33888
|
+
else if (originalType === 'boolean') {
|
|
33889
|
+
type = 'string'; // we don't handle booleans yet in the data fetcher
|
|
33890
|
+
}
|
|
33891
|
+
else {
|
|
33892
|
+
type = originalType;
|
|
33893
|
+
}
|
|
33292
33894
|
return {
|
|
33293
33895
|
name: prop,
|
|
33294
33896
|
label: prop,
|
|
@@ -33297,83 +33899,63 @@ class WfsReader extends BaseCacheReader {
|
|
|
33297
33899
|
}));
|
|
33298
33900
|
}
|
|
33299
33901
|
get info() {
|
|
33300
|
-
return this.
|
|
33902
|
+
return this.featureType.then((result) => ({
|
|
33301
33903
|
itemsCount: result.objectCount,
|
|
33904
|
+
hasGeometry: !!result.geometryName,
|
|
33302
33905
|
}));
|
|
33303
33906
|
}
|
|
33304
|
-
|
|
33305
|
-
|
|
33306
|
-
const featureTypes = wfsEndpoint.getFeatureTypes();
|
|
33307
|
-
const featureType = wfsEndpoint.getFeatureTypeSummary(featureTypes.length === 1 && !featureTypeName
|
|
33308
|
-
? featureTypes[0].name
|
|
33309
|
-
: featureTypeName);
|
|
33310
|
-
if (!featureType) {
|
|
33311
|
-
throw new Error('wfs.featuretype.notfound');
|
|
33312
|
-
}
|
|
33313
|
-
if (wfsEndpoint.supportsStartIndex()) {
|
|
33314
|
-
return new WfsReader(wfsUrlEndpoint, wfsEndpoint, featureType.name);
|
|
33315
|
-
}
|
|
33316
|
-
else if (wfsEndpoint.supportsJson(featureType.name)) {
|
|
33317
|
-
return new GeojsonReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33318
|
-
asJson: true,
|
|
33319
|
-
outputCrs: 'EPSG:4326',
|
|
33320
|
-
}));
|
|
33321
|
-
}
|
|
33322
|
-
else {
|
|
33323
|
-
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33324
|
-
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33325
|
-
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33326
|
-
return new GmlReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33327
|
-
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33328
|
-
outputCrs: 'EPSG:4326',
|
|
33329
|
-
}), featureType.name, wfsEndpoint.getVersion());
|
|
33330
|
-
}
|
|
33331
|
-
throw new Error('wfs.geojsongml.notsupported');
|
|
33332
|
-
}
|
|
33907
|
+
load() {
|
|
33908
|
+
// Nothing to load for Wfs
|
|
33333
33909
|
}
|
|
33334
|
-
async
|
|
33335
|
-
|
|
33336
|
-
|
|
33910
|
+
async read() {
|
|
33911
|
+
const endpoint = await this.endpoint;
|
|
33912
|
+
const featureType = await this.featureType;
|
|
33913
|
+
// if we can't use the WFS protocol we fall back to the backup reader
|
|
33914
|
+
if (this.aggregations || this.groupedBy || !endpoint.supportsStartIndex()) {
|
|
33915
|
+
const backupReader = await this.backupReader;
|
|
33916
|
+
backupReader.selectAll();
|
|
33917
|
+
if (this.selected) {
|
|
33918
|
+
backupReader.select(...this.selected);
|
|
33919
|
+
}
|
|
33920
|
+
if (this.aggregations) {
|
|
33921
|
+
backupReader.aggregate(...this.aggregations);
|
|
33922
|
+
}
|
|
33923
|
+
if (this.groupedBy) {
|
|
33924
|
+
backupReader.groupBy(...this.groupedBy);
|
|
33925
|
+
}
|
|
33926
|
+
if (this.sort) {
|
|
33927
|
+
backupReader.orderBy(...this.sort);
|
|
33928
|
+
}
|
|
33929
|
+
if (this.startIndex !== null && this.count !== null) {
|
|
33930
|
+
backupReader.limit(this.startIndex, this.count);
|
|
33931
|
+
}
|
|
33932
|
+
return backupReader.read();
|
|
33337
33933
|
}
|
|
33338
|
-
const asJson =
|
|
33934
|
+
const asJson = endpoint.supportsJson(featureType.name);
|
|
33339
33935
|
const attributes = this.selected ?? undefined;
|
|
33340
|
-
let
|
|
33936
|
+
let sortBy = null;
|
|
33937
|
+
if (this.sort) {
|
|
33938
|
+
const mapSort = (s) => [s[0] === 'desc' ? 'D' : 'A', s[1]];
|
|
33939
|
+
sortBy = Array.isArray(this.sort[0])
|
|
33940
|
+
? this.sort.map(mapSort)
|
|
33941
|
+
: mapSort(this.sort);
|
|
33942
|
+
}
|
|
33943
|
+
const url = endpoint.getFeatureUrl(featureType.name, {
|
|
33341
33944
|
...(this.startIndex !== null && { startIndex: this.startIndex }),
|
|
33342
33945
|
...(this.count !== null && { maxFeatures: this.count }),
|
|
33343
33946
|
asJson,
|
|
33344
33947
|
outputCrs: 'EPSG:4326',
|
|
33345
33948
|
attributes,
|
|
33346
|
-
|
|
33949
|
+
sortBy,
|
|
33347
33950
|
});
|
|
33348
|
-
|
|
33349
|
-
const finalUrl = new URL(url);
|
|
33350
|
-
const sorts = this.sort
|
|
33351
|
-
.map((fieldSort) => `${fieldSort[1]}+${fieldSort[0] === 'asc' ? 'A' : 'D'}`)
|
|
33352
|
-
.join(',');
|
|
33353
|
-
// Direct update on string url to prevent encoding of +A and +D
|
|
33354
|
-
url = `${url}${finalUrl.search ? '&' : ''}SORTBY=${sorts}`;
|
|
33355
|
-
}
|
|
33356
|
-
return fetchDataAsText(url, this.cacheActive).then((text) => asJson
|
|
33951
|
+
return fetchDataAsText(url, this.cacheEnabled).then((text) => asJson
|
|
33357
33952
|
? parseGeojson(text)
|
|
33358
|
-
: parseGml(text,
|
|
33359
|
-
}
|
|
33360
|
-
async getQueryData() {
|
|
33361
|
-
const items = (await this.getData()).items;
|
|
33362
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33363
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33364
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33365
|
-
return result.map(jsonToGeojsonFeature);
|
|
33366
|
-
}
|
|
33367
|
-
load() {
|
|
33368
|
-
// Nothing to load for Wfs
|
|
33369
|
-
}
|
|
33370
|
-
async read() {
|
|
33371
|
-
return (await this.getData(this.aggregations, this.groupedBy)).items;
|
|
33953
|
+
: parseGml(text, featureType.name, endpoint.getVersion()));
|
|
33372
33954
|
}
|
|
33373
33955
|
}
|
|
33374
33956
|
|
|
33375
|
-
async function openDataset(url,
|
|
33376
|
-
const fileType = await inferDatasetType(url, typeHint);
|
|
33957
|
+
async function openDataset(url, options) {
|
|
33958
|
+
const fileType = await inferDatasetType(url, options?.typeHint);
|
|
33377
33959
|
let reader;
|
|
33378
33960
|
try {
|
|
33379
33961
|
switch (fileType) {
|
|
@@ -33390,18 +33972,18 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33390
33972
|
reader = new ExcelReader(url);
|
|
33391
33973
|
break;
|
|
33392
33974
|
case 'gml':
|
|
33393
|
-
reader = new GmlReader(url
|
|
33975
|
+
reader = new GmlReader(url);
|
|
33394
33976
|
break;
|
|
33395
33977
|
case 'wfs':
|
|
33396
|
-
reader =
|
|
33978
|
+
reader = new WfsReader(url, options?.wfsFeatureType);
|
|
33397
33979
|
break;
|
|
33398
33980
|
}
|
|
33399
|
-
reader.
|
|
33981
|
+
reader.enableCache(options?.enableCache ?? true);
|
|
33400
33982
|
reader.load();
|
|
33401
33983
|
return reader;
|
|
33402
33984
|
}
|
|
33403
33985
|
catch (e) {
|
|
33404
|
-
//WfsReader may already raise a FetchError
|
|
33986
|
+
// WfsReader may already raise a FetchError
|
|
33405
33987
|
if (e instanceof FetchError)
|
|
33406
33988
|
throw e;
|
|
33407
33989
|
else
|
|
@@ -33412,13 +33994,13 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33412
33994
|
* This fetches the full dataset at the given URL and parses it according to its mime type.
|
|
33413
33995
|
* All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
|
|
33414
33996
|
* File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
|
|
33415
|
-
* File type is determined
|
|
33997
|
+
* File type is determined like so:
|
|
33416
33998
|
* 1. if a type hint is given, use it
|
|
33417
33999
|
* 2. otherwise, look for a Content-Type header in the response with a supported mime type
|
|
33418
34000
|
* 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
|
|
33419
34001
|
*/
|
|
33420
|
-
async function readDataset(url,
|
|
33421
|
-
const reader = await openDataset(url,
|
|
34002
|
+
async function readDataset(url, options) {
|
|
34003
|
+
const reader = await openDataset(url, options);
|
|
33422
34004
|
try {
|
|
33423
34005
|
return await reader.read();
|
|
33424
34006
|
}
|
|
@@ -33649,9 +34231,11 @@ class DataService {
|
|
|
33649
34231
|
getDataset(link, cacheActive) {
|
|
33650
34232
|
if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
|
|
33651
34233
|
const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString());
|
|
33652
|
-
return from(openDataset(wfsUrlEndpoint,
|
|
34234
|
+
return from(openDataset(wfsUrlEndpoint, {
|
|
34235
|
+
typeHint: 'wfs',
|
|
33653
34236
|
wfsFeatureType: link.name,
|
|
33654
|
-
|
|
34237
|
+
enableCache: cacheActive,
|
|
34238
|
+
}));
|
|
33655
34239
|
}
|
|
33656
34240
|
else if (link.type === 'download') {
|
|
33657
34241
|
const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString());
|
|
@@ -33659,12 +34243,15 @@ class DataService {
|
|
|
33659
34243
|
const supportedType = SupportedTypes.indexOf(format) > -1
|
|
33660
34244
|
? format
|
|
33661
34245
|
: undefined;
|
|
33662
|
-
return from(openDataset(linkProxifiedUrl,
|
|
34246
|
+
return from(openDataset(linkProxifiedUrl, {
|
|
34247
|
+
typeHint: supportedType,
|
|
34248
|
+
enableCache: cacheActive,
|
|
34249
|
+
})).pipe();
|
|
33663
34250
|
}
|
|
33664
34251
|
else if (link.type === 'service' &&
|
|
33665
34252
|
link.accessServiceProtocol === 'esriRest') {
|
|
33666
34253
|
const url = this.getDownloadUrlFromEsriRest(link.url.toString(), 'geojson');
|
|
33667
|
-
return from(openDataset(url, 'geojson',
|
|
34254
|
+
return from(openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })).pipe();
|
|
33668
34255
|
}
|
|
33669
34256
|
else if (link.type === 'service' &&
|
|
33670
34257
|
link.accessServiceProtocol === 'ogcFeatures') {
|
|
@@ -33678,7 +34265,10 @@ class DataService {
|
|
|
33678
34265
|
}
|
|
33679
34266
|
const urlWithoutLimit = new URL(geojsonUrl);
|
|
33680
34267
|
urlWithoutLimit.searchParams.delete('limit');
|
|
33681
|
-
return openDataset(urlWithoutLimit.toString(),
|
|
34268
|
+
return openDataset(urlWithoutLimit.toString(), {
|
|
34269
|
+
typeHint: 'geojson',
|
|
34270
|
+
enableCache: cacheActive,
|
|
34271
|
+
});
|
|
33682
34272
|
}));
|
|
33683
34273
|
}
|
|
33684
34274
|
return throwError(() => 'protocol not supported');
|
|
@@ -33930,20 +34520,31 @@ class DataTableComponent {
|
|
|
33930
34520
|
this.eltRef = inject(ElementRef);
|
|
33931
34521
|
this.cdr = inject(ChangeDetectorRef);
|
|
33932
34522
|
this.translateService = inject(TranslateService);
|
|
33933
|
-
this.
|
|
34523
|
+
this.columnsFromFeatureCatalog = null;
|
|
34524
|
+
this.columnsFromDataset = [];
|
|
33934
34525
|
this.selected = new EventEmitter();
|
|
33935
|
-
this.properties$ = new BehaviorSubject(null);
|
|
33936
34526
|
this.loading$ = new BehaviorSubject(false);
|
|
33937
34527
|
this.error = null;
|
|
33938
34528
|
}
|
|
33939
34529
|
set featureAttributes(value) {
|
|
33940
|
-
this.
|
|
33941
|
-
|
|
34530
|
+
this.columnsFromFeatureCatalog = value.map((attrs) => ({
|
|
34531
|
+
name: attrs.value,
|
|
34532
|
+
label: attrs.label,
|
|
34533
|
+
}));
|
|
33942
34534
|
}
|
|
33943
34535
|
set dataset(value) {
|
|
33944
34536
|
this.dataset_ = value;
|
|
33945
34537
|
this.dataset_.load();
|
|
33946
|
-
this.dataset_.info.then((info) =>
|
|
34538
|
+
this.dataset_.info.then((info) => {
|
|
34539
|
+
this.count = info.itemsCount;
|
|
34540
|
+
this.cdr.detectChanges();
|
|
34541
|
+
});
|
|
34542
|
+
}
|
|
34543
|
+
get columns() {
|
|
34544
|
+
return this.columnsFromFeatureCatalog ?? this.columnsFromDataset;
|
|
34545
|
+
}
|
|
34546
|
+
get columnNames() {
|
|
34547
|
+
return this.columns.map((c) => c.name);
|
|
33947
34548
|
}
|
|
33948
34549
|
ngOnInit() {
|
|
33949
34550
|
this.dataSource = new DataTableDataSource();
|
|
@@ -33978,11 +34579,12 @@ class DataTableComponent {
|
|
|
33978
34579
|
}
|
|
33979
34580
|
async readData() {
|
|
33980
34581
|
this.loading$.next(true);
|
|
33981
|
-
// wait for properties to be read
|
|
33982
|
-
const properties = await firstValueFrom(this.properties$.pipe(filter((p) => !!p)));
|
|
33983
|
-
const propsWithoutGeom = properties.filter((p) => !p.toLowerCase().startsWith('geom'));
|
|
33984
|
-
this.dataset_.select(...propsWithoutGeom);
|
|
33985
34582
|
try {
|
|
34583
|
+
// wait for properties to be read
|
|
34584
|
+
if (!this.columnsFromFeatureCatalog) {
|
|
34585
|
+
this.columnsFromDataset = await this.dataset_.properties;
|
|
34586
|
+
}
|
|
34587
|
+
this.dataset_.select(...this.columnNames);
|
|
33986
34588
|
await this.dataSource.showData(this.dataset_.read());
|
|
33987
34589
|
this.error = null;
|
|
33988
34590
|
}
|
|
@@ -34012,7 +34614,7 @@ class DataTableComponent {
|
|
|
34012
34614
|
}
|
|
34013
34615
|
}
|
|
34014
34616
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34015
|
-
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
|
|
34617
|
+
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 }); }
|
|
34016
34618
|
}
|
|
34017
34619
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
34018
34620
|
type: Component,
|
|
@@ -34024,10 +34626,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
34024
34626
|
CommonModule,
|
|
34025
34627
|
LoadingMaskComponent,
|
|
34026
34628
|
PopupAlertComponent,
|
|
34027
|
-
LetDirective,
|
|
34028
34629
|
TranslatePipe,
|
|
34029
34630
|
TranslateDirective,
|
|
34030
|
-
], 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
|
|
34631
|
+
], 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"] }]
|
|
34031
34632
|
}], propDecorators: { featureAttributes: [{
|
|
34032
34633
|
type: Input
|
|
34033
34634
|
}], dataset: [{
|
|
@@ -34130,7 +34731,7 @@ class ChartViewComponent {
|
|
|
34130
34731
|
}), shareReplay$1(1));
|
|
34131
34732
|
this.properties$ = combineLatest([this.dataset$, this.featureCatalog$]).pipe(switchMap$1(([dataset, catalog]) => this.setProperties(dataset, catalog)), shareReplay$1(1));
|
|
34132
34733
|
this.yChoices$ = this.properties$.pipe(map$1((properties) => properties
|
|
34133
|
-
.filter((prop) => prop.type === 'number'
|
|
34734
|
+
.filter((prop) => prop.type === 'number')
|
|
34134
34735
|
.map((prop) => ({ value: prop.name, label: prop.label || prop.name }))), tap$1((choices) => {
|
|
34135
34736
|
if (!choices.find((choice) => choice.value === this.yProperty$.value)) {
|
|
34136
34737
|
const newProp = choices[0]?.value || '';
|
|
@@ -34157,6 +34758,7 @@ class ChartViewComponent {
|
|
|
34157
34758
|
this.aggregation$,
|
|
34158
34759
|
]).pipe(filter$1(([_, x, y]) => !!x || !!y), switchMap$1(([dataset, xProp, yProp, aggregation]) => {
|
|
34159
34760
|
const fieldAgg = aggregation === 'count' ? ['count'] : [aggregation, yProp];
|
|
34761
|
+
this.loading = true;
|
|
34160
34762
|
return dataset
|
|
34161
34763
|
.groupBy(['distinct', xProp])
|
|
34162
34764
|
.aggregate(fieldAgg)
|
|
@@ -34398,6 +35000,7 @@ class GeoTableViewComponent {
|
|
|
34398
35000
|
}));
|
|
34399
35001
|
}
|
|
34400
35002
|
async initMapContext() {
|
|
35003
|
+
this.dataset.load();
|
|
34401
35004
|
this.dataset.selectAll();
|
|
34402
35005
|
return {
|
|
34403
35006
|
layers: [
|
|
@@ -34571,8 +35174,7 @@ class MdViewFacade {
|
|
|
34571
35174
|
}));
|
|
34572
35175
|
this.error$ = this.store.pipe(select(getMetadataError));
|
|
34573
35176
|
this.related$ = this.store.pipe(select(getRelated));
|
|
34574
|
-
this.
|
|
34575
|
-
this.sourceOf$ = this.store.pipe(select(getSourceOf));
|
|
35177
|
+
this.linkedRecords$ = this.store.pipe(select(getLinkedRecords));
|
|
34576
35178
|
this.chartConfig$ = this.store.pipe(select(getChartConfig));
|
|
34577
35179
|
this.allLinks$ = this.metadata$.pipe(map$1((record) => 'onlineResources' in record ? record.onlineResources : []), shareReplay$1(1));
|
|
34578
35180
|
this.resourceDoi$ = this.metadata$.pipe(map$1((record) => {
|
|
@@ -34691,12 +35293,9 @@ class MdViewEffects {
|
|
|
34691
35293
|
this.loadRelatedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSimilarRecords(full)), map$1((related) => {
|
|
34692
35294
|
return setRelated({ related });
|
|
34693
35295
|
}), catchError(() => of(setRelated({ related: null })))));
|
|
34694
|
-
this.
|
|
34695
|
-
return
|
|
34696
|
-
}), catchError(() => of(
|
|
34697
|
-
this.loadSourceOf$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSourceOf(full)), map$1((sourceOf) => {
|
|
34698
|
-
return setSourceOf({ sourceOf });
|
|
34699
|
-
}), catchError(() => of(setSourceOf({ sourceOf: null })))));
|
|
35296
|
+
this.loadLinkedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getLinkedRecords(full)), map$1((linkedRecords) => {
|
|
35297
|
+
return setLinkedRecords({ linkedRecords });
|
|
35298
|
+
}), catchError(() => of(setLinkedRecords({ linkedRecords: null })))));
|
|
34700
35299
|
/*
|
|
34701
35300
|
UserFeedback effects
|
|
34702
35301
|
*/
|
|
@@ -36430,6 +37029,11 @@ const DEFAULT_CONFIGURATION = {
|
|
|
36430
37029
|
},
|
|
36431
37030
|
hidden: '${record.kind == "service"}',
|
|
36432
37031
|
},
|
|
37032
|
+
{
|
|
37033
|
+
model: 'associatedRecords',
|
|
37034
|
+
formFieldConfig: {},
|
|
37035
|
+
hidden: '${record.kind == "service"}',
|
|
37036
|
+
},
|
|
36433
37037
|
],
|
|
36434
37038
|
},
|
|
36435
37039
|
// Section: Geographical coverage
|
|
@@ -37392,7 +37996,7 @@ class GenericKeywordsComponent {
|
|
|
37392
37996
|
this.deletedKeyword.emit(keyword);
|
|
37393
37997
|
}
|
|
37394
37998
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37395
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
37999
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
37396
38000
|
}
|
|
37397
38001
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, decorators: [{
|
|
37398
38002
|
type: Component,
|
|
@@ -37567,7 +38171,7 @@ class FormFieldTemporalExtentsComponent {
|
|
|
37567
38171
|
provideNgIconsConfig({
|
|
37568
38172
|
size: '1.5rem',
|
|
37569
38173
|
}),
|
|
37570
|
-
], ngImport: i0, template: "<div class=\"flex gap-2
|
|
38174
|
+
], 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 }); }
|
|
37571
38175
|
}
|
|
37572
38176
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldTemporalExtentsComponent, decorators: [{
|
|
37573
38177
|
type: Component,
|
|
@@ -37584,7 +38188,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37584
38188
|
provideNgIconsConfig({
|
|
37585
38189
|
size: '1.5rem',
|
|
37586
38190
|
}),
|
|
37587
|
-
], template: "<div class=\"flex gap-2
|
|
38191
|
+
], 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"] }]
|
|
37588
38192
|
}], propDecorators: { value: [{
|
|
37589
38193
|
type: Input
|
|
37590
38194
|
}], valueChange: [{
|
|
@@ -37800,6 +38404,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37800
38404
|
], 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" }]
|
|
37801
38405
|
}] });
|
|
37802
38406
|
|
|
38407
|
+
class FormFieldAssociatedRecordsComponent {
|
|
38408
|
+
constructor() {
|
|
38409
|
+
this.valueChange = new EventEmitter();
|
|
38410
|
+
}
|
|
38411
|
+
get list() {
|
|
38412
|
+
return this.value ?? [];
|
|
38413
|
+
}
|
|
38414
|
+
get first() {
|
|
38415
|
+
return this.list[0];
|
|
38416
|
+
}
|
|
38417
|
+
get rest() {
|
|
38418
|
+
return this.list.slice(1);
|
|
38419
|
+
}
|
|
38420
|
+
get hasParentLink() {
|
|
38421
|
+
return this.list.length > 0;
|
|
38422
|
+
}
|
|
38423
|
+
get uniqueIdentifier() {
|
|
38424
|
+
return this.first?.uniqueIdentifier ?? '';
|
|
38425
|
+
}
|
|
38426
|
+
get selectedType() {
|
|
38427
|
+
return this.first?.associationType;
|
|
38428
|
+
}
|
|
38429
|
+
get choices() {
|
|
38430
|
+
return associationTypeValues.map((value) => ({
|
|
38431
|
+
value,
|
|
38432
|
+
label: `domain.record.associationType.${value}`,
|
|
38433
|
+
}));
|
|
38434
|
+
}
|
|
38435
|
+
onToggle(checked) {
|
|
38436
|
+
this.valueChange.emit(checked
|
|
38437
|
+
? [
|
|
38438
|
+
{
|
|
38439
|
+
uniqueIdentifier: '',
|
|
38440
|
+
associationType: associationTypeValues[0],
|
|
38441
|
+
},
|
|
38442
|
+
...this.rest,
|
|
38443
|
+
]
|
|
38444
|
+
: this.rest);
|
|
38445
|
+
}
|
|
38446
|
+
onUniqueIdentifierChange(uniqueIdentifier) {
|
|
38447
|
+
this.valueChange.emit(uniqueIdentifier
|
|
38448
|
+
? [{ ...this.first, uniqueIdentifier }, ...this.rest]
|
|
38449
|
+
: this.rest);
|
|
38450
|
+
}
|
|
38451
|
+
onTypeChange(associationType) {
|
|
38452
|
+
this.valueChange.emit([
|
|
38453
|
+
{ ...this.first, associationType: associationType },
|
|
38454
|
+
...this.rest,
|
|
38455
|
+
]);
|
|
38456
|
+
}
|
|
38457
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38458
|
+
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 }); }
|
|
38459
|
+
}
|
|
38460
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, decorators: [{
|
|
38461
|
+
type: Component,
|
|
38462
|
+
args: [{ selector: 'gn-ui-form-field-associated-records', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
38463
|
+
CheckToggleComponent,
|
|
38464
|
+
TextInputComponent,
|
|
38465
|
+
DropdownSelectorComponent,
|
|
38466
|
+
FormFieldWrapperComponent,
|
|
38467
|
+
TranslatePipe,
|
|
38468
|
+
], 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" }]
|
|
38469
|
+
}], propDecorators: { value: [{
|
|
38470
|
+
type: Input
|
|
38471
|
+
}], valueChange: [{
|
|
38472
|
+
type: Output
|
|
38473
|
+
}] } });
|
|
38474
|
+
|
|
37803
38475
|
class ContactCardComponent {
|
|
37804
38476
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37805
38477
|
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 }); }
|
|
@@ -37916,7 +38588,7 @@ class FormFieldContactsForResourceComponent {
|
|
|
37916
38588
|
provideNgIconsConfig({
|
|
37917
38589
|
size: '1.5rem',
|
|
37918
38590
|
}),
|
|
37919
|
-
], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n \n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
38591
|
+
], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n \n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
37920
38592
|
}
|
|
37921
38593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsForResourceComponent, decorators: [{
|
|
37922
38594
|
type: Component,
|
|
@@ -38016,7 +38688,7 @@ class FormFieldContactsComponent {
|
|
|
38016
38688
|
this.subscription.unsubscribe();
|
|
38017
38689
|
}
|
|
38018
38690
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38019
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
38691
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
38020
38692
|
}
|
|
38021
38693
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, decorators: [{
|
|
38022
38694
|
type: Component,
|
|
@@ -38369,7 +39041,7 @@ class OnlineServiceResourceInputComponent {
|
|
|
38369
39041
|
provideNgIconsConfig({
|
|
38370
39042
|
size: '1.5em',
|
|
38371
39043
|
}),
|
|
38372
|
-
], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
39044
|
+
], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
38373
39045
|
}
|
|
38374
39046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: OnlineServiceResourceInputComponent, decorators: [{
|
|
38375
39047
|
type: Component,
|
|
@@ -39185,6 +39857,9 @@ class FormFieldComponent {
|
|
|
39185
39857
|
get valueAsUpdateFrequency() {
|
|
39186
39858
|
return this.value;
|
|
39187
39859
|
}
|
|
39860
|
+
get valueAsAssociatedRecords() {
|
|
39861
|
+
return this.value;
|
|
39862
|
+
}
|
|
39188
39863
|
get valueAsTemporalExtents() {
|
|
39189
39864
|
return this.value;
|
|
39190
39865
|
}
|
|
@@ -39224,7 +39899,7 @@ class FormFieldComponent {
|
|
|
39224
39899
|
}
|
|
39225
39900
|
}
|
|
39226
39901
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39227
|
-
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 }); }
|
|
39902
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FormFieldComponent, isStandalone: true, selector: "gn-ui-form-field", inputs: { uniqueIdentifier: "uniqueIdentifier", recordKind: "recordKind", model: "model", modelSpecifier: "modelSpecifier", componentName: "componentName", config: "config", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [provideIcons({ matEditOutline, matHelpOutline })], viewQueries: [{ propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }], hostDirectives: [{ directive: FieldFocusDirective }], ngImport: i0, template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "component", type: FormFieldLicenseComponent, selector: "gn-ui-form-field-license", inputs: ["label", "recordLicences"], outputs: ["recordLicencesChange"] }, { kind: "component", type: FormFieldDateComponent, selector: "gn-ui-form-field-date", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldUpdateFrequencyComponent, selector: "gn-ui-form-field-update-frequency", inputs: ["value", "recordKind"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldAssociatedRecordsComponent, selector: "gn-ui-form-field-associated-records", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldTemporalExtentsComponent, selector: "gn-ui-form-field-temporal-extents", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSimpleComponent, selector: "gn-ui-form-field-simple", inputs: ["type", "readonly", "invalid", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldRichComponent, selector: "gn-ui-form-field-rich", inputs: ["label", "hint", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSpatialExtentComponent, selector: "gn-ui-form-field-spatial-extent" }, { kind: "component", type: FormFieldKeywordsComponent, selector: "gn-ui-form-field-keywords", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOverviewsComponent, selector: "gn-ui-form-field-overviews", inputs: ["metadataUuid", "recordKind", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsForResourceComponent, selector: "gn-ui-form-field-contacts-for-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineResourcesComponent, selector: "gn-ui-form-field-online-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineLinkResourcesComponent, selector: "gn-ui-form-field-online-link-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineSingleLinkResourceComponent, selector: "gn-ui-form-field-online-single-link-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsComponent, selector: "gn-ui-form-field-contacts", inputs: ["value", "modelSpecifier"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsComponent, selector: "gn-ui-form-field-constraints", inputs: ["label", "value", "constraintType"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsShortcutsComponent, selector: "gn-ui-form-field-constraints-shortcuts" }, { kind: "component", type: FormFieldSpatialToggleComponent, selector: "gn-ui-form-field-spatial-toggle" }, { kind: "component", type: FormFieldTopicsComponent, selector: "gn-ui-form-field-topics", inputs: ["value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i4$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
39228
39903
|
}
|
|
39229
39904
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
39230
39905
|
type: Component,
|
|
@@ -39236,6 +39911,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39236
39911
|
FormFieldLicenseComponent,
|
|
39237
39912
|
FormFieldDateComponent,
|
|
39238
39913
|
FormFieldUpdateFrequencyComponent,
|
|
39914
|
+
FormFieldAssociatedRecordsComponent,
|
|
39239
39915
|
FormFieldTemporalExtentsComponent,
|
|
39240
39916
|
FormFieldSimpleComponent,
|
|
39241
39917
|
FormFieldRichComponent,
|
|
@@ -39253,7 +39929,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39253
39929
|
FormFieldTopicsComponent,
|
|
39254
39930
|
TextFieldModule,
|
|
39255
39931
|
NgIconComponent,
|
|
39256
|
-
], 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"] }]
|
|
39932
|
+
], providers: [provideIcons({ matEditOutline, matHelpOutline })], hostDirectives: [FieldFocusDirective], template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"] }]
|
|
39257
39933
|
}], propDecorators: { uniqueIdentifier: [{
|
|
39258
39934
|
type: Input
|
|
39259
39935
|
}], recordKind: [{
|
|
@@ -39838,7 +40514,7 @@ class RouterService {
|
|
|
39838
40514
|
return ROUTER_ROUTE_ORGANIZATION;
|
|
39839
40515
|
}
|
|
39840
40516
|
getDefaultSort() {
|
|
39841
|
-
return SortByEnum.
|
|
40517
|
+
return SortByEnum.RESOURCE_DATE;
|
|
39842
40518
|
}
|
|
39843
40519
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39844
40520
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, providedIn: 'root' }); }
|
|
@@ -39898,7 +40574,7 @@ function flattenQueryParams(params) {
|
|
|
39898
40574
|
const start = flattened[key].start;
|
|
39899
40575
|
const end = flattened[key].end;
|
|
39900
40576
|
flattened[key] = [
|
|
39901
|
-
`${start ? formatDate(start) : ''}..${formatDate(end)
|
|
40577
|
+
`${start ? formatDate(start) : ''}..${end ? formatDate(end) : ''}`,
|
|
39902
40578
|
];
|
|
39903
40579
|
}
|
|
39904
40580
|
}
|
|
@@ -40255,5 +40931,5 @@ const CHART_TYPE_VALUES = [
|
|
|
40255
40931
|
* Generated bundle index. Do not edit.
|
|
40256
40932
|
*/
|
|
40257
40933
|
|
|
40258
|
-
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, 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 };
|
|
40934
|
+
export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEOCODING_PROVIDER, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingService, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LocationSearchComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceCreationRevisionDateSearchField, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, defaultMapStyleFixture, defaultMapStyleHlFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
|
|
40259
40935
|
//# sourceMappingURL=geonetwork-ui.mjs.map
|