geonetwork-ui 2.10.2 → 2.11.0-dev.0504d85cc
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 +1679 -986
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +303 -128
- package/index.d.ts.map +1 -1
- package/package.json +9 -8
- 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 +221 -0
- 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/gn-ui-version.ts +1 -1
- package/src/libs/util/shared/src/lib/links/link-utils.ts +19 -10
- package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
- package/src/libs/util/shared/src/lib/utils/file.ts +15 -0
- package/src/libs/util/shared/src/lib/utils/geojson.ts +24 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/tailwind.base.css +5 -0
- package/translations/de.json +31 -4
- package/translations/en.json +30 -3
- package/translations/es.json +28 -1
- package/translations/fr.json +31 -4
- package/translations/it.json +29 -2
- package/translations/nl.json +28 -1
- package/translations/pt.json +28 -1
- package/translations/sk.json +29 -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, iconoirImport, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle,
|
|
43
|
+
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirUpload, iconoirTrash, iconoirSquareDashed, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirImport, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
|
|
45
44
|
import { MatButtonModule } from '@angular/material/button';
|
|
46
|
-
import * as i1$
|
|
47
|
-
import {
|
|
45
|
+
import * as i1$7 from '@angular/cdk/overlay';
|
|
46
|
+
import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
48
47
|
import * as i1$3 from '@angular/forms';
|
|
49
48
|
import { UntypedFormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
50
49
|
import * as i1$2 from '@angular/material/autocomplete';
|
|
@@ -52,16 +51,18 @@ import { MatAutocompleteModule, MatAutocompleteTrigger, MatAutocomplete } from '
|
|
|
52
51
|
import tippy from 'tippy.js';
|
|
53
52
|
import * as i2 from '@angular/material/progress-spinner';
|
|
54
53
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
55
|
-
import { matClose, matContentCopy,
|
|
54
|
+
import { matClose, matContentCopy, matExpandMore, matExpandLess, matSearch, matStarBorder, matStar, matRemove, matAdd, matChevronRight, matChevronLeft, matArrowForwardIos, matArrowBackIos, matMoodBad, matQuestionMark, matFace, matZoomOutMap, matOpenInNew, matPersonOutline, matMailOutline, matWarningAmber, matCheck, matCheckCircleOutline, matWarning, matMoreVert } from '@ng-icons/material-icons/baseline';
|
|
56
55
|
import * as i1$4 from '@angular/material/checkbox';
|
|
57
56
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
58
57
|
import * as i1$5 from '@angular/material/tooltip';
|
|
59
58
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
60
|
-
import {
|
|
59
|
+
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
|
|
60
|
+
import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
|
61
|
+
import { enUS } from 'date-fns/locale/en-US';
|
|
61
62
|
import * as i1$6 from '@angular/material/datepicker';
|
|
62
63
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
63
|
-
import * as i1$
|
|
64
|
-
import { NgxDropzoneModule } from 'ngx-dropzone';
|
|
64
|
+
import * as i1$8 from 'ngx-dropzone';
|
|
65
|
+
import { NgxDropzoneModule, NgxDropzoneComponent } from 'ngx-dropzone';
|
|
65
66
|
import * as i1$9 from '@angular/material/button-toggle';
|
|
66
67
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
67
68
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -72,6 +73,7 @@ import { MatTabsModule } from '@angular/material/tabs';
|
|
|
72
73
|
import * as i2$2 from '@ngrx/effects';
|
|
73
74
|
import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
|
|
74
75
|
import { valid as valid$1 } from 'geojson-validation';
|
|
76
|
+
import { 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,24 @@ 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
|
+
}
|
|
19599
|
+
/**
|
|
19600
|
+
* Checks that a bounding box's coordinates stay within the valid
|
|
19601
|
+
* longitude (-180/180) and latitude (-90/90) ranges.
|
|
19602
|
+
*/
|
|
19603
|
+
function isBoundingBoxWithinWorldExtent(bbox) {
|
|
19604
|
+
const [minX, minY, maxX, maxY] = bbox;
|
|
19605
|
+
return (minX >= -180 &&
|
|
19606
|
+
maxX <= 180 &&
|
|
19607
|
+
minY >= -90 &&
|
|
19608
|
+
maxY <= 90 &&
|
|
19609
|
+
minX <= maxX &&
|
|
19610
|
+
minY <= maxY);
|
|
19611
|
+
}
|
|
19529
19612
|
function getGeometryBoundingBox(geometry) {
|
|
19530
19613
|
// use the bounding box if specified in the GeoJSON object
|
|
19531
19614
|
if (geometry.bbox) {
|
|
@@ -20194,7 +20277,7 @@ function getLinkLabel(link) {
|
|
|
20194
20277
|
const label = link.description || ('name' in link ? link.name : '');
|
|
20195
20278
|
return format ? `${label} (${format})` : label;
|
|
20196
20279
|
}
|
|
20197
|
-
async function getLayers(url, serviceProtocol) {
|
|
20280
|
+
async function getLayers(url, serviceProtocol, deep = false) {
|
|
20198
20281
|
switch (serviceProtocol) {
|
|
20199
20282
|
case 'ogcFeatures': {
|
|
20200
20283
|
const layers = await new OgcApiEndpoint(url).allCollections;
|
|
@@ -20202,7 +20285,10 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20202
20285
|
}
|
|
20203
20286
|
case 'wfs': {
|
|
20204
20287
|
const endpointWfs = await new WfsEndpoint(url).isReady();
|
|
20205
|
-
const featureTypes =
|
|
20288
|
+
const featureTypes = endpointWfs.getFeatureTypes();
|
|
20289
|
+
if (!deep) {
|
|
20290
|
+
return featureTypes;
|
|
20291
|
+
}
|
|
20206
20292
|
const layers = (await Promise.allSettled(featureTypes.map((collection) => {
|
|
20207
20293
|
return endpointWfs.getFeatureTypeFull(collection.name);
|
|
20208
20294
|
})))
|
|
@@ -20212,12 +20298,14 @@ async function getLayers(url, serviceProtocol) {
|
|
|
20212
20298
|
}
|
|
20213
20299
|
case 'wms': {
|
|
20214
20300
|
const endpointWms = await new WmsEndpoint(url).isReady();
|
|
20215
|
-
const
|
|
20301
|
+
const layersSummary = endpointWms
|
|
20216
20302
|
.getLayers()
|
|
20217
20303
|
.flatMap(wmsLayerFlatten)
|
|
20218
|
-
.filter((l) => l.name)
|
|
20219
|
-
|
|
20220
|
-
|
|
20304
|
+
.filter((l) => l.name);
|
|
20305
|
+
if (!deep) {
|
|
20306
|
+
return layersSummary;
|
|
20307
|
+
}
|
|
20308
|
+
const layers = layersSummary.map((collection) => endpointWms.getLayerByName(collection.name));
|
|
20221
20309
|
return layers;
|
|
20222
20310
|
}
|
|
20223
20311
|
case 'wmts': {
|
|
@@ -20311,6 +20399,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20311
20399
|
}]
|
|
20312
20400
|
}] });
|
|
20313
20401
|
|
|
20402
|
+
class AutofocusDirective {
|
|
20403
|
+
constructor() {
|
|
20404
|
+
this.el = inject(ElementRef);
|
|
20405
|
+
this.injector = inject(Injector);
|
|
20406
|
+
}
|
|
20407
|
+
set autofocus(active) {
|
|
20408
|
+
if (!active)
|
|
20409
|
+
return;
|
|
20410
|
+
afterNextRender(() => this.el.nativeElement.focus(), {
|
|
20411
|
+
injector: this.injector,
|
|
20412
|
+
});
|
|
20413
|
+
}
|
|
20414
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
20415
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.19", type: AutofocusDirective, isStandalone: true, selector: "[gnUiAutofocus]", inputs: { autofocus: ["gnUiAutofocus", "autofocus", booleanAttribute] }, ngImport: i0 }); }
|
|
20416
|
+
}
|
|
20417
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, decorators: [{
|
|
20418
|
+
type: Directive,
|
|
20419
|
+
args: [{
|
|
20420
|
+
selector: '[gnUiAutofocus]',
|
|
20421
|
+
standalone: true,
|
|
20422
|
+
}]
|
|
20423
|
+
}], propDecorators: { autofocus: [{
|
|
20424
|
+
type: Input,
|
|
20425
|
+
args: [{ alias: 'gnUiAutofocus', transform: booleanAttribute }]
|
|
20426
|
+
}] } });
|
|
20427
|
+
|
|
20314
20428
|
class ImageFallbackDirective {
|
|
20315
20429
|
constructor() {
|
|
20316
20430
|
this.el = inject(ElementRef);
|
|
@@ -20338,7 +20452,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20338
20452
|
}] } });
|
|
20339
20453
|
|
|
20340
20454
|
var name = "geonetwork-ui";
|
|
20341
|
-
var version = "2.
|
|
20455
|
+
var version = "2.11.0-dev.0504d85cc";
|
|
20342
20456
|
var engines = {
|
|
20343
20457
|
node: ">=24"
|
|
20344
20458
|
};
|
|
@@ -20359,6 +20473,7 @@ var peerDependencies = {
|
|
|
20359
20473
|
"@angular/core": "19.x || 20.x || 21.x",
|
|
20360
20474
|
"@angular/forms": "19.x || 20.x || 21.x",
|
|
20361
20475
|
"@angular/material": "19.x || 20.x || 21.x",
|
|
20476
|
+
"@angular/material-date-fns-adapter": "19.x || 20.x",
|
|
20362
20477
|
"@angular/platform-browser": "19.x || 20.x || 21.x",
|
|
20363
20478
|
"@angular/platform-browser-dynamic": "19.x || 20.x || 21.x",
|
|
20364
20479
|
"@angular/router": "19.x || 20.x || 21.x",
|
|
@@ -20377,11 +20492,12 @@ var peerDependencies = {
|
|
|
20377
20492
|
};
|
|
20378
20493
|
var dependencies = {
|
|
20379
20494
|
"@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/
|
|
20495
|
+
"@camptocamp/ogc-client": "1.3.1-dev.200c02a",
|
|
20496
|
+
"@duckdb/duckdb-wasm": "~1.32.0",
|
|
20497
|
+
"@geospatial-sdk/core": "0.0.5-dev.78",
|
|
20498
|
+
"@geospatial-sdk/geocoding": "0.0.5-dev.78",
|
|
20499
|
+
"@geospatial-sdk/legend": "0.0.5-dev.78",
|
|
20500
|
+
"@geospatial-sdk/openlayers": "0.0.5-dev.78",
|
|
20385
20501
|
"@ltd/j-toml": "~1.38.0",
|
|
20386
20502
|
"@messageformat/core": "~3.4.0",
|
|
20387
20503
|
"@ng-icons/core": "~32.5.0",
|
|
@@ -20389,7 +20505,7 @@ var dependencies = {
|
|
|
20389
20505
|
"@ng-icons/material-icons": "~32.5.0",
|
|
20390
20506
|
"@ng-icons/tabler-icons": "~32.4.0",
|
|
20391
20507
|
"@rgrove/parse-xml": "4.2.0",
|
|
20392
|
-
|
|
20508
|
+
"apache-arrow": "~17.0.0",
|
|
20393
20509
|
"chart.js": "~4.5.1",
|
|
20394
20510
|
"chroma-js": "~3.2.0",
|
|
20395
20511
|
"date-fns": "4.1.0",
|
|
@@ -20402,7 +20518,6 @@ var dependencies = {
|
|
|
20402
20518
|
"ngx-dropzone": "~3.1.0",
|
|
20403
20519
|
"ngx-translate-messageformat-compiler": "~7.2.0",
|
|
20404
20520
|
ol: "~10.8.0",
|
|
20405
|
-
papaparse: "~5.5.3",
|
|
20406
20521
|
proj4: "~2.20.4",
|
|
20407
20522
|
rdflib: "~2.3.5",
|
|
20408
20523
|
semver: "~7.7.4",
|
|
@@ -20424,7 +20539,7 @@ var packageJson = {
|
|
|
20424
20539
|
|
|
20425
20540
|
const GEONETWORK_UI_VERSION = packageJson.version;
|
|
20426
20541
|
const GEONETWORK_UI_TAG_NAME = GEONETWORK_UI_VERSION.split('-')[1]?.startsWith('dev')
|
|
20427
|
-
? '
|
|
20542
|
+
? 'main'
|
|
20428
20543
|
: `v${packageJson.version}`;
|
|
20429
20544
|
|
|
20430
20545
|
const ValidatorMapper = {
|
|
@@ -20600,8 +20715,8 @@ class ElasticsearchService {
|
|
|
20600
20715
|
if (!payload.runtime_mappings)
|
|
20601
20716
|
payload.runtime_mappings = {};
|
|
20602
20717
|
payload.runtime_mappings[fieldName] = {
|
|
20603
|
-
type:
|
|
20604
|
-
script: this.runtimeFields[fieldName],
|
|
20718
|
+
type: this.runtimeFields[fieldName].type,
|
|
20719
|
+
script: this.runtimeFields[fieldName].script,
|
|
20605
20720
|
};
|
|
20606
20721
|
};
|
|
20607
20722
|
const lookForField = (node) => {
|
|
@@ -20621,6 +20736,12 @@ class ElasticsearchService {
|
|
|
20621
20736
|
(node[runtimeField] === 'asc' || node[runtimeField] === 'desc')) {
|
|
20622
20737
|
addMapping(runtimeField);
|
|
20623
20738
|
}
|
|
20739
|
+
if (runtimeField in node &&
|
|
20740
|
+
typeof node[runtimeField] === 'object' &&
|
|
20741
|
+
node[runtimeField] !== null &&
|
|
20742
|
+
('gte' in node[runtimeField] || 'lte' in node[runtimeField])) {
|
|
20743
|
+
addMapping(runtimeField);
|
|
20744
|
+
}
|
|
20624
20745
|
if ('query' in node &&
|
|
20625
20746
|
typeof node.query === 'string' &&
|
|
20626
20747
|
node.query.indexOf(runtimeField + ':') > -1) {
|
|
@@ -20637,8 +20758,8 @@ class ElasticsearchService {
|
|
|
20637
20758
|
lookForField(payload.query);
|
|
20638
20759
|
return payload;
|
|
20639
20760
|
}
|
|
20640
|
-
registerRuntimeField(fieldName, expression) {
|
|
20641
|
-
this.runtimeFields[fieldName] = expression;
|
|
20761
|
+
registerRuntimeField(fieldName, expression, type = 'keyword') {
|
|
20762
|
+
this.runtimeFields[fieldName] = { script: expression, type };
|
|
20642
20763
|
}
|
|
20643
20764
|
getMetadataByIdsPayload(uuids) {
|
|
20644
20765
|
return {
|
|
@@ -20647,6 +20768,7 @@ class ElasticsearchService {
|
|
|
20647
20768
|
values: uuids,
|
|
20648
20769
|
},
|
|
20649
20770
|
},
|
|
20771
|
+
size: uuids.length,
|
|
20650
20772
|
};
|
|
20651
20773
|
}
|
|
20652
20774
|
getRelatedRecordPayload(record, size = 6, _source = [...ES_SOURCE_SUMMARY, 'createDate']) {
|
|
@@ -20697,10 +20819,28 @@ class ElasticsearchService {
|
|
|
20697
20819
|
};
|
|
20698
20820
|
}
|
|
20699
20821
|
buildPayloadSort(sortBy) {
|
|
20700
|
-
if (sortBy ===
|
|
20822
|
+
if (!sortBy || sortBy.length === 0)
|
|
20701
20823
|
return undefined;
|
|
20702
|
-
const fields = Array.isArray(sortBy[0])
|
|
20703
|
-
|
|
20824
|
+
const fields = Array.isArray(sortBy[0])
|
|
20825
|
+
? sortBy
|
|
20826
|
+
: [sortBy];
|
|
20827
|
+
return fields.map((field) => {
|
|
20828
|
+
// Sort by nested array of dates only works with the explicit syntax
|
|
20829
|
+
if (field[1].endsWith('.date')) {
|
|
20830
|
+
const nestedPath = field[1].slice(0, field[1].lastIndexOf('.date'));
|
|
20831
|
+
return {
|
|
20832
|
+
[field[1]]: {
|
|
20833
|
+
order: field[0],
|
|
20834
|
+
mode: field[0] === 'desc' ? 'max' : 'min',
|
|
20835
|
+
missing: '_last',
|
|
20836
|
+
nested: {
|
|
20837
|
+
path: nestedPath,
|
|
20838
|
+
},
|
|
20839
|
+
},
|
|
20840
|
+
};
|
|
20841
|
+
}
|
|
20842
|
+
return { [field[1]]: field[0] };
|
|
20843
|
+
});
|
|
20704
20844
|
}
|
|
20705
20845
|
injectLangInQueryStringFields(queryFieldsPriority) {
|
|
20706
20846
|
const queryLang = this.getQueryLang();
|
|
@@ -20736,7 +20876,49 @@ class ElasticsearchService {
|
|
|
20736
20876
|
isCurrentSearchLang() {
|
|
20737
20877
|
return this.metadataLang === 'current';
|
|
20738
20878
|
}
|
|
20739
|
-
|
|
20879
|
+
findSpatialFilterExtent(filters) {
|
|
20880
|
+
if (typeof filters === 'string') {
|
|
20881
|
+
return undefined;
|
|
20882
|
+
}
|
|
20883
|
+
return Object.values(filters).find(isBoundingBox);
|
|
20884
|
+
}
|
|
20885
|
+
// if a field registered min/max runtime fields, its dates form an interval
|
|
20886
|
+
// the record matches if that interval intersects the filter range
|
|
20887
|
+
buildDateRangeQuery(searchField, dateRange) {
|
|
20888
|
+
const minField = `${searchField}Min`;
|
|
20889
|
+
const maxField = `${searchField}Max`;
|
|
20890
|
+
if (minField in this.runtimeFields && maxField in this.runtimeFields) {
|
|
20891
|
+
const filter = [
|
|
20892
|
+
dateRange.start && {
|
|
20893
|
+
range: {
|
|
20894
|
+
[maxField]: {
|
|
20895
|
+
gte: formatDate(dateRange.start),
|
|
20896
|
+
format: 'yyyy-MM-dd',
|
|
20897
|
+
},
|
|
20898
|
+
},
|
|
20899
|
+
},
|
|
20900
|
+
dateRange.end && {
|
|
20901
|
+
range: {
|
|
20902
|
+
[minField]: {
|
|
20903
|
+
lte: formatDate(dateRange.end),
|
|
20904
|
+
format: 'yyyy-MM-dd',
|
|
20905
|
+
},
|
|
20906
|
+
},
|
|
20907
|
+
},
|
|
20908
|
+
].filter(Boolean);
|
|
20909
|
+
return { bool: { filter } };
|
|
20910
|
+
}
|
|
20911
|
+
return {
|
|
20912
|
+
range: {
|
|
20913
|
+
[searchField]: {
|
|
20914
|
+
...(dateRange.start && { gte: formatDate(dateRange.start) }),
|
|
20915
|
+
...(dateRange.end && { lte: formatDate(dateRange.end) }),
|
|
20916
|
+
format: 'yyyy-MM-dd',
|
|
20917
|
+
},
|
|
20918
|
+
},
|
|
20919
|
+
};
|
|
20920
|
+
}
|
|
20921
|
+
filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
|
|
20740
20922
|
const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
|
|
20741
20923
|
const makeQuery = (filter) => {
|
|
20742
20924
|
if (typeof filter === 'string') {
|
|
@@ -20755,7 +20937,9 @@ class ElasticsearchService {
|
|
|
20755
20937
|
? filters
|
|
20756
20938
|
: Object.keys(filters)
|
|
20757
20939
|
.filter((fieldname) => fieldname !== 'gn-ui-crossFieldFilter')
|
|
20940
|
+
.filter((fieldname) => !isBoundingBox(filters[fieldname]))
|
|
20758
20941
|
.filter((fieldname) => !isDateRange(filters[fieldname]))
|
|
20942
|
+
.filter((fieldname) => !Array.isArray(filters[fieldname]))
|
|
20759
20943
|
.filter((fieldname) => filters[fieldname] &&
|
|
20760
20944
|
JSON.stringify(filters[fieldname]) !== '{}')
|
|
20761
20945
|
.map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
|
|
@@ -20763,31 +20947,26 @@ class ElasticsearchService {
|
|
|
20763
20947
|
if (filters['gn-ui-crossFieldFilter']) {
|
|
20764
20948
|
queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
|
|
20765
20949
|
}
|
|
20766
|
-
const
|
|
20767
|
-
.filter(([, value]) => isDateRange(value))
|
|
20768
|
-
.map(([searchField, dateRange]) => {
|
|
20769
|
-
return {
|
|
20770
|
-
searchField,
|
|
20771
|
-
dateRange,
|
|
20772
|
-
};
|
|
20773
|
-
})[0];
|
|
20950
|
+
const queryRanges = Object.entries(filters).filter(([, value]) => isDateRange(value));
|
|
20774
20951
|
const queryParts = [
|
|
20775
20952
|
queryString && {
|
|
20776
20953
|
query_string: {
|
|
20777
20954
|
query: queryString,
|
|
20778
20955
|
},
|
|
20779
20956
|
},
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20957
|
+
...queryRanges.map(([searchField, dateRange]) => this.buildDateRangeQuery(searchField, dateRange)),
|
|
20958
|
+
spatialFilterExtent && {
|
|
20959
|
+
geo_shape: {
|
|
20960
|
+
geom: {
|
|
20961
|
+
shape: {
|
|
20962
|
+
type: 'envelope',
|
|
20963
|
+
// spatialFilterExtent is [minX, minY, maxX, maxY]; envelope coordinates are [top-left, bottom-right]
|
|
20964
|
+
coordinates: [
|
|
20965
|
+
[spatialFilterExtent[0], spatialFilterExtent[3]],
|
|
20966
|
+
[spatialFilterExtent[2], spatialFilterExtent[1]],
|
|
20967
|
+
],
|
|
20968
|
+
},
|
|
20969
|
+
relation: 'intersects',
|
|
20791
20970
|
},
|
|
20792
20971
|
},
|
|
20793
20972
|
},
|
|
@@ -20817,7 +20996,9 @@ class ElasticsearchService {
|
|
|
20817
20996
|
},
|
|
20818
20997
|
});
|
|
20819
20998
|
}
|
|
20820
|
-
|
|
20999
|
+
// a spatial extent filter takes precedence over the preference geometry for boosting
|
|
21000
|
+
const spatialFilterExtent = this.findSpatialFilterExtent(fieldSearchFilters);
|
|
21001
|
+
const queryFilters = this.filtersToQuery(fieldSearchFilters, spatialFilterExtent);
|
|
20821
21002
|
if (queryFilters) {
|
|
20822
21003
|
filter.push(...queryFilters);
|
|
20823
21004
|
}
|
|
@@ -20828,7 +21009,10 @@ class ElasticsearchService {
|
|
|
20828
21009
|
},
|
|
20829
21010
|
});
|
|
20830
21011
|
}
|
|
20831
|
-
|
|
21012
|
+
const boostGeometry = spatialFilterExtent
|
|
21013
|
+
? bboxToPolygon(spatialFilterExtent)
|
|
21014
|
+
: geometry;
|
|
21015
|
+
if (boostGeometry) {
|
|
20832
21016
|
// boosts applied using the filter geometry:
|
|
20833
21017
|
// * records completely within the geometry receive a boost of 5
|
|
20834
21018
|
// * records intersecting the geometry receive a boost of 2
|
|
@@ -20837,7 +21021,7 @@ class ElasticsearchService {
|
|
|
20837
21021
|
should.push({
|
|
20838
21022
|
geo_shape: {
|
|
20839
21023
|
geom: {
|
|
20840
|
-
shape:
|
|
21024
|
+
shape: boostGeometry,
|
|
20841
21025
|
relation: 'within',
|
|
20842
21026
|
},
|
|
20843
21027
|
boost: 5.0,
|
|
@@ -20845,7 +21029,7 @@ class ElasticsearchService {
|
|
|
20845
21029
|
}, {
|
|
20846
21030
|
geo_shape: {
|
|
20847
21031
|
geom: {
|
|
20848
|
-
shape:
|
|
21032
|
+
shape: boostGeometry,
|
|
20849
21033
|
relation: 'intersects',
|
|
20850
21034
|
},
|
|
20851
21035
|
boost: 2.0,
|
|
@@ -20854,7 +21038,7 @@ class ElasticsearchService {
|
|
|
20854
21038
|
// this will boost the results variably depending on their distance from the given geometry
|
|
20855
21039
|
// note: this takes into account the `location` field of a record; this is generally the center of all spatial extents
|
|
20856
21040
|
// combined, and thus the actual size/coverage of the record spatial extent isn't relevant here
|
|
20857
|
-
const bbox = getGeometryBoundingBox(
|
|
21041
|
+
const bbox = getGeometryBoundingBox(boostGeometry);
|
|
20858
21042
|
const center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
|
20859
21043
|
const northToCenter = new LineString([
|
|
20860
21044
|
[center[0], bbox[3]],
|
|
@@ -21180,7 +21364,7 @@ class Gn4Repository {
|
|
|
21180
21364
|
}
|
|
21181
21365
|
getRecord(uniqueIdentifier) {
|
|
21182
21366
|
return this.gn4SearchApi
|
|
21183
|
-
.search('bucket', ['fcats', 'hassources'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21367
|
+
.search('bucket', ['fcats', 'hassources', 'siblings', 'associated'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21184
21368
|
.pipe(map$1((results) => results.hits.hits[0]), switchMap((record) => record ? this.gn4Mapper.readRecord(record) : of(null)));
|
|
21185
21369
|
}
|
|
21186
21370
|
getMultipleRecords(uniqueIdentifiers) {
|
|
@@ -21234,19 +21418,28 @@ class Gn4Repository {
|
|
|
21234
21418
|
.search('bucket', null, JSON.stringify(this.gn4SearchHelper.getRelatedRecordPayload(similarTo, 3)))
|
|
21235
21419
|
.pipe(switchMap((results) => this.gn4Mapper.readRecords(results.hits.hits)));
|
|
21236
21420
|
}
|
|
21237
|
-
|
|
21238
|
-
const
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
|
|
21245
|
-
|
|
21246
|
-
|
|
21247
|
-
|
|
21421
|
+
getLinkedRecords(record) {
|
|
21422
|
+
const siblings = (record.extras?.['siblings'] ?? []);
|
|
21423
|
+
const relations = [
|
|
21424
|
+
['source', (record.extras?.['sourcesIdentifiers'] ?? [])],
|
|
21425
|
+
['sourceOf', (record.extras?.['sourceOfIdentifiers'] ?? [])],
|
|
21426
|
+
['sibling', siblings.map(({ uniqueIdentifier }) => uniqueIdentifier)],
|
|
21427
|
+
[
|
|
21428
|
+
'associated',
|
|
21429
|
+
(record.extras?.['associatedIdentifiers'] ?? []),
|
|
21430
|
+
],
|
|
21431
|
+
];
|
|
21432
|
+
const requested = relations.filter(([, identifiers]) => identifiers.length > 0);
|
|
21433
|
+
if (requested.length === 0) {
|
|
21434
|
+
return of([]);
|
|
21248
21435
|
}
|
|
21249
|
-
return
|
|
21436
|
+
return forkJoin(requested.map(([relation, identifiers]) => this.getMultipleRecords(identifiers).pipe(map$1((records) => (records ?? []).map((record) => ({
|
|
21437
|
+
record,
|
|
21438
|
+
relation,
|
|
21439
|
+
associationType: relation === 'sibling'
|
|
21440
|
+
? siblings.find(({ uniqueIdentifier }) => uniqueIdentifier === record.uniqueIdentifier)?.associationType
|
|
21441
|
+
: undefined,
|
|
21442
|
+
}))), catchError(() => of([]))))).pipe(map$1((groups) => groups.flat()));
|
|
21250
21443
|
}
|
|
21251
21444
|
aggregate(params) {
|
|
21252
21445
|
// if aggregations are empty, return an empty object right away
|
|
@@ -22435,48 +22628,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22435
22628
|
type: Injectable
|
|
22436
22629
|
}] });
|
|
22437
22630
|
|
|
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
22631
|
class FeatureMapModule {
|
|
22471
22632
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
22472
22633
|
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)] }); }
|
|
22634
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [MapFacade], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
|
|
22480
22635
|
}
|
|
22481
22636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, decorators: [{
|
|
22482
22637
|
type: NgModule,
|
|
@@ -22484,13 +22639,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
22484
22639
|
imports: [
|
|
22485
22640
|
StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
|
|
22486
22641
|
],
|
|
22487
|
-
providers: [
|
|
22488
|
-
MapFacade,
|
|
22489
|
-
{
|
|
22490
|
-
provide: GEOCODING_PROVIDER,
|
|
22491
|
-
useValue: ['geonames', { maxRows: 5 }],
|
|
22492
|
-
},
|
|
22493
|
-
],
|
|
22642
|
+
providers: [MapFacade],
|
|
22494
22643
|
}]
|
|
22495
22644
|
}] });
|
|
22496
22645
|
|
|
@@ -23225,6 +23374,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23225
23374
|
'search_preset',
|
|
23226
23375
|
'advanced_filters',
|
|
23227
23376
|
'limit',
|
|
23377
|
+
'spatial_extent_max_file_size',
|
|
23228
23378
|
], warnings, errors);
|
|
23229
23379
|
const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
|
|
23230
23380
|
searchConfig =
|
|
@@ -23242,6 +23392,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23242
23392
|
})),
|
|
23243
23393
|
ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
|
|
23244
23394
|
LIMIT: parsedSearchSection.limit,
|
|
23395
|
+
SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
|
|
23245
23396
|
};
|
|
23246
23397
|
const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
|
|
23247
23398
|
metadataQualityConfig =
|
|
@@ -24299,7 +24450,7 @@ class AutocompleteComponent {
|
|
|
24299
24450
|
this.enterBtnPosition = event.target['value'].length * 8 + 80;
|
|
24300
24451
|
}
|
|
24301
24452
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24302
|
-
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: [
|
|
24453
|
+
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: [
|
|
24303
24454
|
provideIcons({
|
|
24304
24455
|
iconoirSearch,
|
|
24305
24456
|
matClose,
|
|
@@ -24308,7 +24459,7 @@ class AutocompleteComponent {
|
|
|
24308
24459
|
provideNgIconsConfig({
|
|
24309
24460
|
size: '1.75rem',
|
|
24310
24461
|
}),
|
|
24311
|
-
], 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 }); }
|
|
24462
|
+
], 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 }); }
|
|
24312
24463
|
}
|
|
24313
24464
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
|
|
24314
24465
|
type: Component,
|
|
@@ -24329,7 +24480,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24329
24480
|
provideNgIconsConfig({
|
|
24330
24481
|
size: '1.75rem',
|
|
24331
24482
|
}),
|
|
24332
|
-
], 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"] }]
|
|
24483
|
+
], 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"] }]
|
|
24333
24484
|
}], propDecorators: { placeholder: [{
|
|
24334
24485
|
type: Input
|
|
24335
24486
|
}], enterButton: [{
|
|
@@ -24367,6 +24518,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24367
24518
|
}], inputRef: [{
|
|
24368
24519
|
type: ViewChild,
|
|
24369
24520
|
args: ['searchInput']
|
|
24521
|
+
}], displayWithTemplate: [{
|
|
24522
|
+
type: Input
|
|
24370
24523
|
}], displayWithFn: [{
|
|
24371
24524
|
type: Input
|
|
24372
24525
|
}] } });
|
|
@@ -24499,12 +24652,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24499
24652
|
type: Input
|
|
24500
24653
|
}] } });
|
|
24501
24654
|
|
|
24655
|
+
function provideLocalizedDateAdapter() {
|
|
24656
|
+
return [
|
|
24657
|
+
{ provide: MAT_DATE_LOCALE, useValue: enUS },
|
|
24658
|
+
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
|
|
24659
|
+
{
|
|
24660
|
+
provide: DateAdapter,
|
|
24661
|
+
useFactory: () => {
|
|
24662
|
+
const dateService = inject(DateService);
|
|
24663
|
+
const adapter = new DateFnsAdapter();
|
|
24664
|
+
dateService
|
|
24665
|
+
.getDateFnsLocale()
|
|
24666
|
+
.then((locale) => adapter.setLocale(locale));
|
|
24667
|
+
return adapter;
|
|
24668
|
+
},
|
|
24669
|
+
},
|
|
24670
|
+
];
|
|
24671
|
+
}
|
|
24672
|
+
|
|
24502
24673
|
class DatePickerComponent {
|
|
24503
24674
|
constructor() {
|
|
24504
|
-
this.dateAdapter = inject(DateAdapter);
|
|
24505
|
-
this.translate = inject(TranslateService);
|
|
24506
24675
|
this.dateChange = new EventEmitter();
|
|
24507
|
-
this.dateAdapter.setLocale(this.translate.getCurrentLang());
|
|
24508
24676
|
}
|
|
24509
24677
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24510
24678
|
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: [
|
|
@@ -24512,30 +24680,19 @@ class DatePickerComponent {
|
|
|
24512
24680
|
provideNgIconsConfig({
|
|
24513
24681
|
size: '1.5rem',
|
|
24514
24682
|
}),
|
|
24515
|
-
|
|
24516
|
-
|
|
24517
|
-
useFactory: (locale) => locale,
|
|
24518
|
-
},
|
|
24519
|
-
], 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 }); }
|
|
24683
|
+
provideLocalizedDateAdapter(),
|
|
24684
|
+
], 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 }); }
|
|
24520
24685
|
}
|
|
24521
24686
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
24522
24687
|
type: Component,
|
|
24523
|
-
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24524
|
-
MatNativeDateModule,
|
|
24525
|
-
MatDatepickerModule,
|
|
24526
|
-
ButtonComponent,
|
|
24527
|
-
NgIconComponent,
|
|
24528
|
-
], providers: [
|
|
24688
|
+
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24529
24689
|
provideIcons({ iconoirCalendar }),
|
|
24530
24690
|
provideNgIconsConfig({
|
|
24531
24691
|
size: '1.5rem',
|
|
24532
24692
|
}),
|
|
24533
|
-
|
|
24534
|
-
provide: MAT_DATE_LOCALE,
|
|
24535
|
-
useFactory: (locale) => locale,
|
|
24536
|
-
},
|
|
24693
|
+
provideLocalizedDateAdapter(),
|
|
24537
24694
|
], 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"] }]
|
|
24538
|
-
}],
|
|
24695
|
+
}], propDecorators: { date: [{
|
|
24539
24696
|
type: Input
|
|
24540
24697
|
}], dateChange: [{
|
|
24541
24698
|
type: Output
|
|
@@ -24543,58 +24700,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24543
24700
|
|
|
24544
24701
|
class DateRangeDropdownComponent {
|
|
24545
24702
|
constructor() {
|
|
24546
|
-
this.
|
|
24703
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
24704
|
+
this.dateAdapter = inject(DateAdapter);
|
|
24705
|
+
this.dateFormats = inject(MAT_DATE_FORMATS);
|
|
24547
24706
|
this.cdr = inject(ChangeDetectorRef);
|
|
24548
|
-
this.
|
|
24549
|
-
this.
|
|
24550
|
-
this.
|
|
24707
|
+
this.dateRange = {};
|
|
24708
|
+
this.dateRangeChange = new EventEmitter();
|
|
24709
|
+
this.overlayPositions = [
|
|
24710
|
+
{
|
|
24711
|
+
originX: 'start',
|
|
24712
|
+
originY: 'bottom',
|
|
24713
|
+
overlayX: 'start',
|
|
24714
|
+
overlayY: 'top',
|
|
24715
|
+
offsetY: 8,
|
|
24716
|
+
},
|
|
24717
|
+
{
|
|
24718
|
+
originX: 'start',
|
|
24719
|
+
originY: 'top',
|
|
24720
|
+
overlayX: 'start',
|
|
24721
|
+
overlayY: 'bottom',
|
|
24722
|
+
offsetY: -8,
|
|
24723
|
+
},
|
|
24724
|
+
];
|
|
24725
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
24726
|
+
this.overlayOpen = false;
|
|
24727
|
+
this.expandedBound = 'start';
|
|
24728
|
+
this.invalidBounds = { start: false, end: false };
|
|
24729
|
+
// redraw when the lazily loaded UI locale reaches the adapter
|
|
24730
|
+
this.dateAdapter.localeChanges
|
|
24731
|
+
.pipe(takeUntilDestroyed())
|
|
24732
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
24551
24733
|
}
|
|
24552
|
-
|
|
24553
|
-
this.
|
|
24734
|
+
get startDate() {
|
|
24735
|
+
return this.dateRange.start;
|
|
24554
24736
|
}
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
24737
|
+
get endDate() {
|
|
24738
|
+
return this.dateRange.end;
|
|
24739
|
+
}
|
|
24740
|
+
get selectedDatesCount() {
|
|
24741
|
+
return (this.startDate ? 1 : 0) + (this.endDate ? 1 : 0);
|
|
24742
|
+
}
|
|
24743
|
+
openOverlay() {
|
|
24744
|
+
this.expandedBound = 'start';
|
|
24745
|
+
this.overlayOpen = true;
|
|
24746
|
+
}
|
|
24747
|
+
closeOverlay() {
|
|
24748
|
+
this.overlayOpen = false;
|
|
24749
|
+
}
|
|
24750
|
+
toggleBound(bound) {
|
|
24751
|
+
this.expandedBound = this.expandedBound === bound ? null : bound;
|
|
24752
|
+
}
|
|
24753
|
+
formatDate(date) {
|
|
24754
|
+
return this.dateAdapter.format(date, this.dateFormats.display.dateInput);
|
|
24755
|
+
}
|
|
24756
|
+
onDateInput(bound, event) {
|
|
24757
|
+
const typedText = event.target.value.trim();
|
|
24758
|
+
const date = typedText
|
|
24759
|
+
? this.dateAdapter.parse(typedText, this.dateFormats.parse.dateInput)
|
|
24760
|
+
: null;
|
|
24761
|
+
if (!this.isAcceptable(bound, typedText, date)) {
|
|
24762
|
+
// keep the text as typed and flag it; the filter stays on its last value
|
|
24763
|
+
this.invalidBounds = { ...this.invalidBounds, [bound]: true };
|
|
24764
|
+
return;
|
|
24765
|
+
}
|
|
24766
|
+
if (bound === 'start')
|
|
24767
|
+
this.setStartDate(date);
|
|
24768
|
+
else
|
|
24769
|
+
this.setEndDate(date);
|
|
24770
|
+
}
|
|
24771
|
+
normalizeDateInput(bound, event) {
|
|
24772
|
+
if (this.invalidBounds[bound])
|
|
24773
|
+
return;
|
|
24774
|
+
const date = bound === 'start' ? this.startDate : this.endDate;
|
|
24775
|
+
const input = event.target;
|
|
24776
|
+
input.value = date ? this.formatDate(date) : '';
|
|
24777
|
+
}
|
|
24778
|
+
isAcceptable(bound, typedText, date) {
|
|
24779
|
+
if (!typedText)
|
|
24780
|
+
return true;
|
|
24781
|
+
if (!date || !this.dateAdapter.isValid(date))
|
|
24782
|
+
return false;
|
|
24783
|
+
return bound === 'start'
|
|
24784
|
+
? !this.endDate || date <= this.endDate
|
|
24785
|
+
: !this.startDate || date >= this.startDate;
|
|
24786
|
+
}
|
|
24787
|
+
setStartDate(date) {
|
|
24788
|
+
this.invalidBounds = { ...this.invalidBounds, start: false };
|
|
24789
|
+
this.applyDateRange({ ...this.dateRange, start: date });
|
|
24790
|
+
this.expandedBound = 'end';
|
|
24791
|
+
}
|
|
24792
|
+
setEndDate(date) {
|
|
24793
|
+
this.invalidBounds = { ...this.invalidBounds, end: false };
|
|
24794
|
+
this.applyDateRange({ ...this.dateRange, end: date });
|
|
24795
|
+
this.expandedBound = null;
|
|
24796
|
+
}
|
|
24797
|
+
clearDates(event) {
|
|
24798
|
+
this.invalidBounds = { start: false, end: false };
|
|
24799
|
+
this.expandedBound = 'start';
|
|
24800
|
+
this.applyDateRange({});
|
|
24801
|
+
propagateToDocumentOnly(event);
|
|
24802
|
+
}
|
|
24803
|
+
applyDateRange(dateRange) {
|
|
24804
|
+
this.dateRange = {
|
|
24805
|
+
...(dateRange.start && { start: dateRange.start }),
|
|
24806
|
+
...(dateRange.end && { end: dateRange.end }),
|
|
24807
|
+
};
|
|
24808
|
+
this.dateRangeChange.emit(this.dateRange);
|
|
24563
24809
|
}
|
|
24564
24810
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24565
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
24811
|
+
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: [
|
|
24566
24812
|
provideIcons({
|
|
24567
|
-
|
|
24813
|
+
iconoirCalendar,
|
|
24814
|
+
matClose,
|
|
24568
24815
|
matExpandLess,
|
|
24816
|
+
matExpandMore,
|
|
24569
24817
|
}),
|
|
24570
|
-
|
|
24818
|
+
provideNgIconsConfig({
|
|
24819
|
+
size: '1.5rem',
|
|
24820
|
+
}),
|
|
24821
|
+
provideLocalizedDateAdapter(),
|
|
24822
|
+
], 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 }); }
|
|
24571
24823
|
}
|
|
24572
24824
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, decorators: [{
|
|
24573
24825
|
type: Component,
|
|
24574
24826
|
args: [{ selector: 'gn-ui-date-range-dropdown', standalone: true, imports: [
|
|
24575
|
-
|
|
24576
|
-
MatNativeDateModule,
|
|
24577
|
-
MatDatepickerModule,
|
|
24827
|
+
AutofocusDirective,
|
|
24578
24828
|
ButtonComponent,
|
|
24829
|
+
MatDatepickerModule,
|
|
24830
|
+
NgIcon,
|
|
24831
|
+
NgTemplateOutlet,
|
|
24832
|
+
OverlayModule,
|
|
24833
|
+
TranslateDirective,
|
|
24834
|
+
TranslatePipe,
|
|
24579
24835
|
], providers: [
|
|
24580
24836
|
provideIcons({
|
|
24581
|
-
|
|
24837
|
+
iconoirCalendar,
|
|
24838
|
+
matClose,
|
|
24582
24839
|
matExpandLess,
|
|
24840
|
+
matExpandMore,
|
|
24583
24841
|
}),
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24842
|
+
provideNgIconsConfig({
|
|
24843
|
+
size: '1.5rem',
|
|
24844
|
+
}),
|
|
24845
|
+
provideLocalizedDateAdapter(),
|
|
24846
|
+
], 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"] }]
|
|
24847
|
+
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
24588
24848
|
type: Input
|
|
24589
|
-
}],
|
|
24849
|
+
}], dateRange: [{
|
|
24590
24850
|
type: Input
|
|
24591
|
-
}],
|
|
24851
|
+
}], dateRangeChange: [{
|
|
24592
24852
|
type: Output
|
|
24593
|
-
}],
|
|
24594
|
-
type: Output
|
|
24595
|
-
}], picker: [{
|
|
24853
|
+
}], overlayOrigin: [{
|
|
24596
24854
|
type: ViewChild,
|
|
24597
|
-
args: ['
|
|
24855
|
+
args: ['overlayOrigin']
|
|
24598
24856
|
}] } });
|
|
24599
24857
|
|
|
24600
24858
|
class DateRangePickerComponent {
|
|
@@ -24608,20 +24866,17 @@ class DateRangePickerComponent {
|
|
|
24608
24866
|
provideNgIconsConfig({
|
|
24609
24867
|
size: '1.5rem',
|
|
24610
24868
|
}),
|
|
24611
|
-
|
|
24869
|
+
provideLocalizedDateAdapter(),
|
|
24870
|
+
], 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 }); }
|
|
24612
24871
|
}
|
|
24613
24872
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
24614
24873
|
type: Component,
|
|
24615
|
-
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
24616
|
-
MatNativeDateModule,
|
|
24617
|
-
MatDatepickerModule,
|
|
24618
|
-
ButtonComponent,
|
|
24619
|
-
NgIconComponent,
|
|
24620
|
-
], providers: [
|
|
24874
|
+
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24621
24875
|
provideIcons({ iconoirCalendar }),
|
|
24622
24876
|
provideNgIconsConfig({
|
|
24623
24877
|
size: '1.5rem',
|
|
24624
24878
|
}),
|
|
24879
|
+
provideLocalizedDateAdapter(),
|
|
24625
24880
|
], 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"] }]
|
|
24626
24881
|
}], propDecorators: { startDate: [{
|
|
24627
24882
|
type: Input
|
|
@@ -24639,28 +24894,68 @@ class DragAndDropFileInputComponent {
|
|
|
24639
24894
|
constructor() {
|
|
24640
24895
|
this.placeholder = placeholder;
|
|
24641
24896
|
this.accept = '*';
|
|
24897
|
+
this.maxFileSizeMb = null;
|
|
24898
|
+
this.icon = null;
|
|
24899
|
+
this.dropzoneBackgroundColor = null;
|
|
24900
|
+
this.textClass = '';
|
|
24901
|
+
this.extraClass = '';
|
|
24902
|
+
this.showFileName = true;
|
|
24642
24903
|
this.fileChange = new EventEmitter();
|
|
24904
|
+
this.errorChange = new EventEmitter();
|
|
24643
24905
|
this.selectedFile = null;
|
|
24644
24906
|
}
|
|
24645
24907
|
get fileName() {
|
|
24646
24908
|
return this.selectedFile && this.selectedFile.name;
|
|
24647
24909
|
}
|
|
24910
|
+
get maxFileSizeBytes() {
|
|
24911
|
+
return typeof this.maxFileSizeMb === 'number'
|
|
24912
|
+
? megabytesToBytes(this.maxFileSizeMb)
|
|
24913
|
+
: null;
|
|
24914
|
+
}
|
|
24648
24915
|
selectFile(event) {
|
|
24916
|
+
if (event.rejectedFiles?.length) {
|
|
24917
|
+
const reason = event.rejectedFiles[0].reason;
|
|
24918
|
+
this.errorChange.emit(reason === 'size' ? 'file-too-large' : 'invalid-extension');
|
|
24919
|
+
return;
|
|
24920
|
+
}
|
|
24649
24921
|
this.selectedFile = event.addedFiles[0];
|
|
24650
24922
|
this.fileChange.emit(this.selectedFile);
|
|
24651
24923
|
}
|
|
24924
|
+
openFileSelector() {
|
|
24925
|
+
this.dropzone.showFileSelector();
|
|
24926
|
+
}
|
|
24927
|
+
clear() {
|
|
24928
|
+
this.selectedFile = null;
|
|
24929
|
+
}
|
|
24652
24930
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24653
|
-
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
|
|
24931
|
+
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"] }] }); }
|
|
24654
24932
|
}
|
|
24655
24933
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, decorators: [{
|
|
24656
24934
|
type: Component,
|
|
24657
|
-
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule], template: "<div
|
|
24935
|
+
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"] }]
|
|
24658
24936
|
}], propDecorators: { placeholder: [{
|
|
24659
24937
|
type: Input
|
|
24660
24938
|
}], accept: [{
|
|
24661
24939
|
type: Input
|
|
24940
|
+
}], maxFileSizeMb: [{
|
|
24941
|
+
type: Input
|
|
24942
|
+
}], icon: [{
|
|
24943
|
+
type: Input
|
|
24944
|
+
}], dropzoneBackgroundColor: [{
|
|
24945
|
+
type: Input
|
|
24946
|
+
}], textClass: [{
|
|
24947
|
+
type: Input
|
|
24948
|
+
}], extraClass: [{
|
|
24949
|
+
type: Input
|
|
24950
|
+
}], showFileName: [{
|
|
24951
|
+
type: Input
|
|
24662
24952
|
}], fileChange: [{
|
|
24663
24953
|
type: Output
|
|
24954
|
+
}], errorChange: [{
|
|
24955
|
+
type: Output
|
|
24956
|
+
}], dropzone: [{
|
|
24957
|
+
type: ViewChild,
|
|
24958
|
+
args: [NgxDropzoneComponent]
|
|
24664
24959
|
}] } });
|
|
24665
24960
|
|
|
24666
24961
|
class DropdownMultiselectComponent {
|
|
@@ -24709,7 +25004,7 @@ class DropdownMultiselectComponent {
|
|
|
24709
25004
|
}
|
|
24710
25005
|
setFocus() {
|
|
24711
25006
|
setTimeout(() => {
|
|
24712
|
-
this.searchFieldInput
|
|
25007
|
+
this.searchFieldInput?.nativeElement.focus();
|
|
24713
25008
|
}, 0);
|
|
24714
25009
|
}
|
|
24715
25010
|
openOverlay() {
|
|
@@ -24815,7 +25110,10 @@ class DropdownMultiselectComponent {
|
|
|
24815
25110
|
matExpandMore,
|
|
24816
25111
|
matExpandLess,
|
|
24817
25112
|
}),
|
|
24818
|
-
|
|
25113
|
+
provideNgIconsConfig({
|
|
25114
|
+
size: '1.5rem',
|
|
25115
|
+
}),
|
|
25116
|
+
], 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 }); }
|
|
24819
25117
|
}
|
|
24820
25118
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
|
|
24821
25119
|
type: Component,
|
|
@@ -24825,7 +25123,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24825
25123
|
matExpandMore,
|
|
24826
25124
|
matExpandLess,
|
|
24827
25125
|
}),
|
|
24828
|
-
|
|
25126
|
+
provideNgIconsConfig({
|
|
25127
|
+
size: '1.5rem',
|
|
25128
|
+
}),
|
|
25129
|
+
], 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" }]
|
|
24829
25130
|
}], propDecorators: { title: [{
|
|
24830
25131
|
type: Input
|
|
24831
25132
|
}], choices: [{
|
|
@@ -24997,7 +25298,7 @@ class DropdownSelectorComponent {
|
|
|
24997
25298
|
provideNgIconsConfig({
|
|
24998
25299
|
size: '1.5em',
|
|
24999
25300
|
}),
|
|
25000
|
-
], 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$
|
|
25301
|
+
], 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 }); }
|
|
25001
25302
|
}
|
|
25002
25303
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownSelectorComponent, decorators: [{
|
|
25003
25304
|
type: Component,
|
|
@@ -25737,6 +26038,180 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
25737
26038
|
type: Output
|
|
25738
26039
|
}] } });
|
|
25739
26040
|
|
|
26041
|
+
marker('search.filters.spatialExtent.import');
|
|
26042
|
+
marker('search.filters.spatialExtent.helpText');
|
|
26043
|
+
marker('search.filters.spatialExtent.error.title');
|
|
26044
|
+
marker('search.filters.spatialExtent.error.outOfBounds');
|
|
26045
|
+
const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
|
|
26046
|
+
const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
|
|
26047
|
+
const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
|
|
26048
|
+
const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
|
|
26049
|
+
class SpatialExtentDropdownComponent {
|
|
26050
|
+
constructor() {
|
|
26051
|
+
this.cd = inject(ChangeDetectorRef);
|
|
26052
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
26053
|
+
this.maxFileSizeMb = null;
|
|
26054
|
+
this.bboxChange = new EventEmitter();
|
|
26055
|
+
this.errorChange = new EventEmitter();
|
|
26056
|
+
this.bbox = null;
|
|
26057
|
+
this.fileName = '';
|
|
26058
|
+
this.overlayPositions = [
|
|
26059
|
+
{
|
|
26060
|
+
originX: 'start',
|
|
26061
|
+
originY: 'bottom',
|
|
26062
|
+
overlayX: 'start',
|
|
26063
|
+
overlayY: 'top',
|
|
26064
|
+
offsetY: 8,
|
|
26065
|
+
},
|
|
26066
|
+
{
|
|
26067
|
+
originX: 'start',
|
|
26068
|
+
originY: 'top',
|
|
26069
|
+
overlayX: 'start',
|
|
26070
|
+
overlayY: 'bottom',
|
|
26071
|
+
offsetY: -8,
|
|
26072
|
+
},
|
|
26073
|
+
];
|
|
26074
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
26075
|
+
this.overlayOpen = false;
|
|
26076
|
+
this.overlayMinWidth = 'none';
|
|
26077
|
+
this.errorKey = null;
|
|
26078
|
+
}
|
|
26079
|
+
set initialBbox(value) {
|
|
26080
|
+
if (!this.bbox && value) {
|
|
26081
|
+
this.bbox = value;
|
|
26082
|
+
}
|
|
26083
|
+
}
|
|
26084
|
+
get hasSelection() {
|
|
26085
|
+
return !!this.bbox;
|
|
26086
|
+
}
|
|
26087
|
+
get selectionLabelKey() {
|
|
26088
|
+
return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
|
|
26089
|
+
}
|
|
26090
|
+
get selectionDeleteLabelKey() {
|
|
26091
|
+
return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
|
|
26092
|
+
}
|
|
26093
|
+
get selectionLabelParams() {
|
|
26094
|
+
return { fileName: this.fileName };
|
|
26095
|
+
}
|
|
26096
|
+
openOverlay() {
|
|
26097
|
+
this.overlayMinWidth =
|
|
26098
|
+
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
|
|
26099
|
+
.width + 'px';
|
|
26100
|
+
this.overlayOpen = true;
|
|
26101
|
+
}
|
|
26102
|
+
closeOverlay() {
|
|
26103
|
+
this.overlayOpen = false;
|
|
26104
|
+
}
|
|
26105
|
+
toggleOverlay() {
|
|
26106
|
+
if (this.overlayOpen) {
|
|
26107
|
+
this.closeOverlay();
|
|
26108
|
+
}
|
|
26109
|
+
else {
|
|
26110
|
+
this.openOverlay();
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
26113
|
+
async handleFileSelected(file) {
|
|
26114
|
+
this.errorKey = null;
|
|
26115
|
+
let content;
|
|
26116
|
+
try {
|
|
26117
|
+
content = await readFileAsText(file);
|
|
26118
|
+
const parsed = JSON.parse(content);
|
|
26119
|
+
const geometry = getGeometryFromGeoJSON(parsed);
|
|
26120
|
+
if (!geometry) {
|
|
26121
|
+
this.setError(marker('search.filters.spatialExtent.error.noGeometry'));
|
|
26122
|
+
return;
|
|
26123
|
+
}
|
|
26124
|
+
const bbox = getGeometryBoundingBox(geometry);
|
|
26125
|
+
if (!isBoundingBoxWithinWorldExtent(bbox)) {
|
|
26126
|
+
this.setError(marker('search.filters.spatialExtent.error.outOfBounds'));
|
|
26127
|
+
return;
|
|
26128
|
+
}
|
|
26129
|
+
this.bbox = bbox;
|
|
26130
|
+
this.fileName = file.name;
|
|
26131
|
+
this.bboxChange.emit(bbox);
|
|
26132
|
+
this.cd.markForCheck();
|
|
26133
|
+
}
|
|
26134
|
+
catch {
|
|
26135
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26136
|
+
return;
|
|
26137
|
+
}
|
|
26138
|
+
}
|
|
26139
|
+
handleFileError(error) {
|
|
26140
|
+
if (error === 'file-too-large') {
|
|
26141
|
+
this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
|
|
26142
|
+
maxSize: this.maxFileSizeMb,
|
|
26143
|
+
});
|
|
26144
|
+
}
|
|
26145
|
+
else {
|
|
26146
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26147
|
+
}
|
|
26148
|
+
}
|
|
26149
|
+
setError(errorKey, params) {
|
|
26150
|
+
this.errorKey = errorKey;
|
|
26151
|
+
this.errorChange.emit({ key: errorKey, params });
|
|
26152
|
+
this.cd.markForCheck();
|
|
26153
|
+
}
|
|
26154
|
+
removeSelection(event) {
|
|
26155
|
+
this.bbox = null;
|
|
26156
|
+
this.fileName = '';
|
|
26157
|
+
this.errorKey = null;
|
|
26158
|
+
this.fileInput?.clear();
|
|
26159
|
+
this.bboxChange.emit(null);
|
|
26160
|
+
propagateToDocumentOnly(event);
|
|
26161
|
+
}
|
|
26162
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26163
|
+
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: [
|
|
26164
|
+
provideIcons({
|
|
26165
|
+
iconoirCheckCircle,
|
|
26166
|
+
iconoirSquareDashed,
|
|
26167
|
+
iconoirTrash,
|
|
26168
|
+
iconoirUpload,
|
|
26169
|
+
matClose,
|
|
26170
|
+
matExpandLess,
|
|
26171
|
+
matExpandMore,
|
|
26172
|
+
}),
|
|
26173
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[12px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirUpload\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
26174
|
+
}
|
|
26175
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
|
|
26176
|
+
type: Component,
|
|
26177
|
+
args: [{ selector: 'gn-ui-spatial-extent-dropdown', standalone: true, imports: [
|
|
26178
|
+
ButtonComponent,
|
|
26179
|
+
NgIcon,
|
|
26180
|
+
OverlayModule,
|
|
26181
|
+
TranslatePipe,
|
|
26182
|
+
DragAndDropFileInputComponent,
|
|
26183
|
+
], providers: [
|
|
26184
|
+
provideIcons({
|
|
26185
|
+
iconoirCheckCircle,
|
|
26186
|
+
iconoirSquareDashed,
|
|
26187
|
+
iconoirTrash,
|
|
26188
|
+
iconoirUpload,
|
|
26189
|
+
matClose,
|
|
26190
|
+
matExpandLess,
|
|
26191
|
+
matExpandMore,
|
|
26192
|
+
}),
|
|
26193
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[12px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirUpload\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
|
|
26194
|
+
}], propDecorators: { title: [{
|
|
26195
|
+
type: Input
|
|
26196
|
+
}], maxFileSizeMb: [{
|
|
26197
|
+
type: Input
|
|
26198
|
+
}], initialBbox: [{
|
|
26199
|
+
type: Input
|
|
26200
|
+
}], bboxChange: [{
|
|
26201
|
+
type: Output
|
|
26202
|
+
}], errorChange: [{
|
|
26203
|
+
type: Output
|
|
26204
|
+
}], overlayOrigin: [{
|
|
26205
|
+
type: ViewChild,
|
|
26206
|
+
args: ['overlayOrigin']
|
|
26207
|
+
}], overlay: [{
|
|
26208
|
+
type: ViewChild,
|
|
26209
|
+
args: [CdkConnectedOverlay]
|
|
26210
|
+
}], fileInput: [{
|
|
26211
|
+
type: ViewChild,
|
|
26212
|
+
args: [DragAndDropFileInputComponent]
|
|
26213
|
+
}] } });
|
|
26214
|
+
|
|
25740
26215
|
class CellPopinComponent {
|
|
25741
26216
|
constructor() {
|
|
25742
26217
|
this.scrollDispatcher = inject(ScrollDispatcher);
|
|
@@ -25813,7 +26288,7 @@ class CellPopinComponent {
|
|
|
25813
26288
|
this.isOpen = false;
|
|
25814
26289
|
}
|
|
25815
26290
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25816
|
-
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$
|
|
26291
|
+
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"] }] }); }
|
|
25817
26292
|
}
|
|
25818
26293
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, decorators: [{
|
|
25819
26294
|
type: Component,
|
|
@@ -27435,6 +27910,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
27435
27910
|
}]
|
|
27436
27911
|
}] });
|
|
27437
27912
|
|
|
27913
|
+
const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
|
|
27914
|
+
providedIn: 'root',
|
|
27915
|
+
factory: () => ['geonames', { maxRows: 5 }],
|
|
27916
|
+
});
|
|
27917
|
+
class GeocodingService {
|
|
27918
|
+
constructor() {
|
|
27919
|
+
this.provider = inject(GEOCODING_PROVIDER);
|
|
27920
|
+
}
|
|
27921
|
+
query(text) {
|
|
27922
|
+
let queryObservable;
|
|
27923
|
+
switch (this.provider[0]) {
|
|
27924
|
+
case 'geoadmin':
|
|
27925
|
+
queryObservable = from(queryGeoadmin(text, this.provider[1]));
|
|
27926
|
+
break;
|
|
27927
|
+
case 'geonames':
|
|
27928
|
+
queryObservable = from(queryGeonames(text, this.provider[1]));
|
|
27929
|
+
break;
|
|
27930
|
+
case 'data-gouv-fr':
|
|
27931
|
+
queryObservable = from(queryDataGouvFr(text, this.provider[1]));
|
|
27932
|
+
break;
|
|
27933
|
+
default:
|
|
27934
|
+
return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
|
|
27935
|
+
}
|
|
27936
|
+
return queryObservable.pipe(catchError((error) => throwError(error)));
|
|
27937
|
+
}
|
|
27938
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
27939
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
|
|
27940
|
+
}
|
|
27941
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
|
|
27942
|
+
type: Injectable,
|
|
27943
|
+
args: [{
|
|
27944
|
+
providedIn: 'root',
|
|
27945
|
+
}]
|
|
27946
|
+
}] });
|
|
27947
|
+
|
|
27948
|
+
class LocationSearchComponent {
|
|
27949
|
+
constructor() {
|
|
27950
|
+
this.geocodingService = inject(GeocodingService);
|
|
27951
|
+
this.placeholder = '';
|
|
27952
|
+
this.resultSelected = new EventEmitter();
|
|
27953
|
+
this.displayWithFn = (item) => item.label;
|
|
27954
|
+
this.searchAction = (text) => this.geocodingService.query(text);
|
|
27955
|
+
}
|
|
27956
|
+
handleItemSelected(item) {
|
|
27957
|
+
this.resultSelected.emit(item);
|
|
27958
|
+
}
|
|
27959
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
27960
|
+
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 }); }
|
|
27961
|
+
}
|
|
27962
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
|
|
27963
|
+
type: Component,
|
|
27964
|
+
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" }]
|
|
27965
|
+
}], propDecorators: { placeholder: [{
|
|
27966
|
+
type: Input
|
|
27967
|
+
}], displayWithTemplate: [{
|
|
27968
|
+
type: Input
|
|
27969
|
+
}], resultSelected: [{
|
|
27970
|
+
type: Output
|
|
27971
|
+
}] } });
|
|
27972
|
+
|
|
27438
27973
|
// expects the replacement key ${uuid}
|
|
27439
27974
|
const RECORD_DATASET_URL_TOKEN = new InjectionToken('record-dataset-url-token');
|
|
27440
27975
|
const RECORD_SERVICE_URL_TOKEN = new InjectionToken('record-service-url-token');
|
|
@@ -27903,6 +28438,45 @@ class DateRangeSearchField extends SimpleSearchField {
|
|
|
27903
28438
|
return 'dateRange';
|
|
27904
28439
|
}
|
|
27905
28440
|
}
|
|
28441
|
+
// treats a resource's creation/revision dates as an interval (its min and max), so a record matches
|
|
28442
|
+
// when that interval intersects the filter range, not just when a single date falls inside it
|
|
28443
|
+
class ResourceCreationRevisionDateSearchField extends DateRangeSearchField {
|
|
28444
|
+
constructor(injector, order = 'desc') {
|
|
28445
|
+
super('resourceCreationRevisionDate', injector, order);
|
|
28446
|
+
const dateSourceFields = [
|
|
28447
|
+
'creationDateForResource',
|
|
28448
|
+
'revisionDateForResource',
|
|
28449
|
+
];
|
|
28450
|
+
const collectSortedDates = dateSourceFields
|
|
28451
|
+
.map((field) => `if (doc.containsKey('${field}')) {
|
|
28452
|
+
for (def date : doc['${field}']) { dates.add(date.millis); }
|
|
28453
|
+
}`)
|
|
28454
|
+
.join('\n');
|
|
28455
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMin', `def dates = [];
|
|
28456
|
+
${collectSortedDates}
|
|
28457
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[0]); }`, 'date');
|
|
28458
|
+
this.esService.registerRuntimeField('resourceCreationRevisionDateMax', `def dates = [];
|
|
28459
|
+
${collectSortedDates}
|
|
28460
|
+
if (dates.length > 0) { dates.sort(null); emit(dates[dates.length - 1]); }`, 'date');
|
|
28461
|
+
}
|
|
28462
|
+
}
|
|
28463
|
+
class BoundingBoxSearchField extends SimpleSearchField {
|
|
28464
|
+
getAvailableValues() {
|
|
28465
|
+
return of([]);
|
|
28466
|
+
}
|
|
28467
|
+
getFiltersForValues(values) {
|
|
28468
|
+
return of({
|
|
28469
|
+
[this.esFieldName]: values.map(Number),
|
|
28470
|
+
});
|
|
28471
|
+
}
|
|
28472
|
+
getValuesForFilter(filters) {
|
|
28473
|
+
const filter = filters[this.esFieldName];
|
|
28474
|
+
return of(isBoundingBox(filter) ? filter : []);
|
|
28475
|
+
}
|
|
28476
|
+
getType() {
|
|
28477
|
+
return 'spatialExtent';
|
|
28478
|
+
}
|
|
28479
|
+
}
|
|
27906
28480
|
marker('search.filters.availableServices.view');
|
|
27907
28481
|
marker('search.filters.availableServices.download');
|
|
27908
28482
|
class AvailableServicesField extends SimpleSearchField {
|
|
@@ -28047,6 +28621,8 @@ marker('search.filters.producerOrg');
|
|
|
28047
28621
|
marker('search.filters.publisherOrg');
|
|
28048
28622
|
marker('search.filters.user');
|
|
28049
28623
|
marker('search.filters.changeDate');
|
|
28624
|
+
marker('search.filters.resourceCreationRevisionDate');
|
|
28625
|
+
marker('search.filters.spatialExtent');
|
|
28050
28626
|
class FieldsService {
|
|
28051
28627
|
constructor() {
|
|
28052
28628
|
this.injector = inject(Injector);
|
|
@@ -28069,7 +28645,9 @@ class FieldsService {
|
|
|
28069
28645
|
publisherOrg: new MultilingualSearchField('distributorOrgForResourceObject', this.injector, 'asc', 'key'),
|
|
28070
28646
|
user: new UserSearchField(this.injector),
|
|
28071
28647
|
changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
|
|
28648
|
+
resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
|
|
28072
28649
|
availableServices: new AvailableServicesField(this.injector),
|
|
28650
|
+
spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
|
|
28073
28651
|
};
|
|
28074
28652
|
}
|
|
28075
28653
|
get supportedFields() {
|
|
@@ -29332,7 +29910,7 @@ class ContactPillComponent {
|
|
|
29332
29910
|
this.overlayOpen = false;
|
|
29333
29911
|
}
|
|
29334
29912
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
29335
|
-
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$
|
|
29913
|
+
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 }); }
|
|
29336
29914
|
}
|
|
29337
29915
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, decorators: [{
|
|
29338
29916
|
type: Component,
|
|
@@ -30058,7 +30636,7 @@ class ServiceCapabilitiesComponent {
|
|
|
30058
30636
|
if (this.apiLinks.length > 0 &&
|
|
30059
30637
|
this.apiLinks[0].accessServiceProtocol !== 'ogcFeatures') {
|
|
30060
30638
|
this.loading = true;
|
|
30061
|
-
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol);
|
|
30639
|
+
this.availableLayers = await getLayers(this.apiLinks[0].url.href, this.apiLinks[0].accessServiceProtocol, true);
|
|
30062
30640
|
this.loading = false;
|
|
30063
30641
|
this.cdr.detectChanges();
|
|
30064
30642
|
this.filteredLayers = this.availableLayers;
|
|
@@ -31254,19 +31832,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31254
31832
|
type: Output
|
|
31255
31833
|
}] } });
|
|
31256
31834
|
|
|
31835
|
+
class NotificationsService {
|
|
31836
|
+
constructor() {
|
|
31837
|
+
this.notifications$ = new BehaviorSubject([]);
|
|
31838
|
+
}
|
|
31839
|
+
showNotification(content, timeoutMs, error) {
|
|
31840
|
+
error && console.error(error);
|
|
31841
|
+
const id = Math.floor(Math.random() * 1000000);
|
|
31842
|
+
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31843
|
+
if (typeof timeoutMs !== 'undefined') {
|
|
31844
|
+
setTimeout(() => {
|
|
31845
|
+
this.removeNotificationById(id);
|
|
31846
|
+
}, timeoutMs);
|
|
31847
|
+
}
|
|
31848
|
+
return id;
|
|
31849
|
+
}
|
|
31850
|
+
removeNotificationById(id) {
|
|
31851
|
+
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31852
|
+
}
|
|
31853
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31854
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31855
|
+
}
|
|
31856
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31857
|
+
type: Injectable,
|
|
31858
|
+
args: [{
|
|
31859
|
+
providedIn: 'root',
|
|
31860
|
+
}]
|
|
31861
|
+
}] });
|
|
31862
|
+
|
|
31863
|
+
class NotificationsContainerComponent {
|
|
31864
|
+
constructor() {
|
|
31865
|
+
this.notificationsService = inject(NotificationsService);
|
|
31866
|
+
}
|
|
31867
|
+
trackById(index, notification) {
|
|
31868
|
+
return notification.id;
|
|
31869
|
+
}
|
|
31870
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31871
|
+
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: [
|
|
31872
|
+
trigger('enterExit', [
|
|
31873
|
+
transition(':enter', [
|
|
31874
|
+
animate('150ms', keyframes([
|
|
31875
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31876
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31877
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31878
|
+
])),
|
|
31879
|
+
]),
|
|
31880
|
+
transition(':leave', [
|
|
31881
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31882
|
+
]),
|
|
31883
|
+
]),
|
|
31884
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31885
|
+
}
|
|
31886
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31887
|
+
type: Component,
|
|
31888
|
+
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31889
|
+
trigger('enterExit', [
|
|
31890
|
+
transition(':enter', [
|
|
31891
|
+
animate('150ms', keyframes([
|
|
31892
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31893
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31894
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31895
|
+
])),
|
|
31896
|
+
]),
|
|
31897
|
+
transition(':leave', [
|
|
31898
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31899
|
+
]),
|
|
31900
|
+
]),
|
|
31901
|
+
], 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" }]
|
|
31902
|
+
}] });
|
|
31903
|
+
|
|
31257
31904
|
class FilterDropdownComponent {
|
|
31258
31905
|
constructor() {
|
|
31259
31906
|
this.searchFacade = inject(SearchFacade);
|
|
31260
31907
|
this.searchService = inject(SearchService);
|
|
31261
31908
|
this.fieldsService = inject(FieldsService);
|
|
31909
|
+
this.notificationsService = inject(NotificationsService);
|
|
31910
|
+
this.translateService = inject(TranslateService);
|
|
31911
|
+
this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
|
|
31262
31912
|
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([])));
|
|
31263
|
-
this.selectedDateRange$ = this.selected$.pipe(map$1((
|
|
31913
|
+
this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
|
|
31914
|
+
this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
|
|
31915
|
+
? selected
|
|
31916
|
+
: null));
|
|
31917
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31264
31918
|
}
|
|
31265
31919
|
onSelectedValues(values) {
|
|
31266
31920
|
this.fieldsService
|
|
31267
31921
|
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
31268
31922
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31269
31923
|
}
|
|
31924
|
+
onBboxChange(bbox) {
|
|
31925
|
+
this.fieldsService
|
|
31926
|
+
.buildFiltersFromFieldValues({
|
|
31927
|
+
[this.fieldName]: bbox,
|
|
31928
|
+
})
|
|
31929
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31930
|
+
this.clearSpatialExtentErrorNotification();
|
|
31931
|
+
}
|
|
31932
|
+
onSpatialExtentError(error) {
|
|
31933
|
+
this.clearSpatialExtentErrorNotification();
|
|
31934
|
+
this.spatialExtentErrorNotificationId =
|
|
31935
|
+
this.notificationsService.showNotification({
|
|
31936
|
+
type: 'error',
|
|
31937
|
+
title: this.translateService.instant('search.filters.spatialExtent.error.title'),
|
|
31938
|
+
text: this.translateService.instant(error.key, error.params),
|
|
31939
|
+
});
|
|
31940
|
+
}
|
|
31941
|
+
clearSpatialExtentErrorNotification() {
|
|
31942
|
+
if (this.spatialExtentErrorNotificationId === null)
|
|
31943
|
+
return;
|
|
31944
|
+
this.notificationsService.removeNotificationById(this.spatialExtentErrorNotificationId);
|
|
31945
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31946
|
+
}
|
|
31270
31947
|
ngOnInit() {
|
|
31271
31948
|
this.fieldType = this.fieldsService.getFieldType(this.fieldName);
|
|
31272
31949
|
this.choices$ = this.fieldsService.getAvailableValues(this.fieldName).pipe(startWith$1([]), map$1((values) => values.map((v) => ({
|
|
@@ -31274,27 +31951,15 @@ class FilterDropdownComponent {
|
|
|
31274
31951
|
value: v.value.toString(), // converting to string for the dropdown
|
|
31275
31952
|
}))), catchError(() => of([])));
|
|
31276
31953
|
}
|
|
31277
|
-
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31282
|
-
|
|
31283
|
-
if (!end)
|
|
31284
|
-
return;
|
|
31285
|
-
this.dateRange = { ...this.dateRange, end };
|
|
31286
|
-
if (this.dateRange.start && this.dateRange.end) {
|
|
31287
|
-
this.fieldsService
|
|
31288
|
-
.buildFiltersFromFieldValues({
|
|
31289
|
-
[this.fieldName]: this.dateRange,
|
|
31290
|
-
})
|
|
31291
|
-
.subscribe((filters) => {
|
|
31292
|
-
return this.searchService.updateFilters(filters);
|
|
31293
|
-
});
|
|
31294
|
-
}
|
|
31954
|
+
onDateRangeChange(dateRange) {
|
|
31955
|
+
this.fieldsService
|
|
31956
|
+
.buildFiltersFromFieldValues({
|
|
31957
|
+
[this.fieldName]: dateRange,
|
|
31958
|
+
})
|
|
31959
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31295
31960
|
}
|
|
31296
31961
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31297
|
-
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 [
|
|
31962
|
+
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 }); }
|
|
31298
31963
|
}
|
|
31299
31964
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
|
|
31300
31965
|
type: Component,
|
|
@@ -31302,7 +31967,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31302
31967
|
CommonModule,
|
|
31303
31968
|
DateRangeDropdownComponent,
|
|
31304
31969
|
DropdownMultiselectComponent,
|
|
31305
|
-
|
|
31970
|
+
SpatialExtentDropdownComponent,
|
|
31971
|
+
], 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" }]
|
|
31306
31972
|
}], propDecorators: { fieldName: [{
|
|
31307
31973
|
type: Input
|
|
31308
31974
|
}], title: [{
|
|
@@ -31363,7 +32029,7 @@ class FuzzySearchComponent {
|
|
|
31363
32029
|
this.isSearchActive.emit(event);
|
|
31364
32030
|
}
|
|
31365
32031
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31366
|
-
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 }); }
|
|
32032
|
+
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 }); }
|
|
31367
32033
|
}
|
|
31368
32034
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, decorators: [{
|
|
31369
32035
|
type: Component,
|
|
@@ -31772,11 +32438,7 @@ const SortByEnum = {
|
|
|
31772
32438
|
RELEVANCY: ['desc', '_score'],
|
|
31773
32439
|
QUALITY_SCORE: ['desc', 'qualityScore'],
|
|
31774
32440
|
CHANGE_DATE: ['desc', 'changeDate'],
|
|
31775
|
-
|
|
31776
|
-
['desc', 'revisionDateForResource'],
|
|
31777
|
-
['desc', 'publicationDateForResource'],
|
|
31778
|
-
['desc', 'creationDateForResource'],
|
|
31779
|
-
],
|
|
32441
|
+
RESOURCE_DATE: ['desc', 'resourceDate.date'],
|
|
31780
32442
|
};
|
|
31781
32443
|
|
|
31782
32444
|
class SortByComponent {
|
|
@@ -31790,7 +32452,7 @@ class SortByComponent {
|
|
|
31790
32452
|
},
|
|
31791
32453
|
{
|
|
31792
32454
|
label: marker('results.sortBy.dateStamp'),
|
|
31793
|
-
value: SortByEnum.
|
|
32455
|
+
value: SortByEnum.RESOURCE_DATE,
|
|
31794
32456
|
},
|
|
31795
32457
|
{
|
|
31796
32458
|
label: marker('results.sortBy.popularity'),
|
|
@@ -31842,74 +32504,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31842
32504
|
args: ['gnUiSearchStateContainer']
|
|
31843
32505
|
}] } });
|
|
31844
32506
|
|
|
31845
|
-
class NotificationsService {
|
|
31846
|
-
constructor() {
|
|
31847
|
-
this.notifications$ = new BehaviorSubject([]);
|
|
31848
|
-
}
|
|
31849
|
-
showNotification(content, timeoutMs, error) {
|
|
31850
|
-
error && console.error(error);
|
|
31851
|
-
const id = Math.floor(Math.random() * 1000000);
|
|
31852
|
-
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31853
|
-
if (typeof timeoutMs === 'undefined')
|
|
31854
|
-
return;
|
|
31855
|
-
setTimeout(() => {
|
|
31856
|
-
this.removeNotificationById(id);
|
|
31857
|
-
}, timeoutMs);
|
|
31858
|
-
}
|
|
31859
|
-
removeNotificationById(id) {
|
|
31860
|
-
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31861
|
-
}
|
|
31862
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31863
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31864
|
-
}
|
|
31865
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31866
|
-
type: Injectable,
|
|
31867
|
-
args: [{
|
|
31868
|
-
providedIn: 'root',
|
|
31869
|
-
}]
|
|
31870
|
-
}] });
|
|
31871
|
-
|
|
31872
|
-
class NotificationsContainerComponent {
|
|
31873
|
-
constructor() {
|
|
31874
|
-
this.notificationsService = inject(NotificationsService);
|
|
31875
|
-
}
|
|
31876
|
-
trackById(index, notification) {
|
|
31877
|
-
return notification.id;
|
|
31878
|
-
}
|
|
31879
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31880
|
-
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: [
|
|
31881
|
-
trigger('enterExit', [
|
|
31882
|
-
transition(':enter', [
|
|
31883
|
-
animate('150ms', keyframes([
|
|
31884
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31885
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31886
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31887
|
-
])),
|
|
31888
|
-
]),
|
|
31889
|
-
transition(':leave', [
|
|
31890
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31891
|
-
]),
|
|
31892
|
-
]),
|
|
31893
|
-
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31894
|
-
}
|
|
31895
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31896
|
-
type: Component,
|
|
31897
|
-
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31898
|
-
trigger('enterExit', [
|
|
31899
|
-
transition(':enter', [
|
|
31900
|
-
animate('150ms', keyframes([
|
|
31901
|
-
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31902
|
-
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31903
|
-
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31904
|
-
])),
|
|
31905
|
-
]),
|
|
31906
|
-
transition(':leave', [
|
|
31907
|
-
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31908
|
-
]),
|
|
31909
|
-
]),
|
|
31910
|
-
], 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" }]
|
|
31911
|
-
}] });
|
|
31912
|
-
|
|
31913
32507
|
class ResultsTableContainerComponent {
|
|
31914
32508
|
constructor() {
|
|
31915
32509
|
this.searchFacade = inject(SearchFacade);
|
|
@@ -31994,12 +32588,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31994
32588
|
|
|
31995
32589
|
marker('search.filters.summaryLabel.user');
|
|
31996
32590
|
marker('search.filters.summaryLabel.changeDate');
|
|
32591
|
+
marker('search.filters.summaryLabel.resourceCreationRevisionDate');
|
|
32592
|
+
const OPEN_BOUND = '…';
|
|
31997
32593
|
class SearchFiltersSummaryItemComponent {
|
|
31998
32594
|
constructor() {
|
|
31999
32595
|
this.searchFacade = inject(SearchFacade);
|
|
32000
32596
|
this.searchService = inject(SearchService);
|
|
32001
32597
|
this.fieldsService = inject(FieldsService);
|
|
32002
|
-
this.
|
|
32598
|
+
this.dateService = inject(DateService);
|
|
32003
32599
|
this.translate = inject(TranslateService);
|
|
32004
32600
|
this.fieldValues$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$2((fieldValues) => Array.isArray(fieldValues[this.fieldName])
|
|
32005
32601
|
? fieldValues[this.fieldName]
|
|
@@ -32026,9 +32622,10 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32026
32622
|
getReadableValues(fieldValues) {
|
|
32027
32623
|
return fieldValues.map((value) => {
|
|
32028
32624
|
if (this.fieldType === 'dateRange') {
|
|
32625
|
+
const { start, end } = value;
|
|
32029
32626
|
return {
|
|
32030
32627
|
value,
|
|
32031
|
-
label: `${this.
|
|
32628
|
+
label: `${this.formatBound(start)} - ${this.formatBound(end)}`,
|
|
32032
32629
|
};
|
|
32033
32630
|
}
|
|
32034
32631
|
else if (this.fieldName === 'user') {
|
|
@@ -32039,6 +32636,15 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32039
32636
|
}
|
|
32040
32637
|
});
|
|
32041
32638
|
}
|
|
32639
|
+
formatBound(date) {
|
|
32640
|
+
return date
|
|
32641
|
+
? this.dateService.formatDate(date, {
|
|
32642
|
+
day: '2-digit',
|
|
32643
|
+
month: '2-digit',
|
|
32644
|
+
year: 'numeric',
|
|
32645
|
+
})
|
|
32646
|
+
: OPEN_BOUND;
|
|
32647
|
+
}
|
|
32042
32648
|
async removeFilterValue(fieldValue) {
|
|
32043
32649
|
const currentFieldValues = await firstValueFrom(this.fieldValues$);
|
|
32044
32650
|
const updatedFieldValues = currentFieldValues
|
|
@@ -32051,11 +32657,11 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32051
32657
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
32052
32658
|
}
|
|
32053
32659
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32054
|
-
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" },
|
|
32660
|
+
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" }] }); }
|
|
32055
32661
|
}
|
|
32056
32662
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, decorators: [{
|
|
32057
32663
|
type: Component,
|
|
32058
|
-
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent],
|
|
32664
|
+
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" }]
|
|
32059
32665
|
}], propDecorators: { fieldName: [{
|
|
32060
32666
|
type: Input
|
|
32061
32667
|
}] } });
|
|
@@ -32299,11 +32905,11 @@ class AddLayerFromFileComponent {
|
|
|
32299
32905
|
}, 5000);
|
|
32300
32906
|
}
|
|
32301
32907
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32302
|
-
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" }] }); }
|
|
32908
|
+
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" }] }); }
|
|
32303
32909
|
}
|
|
32304
32910
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, decorators: [{
|
|
32305
32911
|
type: Component,
|
|
32306
|
-
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" }]
|
|
32912
|
+
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" }]
|
|
32307
32913
|
}] });
|
|
32308
32914
|
|
|
32309
32915
|
class LayersPanelComponent {
|
|
@@ -32364,95 +32970,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
32364
32970
|
], 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" }]
|
|
32365
32971
|
}] });
|
|
32366
32972
|
|
|
32367
|
-
class GeocodingComponent {
|
|
32368
|
-
constructor() {
|
|
32369
|
-
this.mapFacade = inject(MapFacade);
|
|
32370
|
-
this.geocodingService = inject(GeocodingService);
|
|
32371
|
-
this.searchText = '';
|
|
32372
|
-
this.results = [];
|
|
32373
|
-
this.searchTextChanged = new Subject();
|
|
32374
|
-
this.destroy$ = new Subject();
|
|
32375
|
-
this.errorMessage = null;
|
|
32376
|
-
this.searchTextChanged
|
|
32377
|
-
.pipe(debounceTime(300), switchMap$1((searchText) => {
|
|
32378
|
-
return from(this.geocodingService.query(searchText)).pipe(catchError$1((error) => {
|
|
32379
|
-
this.errorMessage =
|
|
32380
|
-
'An error occurred while searching. Please try again.';
|
|
32381
|
-
console.error(error);
|
|
32382
|
-
return [];
|
|
32383
|
-
}));
|
|
32384
|
-
}), takeUntil(this.destroy$))
|
|
32385
|
-
.subscribe((results) => {
|
|
32386
|
-
this.results = results;
|
|
32387
|
-
});
|
|
32388
|
-
}
|
|
32389
|
-
ngOnDestroy() {
|
|
32390
|
-
this.destroy$.next();
|
|
32391
|
-
this.destroy$.complete();
|
|
32392
|
-
}
|
|
32393
|
-
onSearchChange(searchText) {
|
|
32394
|
-
if (!searchText) {
|
|
32395
|
-
this.clearSearch();
|
|
32396
|
-
return;
|
|
32397
|
-
}
|
|
32398
|
-
else {
|
|
32399
|
-
this.searchTextChanged.next(searchText);
|
|
32400
|
-
}
|
|
32401
|
-
}
|
|
32402
|
-
clearSearch() {
|
|
32403
|
-
this.searchText = '';
|
|
32404
|
-
this.results = [];
|
|
32405
|
-
this.errorMessage = null;
|
|
32406
|
-
}
|
|
32407
|
-
async zoomToLocation(result) {
|
|
32408
|
-
const geometry = result.geom;
|
|
32409
|
-
if (geometry.type === 'Point') {
|
|
32410
|
-
await this.zoomToPoint(geometry.coordinates);
|
|
32411
|
-
}
|
|
32412
|
-
else if (geometry.type === 'Polygon') {
|
|
32413
|
-
await this.zoomToPolygon(geometry.coordinates);
|
|
32414
|
-
}
|
|
32415
|
-
else {
|
|
32416
|
-
console.error(`Unsupported geometry type: ${geometry.type}`);
|
|
32417
|
-
}
|
|
32418
|
-
}
|
|
32419
|
-
async zoomToPoint(pointCoords) {
|
|
32420
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32421
|
-
const view = {
|
|
32422
|
-
center: pointCoords,
|
|
32423
|
-
zoom: 10,
|
|
32424
|
-
};
|
|
32425
|
-
this.mapFacade.applyContext({
|
|
32426
|
-
...context,
|
|
32427
|
-
view,
|
|
32428
|
-
});
|
|
32429
|
-
}
|
|
32430
|
-
async zoomToPolygon(polygonCoords) {
|
|
32431
|
-
const context = await firstValueFrom(this.mapFacade.context$);
|
|
32432
|
-
const view = {
|
|
32433
|
-
geometry: {
|
|
32434
|
-
type: 'Polygon',
|
|
32435
|
-
coordinates: polygonCoords,
|
|
32436
|
-
},
|
|
32437
|
-
};
|
|
32438
|
-
this.mapFacade.applyContext({
|
|
32439
|
-
...context,
|
|
32440
|
-
view,
|
|
32441
|
-
});
|
|
32442
|
-
}
|
|
32443
|
-
onEnterPress() {
|
|
32444
|
-
if (this.results && this.results.length > 0) {
|
|
32445
|
-
this.zoomToLocation(this.results[0]);
|
|
32446
|
-
}
|
|
32447
|
-
}
|
|
32448
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
32449
|
-
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" }] }); }
|
|
32450
|
-
}
|
|
32451
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, decorators: [{
|
|
32452
|
-
type: Component,
|
|
32453
|
-
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" }]
|
|
32454
|
-
}], ctorParameters: () => [] });
|
|
32455
|
-
|
|
32456
32973
|
/*
|
|
32457
32974
|
Metadata actions
|
|
32458
32975
|
*/
|
|
@@ -32468,8 +32985,7 @@ const closeMetadata = createAction('[Metadata view] close');
|
|
|
32468
32985
|
Related actions
|
|
32469
32986
|
*/
|
|
32470
32987
|
const setRelated = createAction('[Metadata view] Set related records', props());
|
|
32471
|
-
const
|
|
32472
|
-
const setSourceOf = createAction('[Metadata view] Set has sources', props());
|
|
32988
|
+
const setLinkedRecords = createAction('[Metadata view] Set associated records', props());
|
|
32473
32989
|
/*
|
|
32474
32990
|
ChartConfig actions
|
|
32475
32991
|
*/
|
|
@@ -32501,9 +33017,8 @@ var mdview_actions = /*#__PURE__*/Object.freeze({
|
|
|
32501
33017
|
loadUserFeedbacksSuccess: loadUserFeedbacksSuccess,
|
|
32502
33018
|
setChartConfig: setChartConfig,
|
|
32503
33019
|
setIncompleteMetadata: setIncompleteMetadata,
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
setSources: setSources
|
|
33020
|
+
setLinkedRecords: setLinkedRecords,
|
|
33021
|
+
setRelated: setRelated
|
|
32507
33022
|
});
|
|
32508
33023
|
|
|
32509
33024
|
const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView';
|
|
@@ -32546,12 +33061,9 @@ on(loadFullMetadata, (state) => ({
|
|
|
32546
33061
|
on(setRelated, (state, { related }) => ({
|
|
32547
33062
|
...state,
|
|
32548
33063
|
related,
|
|
32549
|
-
})), on(
|
|
32550
|
-
...state,
|
|
32551
|
-
sources,
|
|
32552
|
-
})), on(setSourceOf, (state, { sourceOf }) => ({
|
|
33064
|
+
})), on(setLinkedRecords, (state, { linkedRecords }) => ({
|
|
32553
33065
|
...state,
|
|
32554
|
-
|
|
33066
|
+
linkedRecords,
|
|
32555
33067
|
})),
|
|
32556
33068
|
/*
|
|
32557
33069
|
ChartConfig reducers
|
|
@@ -32613,8 +33125,7 @@ const getMetadataError = createSelector(getMdViewState, (state) => state.error);
|
|
|
32613
33125
|
Related selectors
|
|
32614
33126
|
*/
|
|
32615
33127
|
const getRelated = createSelector(getMdViewState, (state) => state.related);
|
|
32616
|
-
const
|
|
32617
|
-
const getSourceOf = createSelector(getMdViewState, (state) => state.sourceOf);
|
|
33128
|
+
const getLinkedRecords = createSelector(getMdViewState, (state) => state.linkedRecords);
|
|
32618
33129
|
/*
|
|
32619
33130
|
Metadata selectors
|
|
32620
33131
|
*/
|
|
@@ -32715,212 +33226,10 @@ function parseHeaders(httpHeaders) {
|
|
|
32715
33226
|
return result;
|
|
32716
33227
|
}
|
|
32717
33228
|
|
|
32718
|
-
|
|
32719
|
-
|
|
32720
|
-
|
|
32721
|
-
? fileExtensionMatches[1].toLowerCase()
|
|
32722
|
-
: null;
|
|
32723
|
-
// 1. type hint
|
|
32724
|
-
if (typeHint)
|
|
32725
|
-
return Promise.resolve(typeHint);
|
|
32726
|
-
// 2. content-type header
|
|
32727
|
-
const headers = await fetchHeaders(url);
|
|
32728
|
-
if ('supportedType' in headers)
|
|
32729
|
-
return headers.supportedType;
|
|
32730
|
-
// 3. file extension from url
|
|
32731
|
-
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
32732
|
-
return fileExtension;
|
|
32733
|
-
// no type inferred or hinted
|
|
32734
|
-
if ('mimeType' in headers)
|
|
32735
|
-
throw FetchError.unsupportedType(headers.mimeType);
|
|
32736
|
-
else
|
|
32737
|
-
throw FetchError.unknownType();
|
|
33229
|
+
const GEOMETRY_COLUMN_ALIAS = '__geometry__';
|
|
33230
|
+
function fieldToSql(name) {
|
|
33231
|
+
return `"${name.replace(/"/g, '""')}"`; // escape double quotes in field names
|
|
32738
33232
|
}
|
|
32739
|
-
function fetchHeaders(url) {
|
|
32740
|
-
return sharedFetch(url, 'HEAD')
|
|
32741
|
-
.catch((error) => {
|
|
32742
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32743
|
-
})
|
|
32744
|
-
.then((response) => {
|
|
32745
|
-
if (!response.ok) {
|
|
32746
|
-
throw FetchError.http(response.status);
|
|
32747
|
-
}
|
|
32748
|
-
return parseHeaders(response.headers);
|
|
32749
|
-
});
|
|
32750
|
-
}
|
|
32751
|
-
function fetchDataAsText(url, cacheActive) {
|
|
32752
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32753
|
-
.catch((error) => {
|
|
32754
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32755
|
-
})
|
|
32756
|
-
.then(async (response) => {
|
|
32757
|
-
if (!response.ok) {
|
|
32758
|
-
const clonedResponse = response.clone();
|
|
32759
|
-
throw FetchError.http(response.status, await clonedResponse.text());
|
|
32760
|
-
}
|
|
32761
|
-
const clonedResponse = response.clone();
|
|
32762
|
-
return clonedResponse.text();
|
|
32763
|
-
});
|
|
32764
|
-
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
32765
|
-
}
|
|
32766
|
-
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
32767
|
-
const fetchFactory = () => sharedFetch(url)
|
|
32768
|
-
.catch((error) => {
|
|
32769
|
-
throw FetchError.corsOrNetwork(error.message);
|
|
32770
|
-
})
|
|
32771
|
-
.then(async (response) => {
|
|
32772
|
-
if (!response.ok) {
|
|
32773
|
-
throw FetchError.http(response.status, await response.text());
|
|
32774
|
-
}
|
|
32775
|
-
// convert to a numeric array so that we can store the response in cache
|
|
32776
|
-
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
32777
|
-
});
|
|
32778
|
-
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
32779
|
-
return new Uint8Array(array).buffer;
|
|
32780
|
-
});
|
|
32781
|
-
}
|
|
32782
|
-
function tryParseDate(input) {
|
|
32783
|
-
if (typeof input !== 'string')
|
|
32784
|
-
return null;
|
|
32785
|
-
function tryIso(value) {
|
|
32786
|
-
const parsed = parseISO(value);
|
|
32787
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32788
|
-
}
|
|
32789
|
-
function tryFormat(value, format) {
|
|
32790
|
-
const parsed = parse$4(value, format, new Date());
|
|
32791
|
-
return isNaN(parsed.getDate()) ? null : parsed;
|
|
32792
|
-
}
|
|
32793
|
-
return (tryIso(input) ||
|
|
32794
|
-
tryFormat(input, 'dd/MM/yyyy') ||
|
|
32795
|
-
tryFormat(input, 'dd.MM.yyyy') ||
|
|
32796
|
-
tryFormat(input, 'MM/dd/yyyy') ||
|
|
32797
|
-
null);
|
|
32798
|
-
}
|
|
32799
|
-
function tryParseNumber(input) {
|
|
32800
|
-
if (isNaN(input))
|
|
32801
|
-
return null;
|
|
32802
|
-
const parsed = parseFloat(input);
|
|
32803
|
-
return isNaN(parsed) ? null : parsed;
|
|
32804
|
-
}
|
|
32805
|
-
function jsonToGeojsonFeature(object) {
|
|
32806
|
-
const { id, properties } = Object.keys(object)
|
|
32807
|
-
.map((property) => (property ? property : 'unknown')) //prevent empty strings
|
|
32808
|
-
.reduce((prev, curr) => curr.toLowerCase().endsWith('id')
|
|
32809
|
-
? {
|
|
32810
|
-
...prev,
|
|
32811
|
-
id: object[curr],
|
|
32812
|
-
}
|
|
32813
|
-
: {
|
|
32814
|
-
...prev,
|
|
32815
|
-
properties: { ...prev.properties, [curr]: object[curr] },
|
|
32816
|
-
}, { id: undefined, properties: {} });
|
|
32817
|
-
return {
|
|
32818
|
-
type: 'Feature',
|
|
32819
|
-
geometry: null,
|
|
32820
|
-
properties,
|
|
32821
|
-
...(id !== undefined && { id }),
|
|
32822
|
-
};
|
|
32823
|
-
}
|
|
32824
|
-
function mutateProperties(items, mutators) {
|
|
32825
|
-
const mutatorKeys = Object.keys(mutators);
|
|
32826
|
-
for (let i = 0, ii = items.length; i < ii; i++) {
|
|
32827
|
-
const item = items[i];
|
|
32828
|
-
for (const mutatorField of mutatorKeys) {
|
|
32829
|
-
if (!(mutatorField in item.properties))
|
|
32830
|
-
continue;
|
|
32831
|
-
item.properties[mutatorField] = mutators[mutatorField](item.properties[mutatorField]);
|
|
32832
|
-
}
|
|
32833
|
-
}
|
|
32834
|
-
return items;
|
|
32835
|
-
}
|
|
32836
|
-
const SAMPLE_SIZE = 20;
|
|
32837
|
-
/**
|
|
32838
|
-
* This will infer field types from a list of data items and cast the values accordingly
|
|
32839
|
-
* @param items
|
|
32840
|
-
* @param inferTypes
|
|
32841
|
-
*/
|
|
32842
|
-
function processItemProperties(items, inferTypes = false) {
|
|
32843
|
-
const foundFields = {};
|
|
32844
|
-
for (let i = 0, ii = Math.min(SAMPLE_SIZE, items.length); i < ii; i++) {
|
|
32845
|
-
const item = items[i];
|
|
32846
|
-
const fields = Object.keys(item.properties);
|
|
32847
|
-
for (const field of fields) {
|
|
32848
|
-
if (!(field in foundFields)) {
|
|
32849
|
-
foundFields[field] = {
|
|
32850
|
-
label: field,
|
|
32851
|
-
name: field,
|
|
32852
|
-
type: null,
|
|
32853
|
-
};
|
|
32854
|
-
}
|
|
32855
|
-
const value = item.properties[field];
|
|
32856
|
-
const info = foundFields[field];
|
|
32857
|
-
if (value === undefined || value === '' || value === null)
|
|
32858
|
-
continue;
|
|
32859
|
-
if (!inferTypes) {
|
|
32860
|
-
if (info.type === null && typeof value === 'number') {
|
|
32861
|
-
info.type = 'number';
|
|
32862
|
-
}
|
|
32863
|
-
else if (info.type === 'number' && typeof value !== 'number') {
|
|
32864
|
-
info.type = 'string';
|
|
32865
|
-
}
|
|
32866
|
-
continue;
|
|
32867
|
-
}
|
|
32868
|
-
const parsedNumber = tryParseNumber(value);
|
|
32869
|
-
if (info.type === null && parsedNumber !== null) {
|
|
32870
|
-
info.type = 'number';
|
|
32871
|
-
continue;
|
|
32872
|
-
}
|
|
32873
|
-
else if (info.type === 'number' && parsedNumber === null) {
|
|
32874
|
-
info.type = 'string';
|
|
32875
|
-
continue;
|
|
32876
|
-
}
|
|
32877
|
-
const parsedDate = tryParseDate(value);
|
|
32878
|
-
if (info.type === null && parsedDate !== null) {
|
|
32879
|
-
info.type = 'date';
|
|
32880
|
-
}
|
|
32881
|
-
else if (info.type === 'date' && parsedDate === null) {
|
|
32882
|
-
info.type = 'string';
|
|
32883
|
-
}
|
|
32884
|
-
}
|
|
32885
|
-
}
|
|
32886
|
-
const properties = [];
|
|
32887
|
-
const mutators = {};
|
|
32888
|
-
for (const field in foundFields) {
|
|
32889
|
-
const info = foundFields[field];
|
|
32890
|
-
if (info.type === 'number') {
|
|
32891
|
-
mutators[field] = tryParseNumber;
|
|
32892
|
-
}
|
|
32893
|
-
else if (info.type === 'date') {
|
|
32894
|
-
mutators[field] = tryParseDate;
|
|
32895
|
-
}
|
|
32896
|
-
properties.push({ ...info, type: info.type || 'string' });
|
|
32897
|
-
}
|
|
32898
|
-
if (inferTypes) {
|
|
32899
|
-
mutateProperties(items, mutators);
|
|
32900
|
-
}
|
|
32901
|
-
return { items, properties };
|
|
32902
|
-
}
|
|
32903
|
-
/**
|
|
32904
|
-
* This creates a Proxy that allows reading and writing to the data item properties
|
|
32905
|
-
* as if it was a simple array of JSON objects
|
|
32906
|
-
* @param items
|
|
32907
|
-
*/
|
|
32908
|
-
function getJsonDataItemsProxy(items) {
|
|
32909
|
-
return new Proxy(items, {
|
|
32910
|
-
get(target, p) {
|
|
32911
|
-
if (typeof p === 'string' &&
|
|
32912
|
-
!Number.isNaN(parseInt(p)) &&
|
|
32913
|
-
target[p]?.properties) {
|
|
32914
|
-
return target[p].properties;
|
|
32915
|
-
}
|
|
32916
|
-
return target[p];
|
|
32917
|
-
},
|
|
32918
|
-
set() {
|
|
32919
|
-
throw new Error('This object is read-only');
|
|
32920
|
-
},
|
|
32921
|
-
});
|
|
32922
|
-
}
|
|
32923
|
-
|
|
32924
33233
|
function filterToSql(filter) {
|
|
32925
33234
|
const operator = filter[0];
|
|
32926
33235
|
const args = filter.slice(1);
|
|
@@ -32935,10 +33244,10 @@ function filterToSql(filter) {
|
|
|
32935
33244
|
case '=':
|
|
32936
33245
|
case '!=':
|
|
32937
33246
|
case 'like':
|
|
32938
|
-
return
|
|
33247
|
+
return `${fieldToSql(args[0])} ${operator.toUpperCase()} ${valueToSql(args[1])}`;
|
|
32939
33248
|
case 'in': {
|
|
32940
33249
|
const values = args.slice(1);
|
|
32941
|
-
return
|
|
33250
|
+
return `${fieldToSql(args[0])} IN (${values.map(valueToSql).join(', ')})`;
|
|
32942
33251
|
}
|
|
32943
33252
|
case 'and':
|
|
32944
33253
|
case 'or': {
|
|
@@ -32957,17 +33266,18 @@ function aggregationToSql(aggregation) {
|
|
|
32957
33266
|
const field = aggregation[1];
|
|
32958
33267
|
switch (operation) {
|
|
32959
33268
|
case 'average':
|
|
32960
|
-
return `AVG(
|
|
33269
|
+
return `CAST(AVG(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`average(${field})`)}`;
|
|
32961
33270
|
case 'sum':
|
|
32962
33271
|
case 'max':
|
|
32963
33272
|
case 'min':
|
|
32964
|
-
return
|
|
33273
|
+
return `CAST(${operation.toUpperCase()}(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`${operation}(${field})`)}`;
|
|
32965
33274
|
case 'count':
|
|
32966
|
-
return 'COUNT(*) as
|
|
33275
|
+
return 'CAST(COUNT(*) AS INTEGER) as "count()"'; // we don't need Bigint precision here
|
|
32967
33276
|
}
|
|
32968
33277
|
}
|
|
32969
33278
|
/**
|
|
32970
33279
|
* Leave arguments at null if not used
|
|
33280
|
+
* @param tableName
|
|
32971
33281
|
* @param selected
|
|
32972
33282
|
* @param filter
|
|
32973
33283
|
* @param sort
|
|
@@ -32976,22 +33286,25 @@ function aggregationToSql(aggregation) {
|
|
|
32976
33286
|
* @param groupBy
|
|
32977
33287
|
* @param aggregations
|
|
32978
33288
|
*/
|
|
32979
|
-
function generateSqlQuery(selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null) {
|
|
33289
|
+
function generateSqlQuery(tableName, selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null, geometryColumn = null) {
|
|
32980
33290
|
let sqlSelect = 'SELECT *';
|
|
32981
|
-
const sqlFrom =
|
|
33291
|
+
const sqlFrom = ` FROM ${tableName}`;
|
|
32982
33292
|
let sqlOrderBy = '';
|
|
32983
33293
|
let sqlWhere = '';
|
|
32984
33294
|
let sqlLimit = '';
|
|
32985
33295
|
let sqlGroupBy = '';
|
|
32986
33296
|
if (selected !== null) {
|
|
32987
|
-
sqlSelect = `SELECT ${selected.map(
|
|
33297
|
+
sqlSelect = `SELECT ${selected.map(fieldToSql).join(', ')}`;
|
|
33298
|
+
}
|
|
33299
|
+
if (geometryColumn !== null) {
|
|
33300
|
+
sqlSelect += `, ST_AsGeoJSON(${fieldToSql(geometryColumn)}) as ${GEOMETRY_COLUMN_ALIAS}`;
|
|
32988
33301
|
}
|
|
32989
33302
|
if (filter !== null) {
|
|
32990
33303
|
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
32991
33304
|
}
|
|
32992
33305
|
if (sort?.length) {
|
|
32993
33306
|
sqlOrderBy = ` ORDER BY ${sort
|
|
32994
|
-
.map((sort) =>
|
|
33307
|
+
.map((sort) => `${fieldToSql(sort[1])} ${sort[0].toUpperCase()}`)
|
|
32995
33308
|
.join(', ')}`;
|
|
32996
33309
|
}
|
|
32997
33310
|
if (startIndex !== null && count !== null) {
|
|
@@ -33001,17 +33314,212 @@ function generateSqlQuery(selected = null, filter = null, sort = null, startInde
|
|
|
33001
33314
|
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33002
33315
|
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33003
33316
|
const sqlGroupByFields = groupedByDistinct
|
|
33004
|
-
.map((group) =>
|
|
33317
|
+
.map((group) => fieldToSql(group[1]))
|
|
33005
33318
|
.join(', ');
|
|
33006
33319
|
const sqlGroupBySelect = groupedByDistinct
|
|
33007
|
-
.map((group) =>
|
|
33320
|
+
.map((group) => `${fieldToSql(group[1])} as ${fieldToSql(`distinct(${group[1]})`)}`)
|
|
33008
33321
|
.join(', ');
|
|
33009
33322
|
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33010
33323
|
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33011
33324
|
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33012
33325
|
}
|
|
33013
33326
|
}
|
|
33014
|
-
return sqlSelect + sqlFrom + sqlGroupBy +
|
|
33327
|
+
return sqlSelect + sqlFrom + sqlGroupBy + sqlWhere + sqlOrderBy + sqlLimit;
|
|
33328
|
+
}
|
|
33329
|
+
|
|
33330
|
+
function arrowTableToDataItems(table) {
|
|
33331
|
+
const fields = table.schema.fields;
|
|
33332
|
+
return table.toArray().map((row) => {
|
|
33333
|
+
const rowJson = row.toJSON();
|
|
33334
|
+
const feature = {
|
|
33335
|
+
type: 'Feature',
|
|
33336
|
+
geometry: null,
|
|
33337
|
+
properties: {},
|
|
33338
|
+
};
|
|
33339
|
+
const keys = Object.keys(rowJson);
|
|
33340
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33341
|
+
const key = keys[i];
|
|
33342
|
+
const dataType = fields[i].type;
|
|
33343
|
+
let value = rowJson[key];
|
|
33344
|
+
// this might happen if we get an array inside a field
|
|
33345
|
+
if (value instanceof Vector) {
|
|
33346
|
+
value = Array.from(value);
|
|
33347
|
+
}
|
|
33348
|
+
// cast bigints to ints
|
|
33349
|
+
if (typeof value === 'bigint') {
|
|
33350
|
+
value = Number(value);
|
|
33351
|
+
}
|
|
33352
|
+
// rename columns with empty name
|
|
33353
|
+
if (!key) {
|
|
33354
|
+
feature.properties['unknown'] = value;
|
|
33355
|
+
continue;
|
|
33356
|
+
}
|
|
33357
|
+
// assign properties that look like an id to the geojson `id` field
|
|
33358
|
+
if (/^(object|feature)?_?id$/.test(key.toLowerCase()) &&
|
|
33359
|
+
(typeof value == 'string' || typeof value === 'number')) {
|
|
33360
|
+
feature.id = value;
|
|
33361
|
+
}
|
|
33362
|
+
// if a date is in timestamp (number) format, convert it to native
|
|
33363
|
+
if (typeof value === 'number' &&
|
|
33364
|
+
(DataType.isTimestamp(dataType) || DataType.isDate(dataType))) {
|
|
33365
|
+
value = new Date(value);
|
|
33366
|
+
}
|
|
33367
|
+
// if a binary field (most likely a geometry column): skip
|
|
33368
|
+
if (DataType.isBinary(dataType)) {
|
|
33369
|
+
continue;
|
|
33370
|
+
}
|
|
33371
|
+
// geometry column
|
|
33372
|
+
if (key === GEOMETRY_COLUMN_ALIAS && DataType.isUtf8(dataType)) {
|
|
33373
|
+
feature.geometry = JSON.parse(value);
|
|
33374
|
+
continue;
|
|
33375
|
+
}
|
|
33376
|
+
feature.properties[key] = value;
|
|
33377
|
+
}
|
|
33378
|
+
return feature;
|
|
33379
|
+
});
|
|
33380
|
+
}
|
|
33381
|
+
|
|
33382
|
+
// init code taken from https://github.com/duckdb/duckdb-wasm/blob/main/packages/duckdb-wasm/README.md
|
|
33383
|
+
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
|
33384
|
+
// from https://duckdb.org/docs/current/sql/data_types/overview
|
|
33385
|
+
const typesMapping = {
|
|
33386
|
+
INTEGER: 'number',
|
|
33387
|
+
SMALLINT: 'number',
|
|
33388
|
+
TINYINT: 'number',
|
|
33389
|
+
BIGINT: 'number',
|
|
33390
|
+
HUGEINT: 'number',
|
|
33391
|
+
UINTEGER: 'number',
|
|
33392
|
+
USMALLINT: 'number',
|
|
33393
|
+
UTINYINT: 'number',
|
|
33394
|
+
UBIGINT: 'number',
|
|
33395
|
+
UHUGEINT: 'number',
|
|
33396
|
+
DOUBLE: 'number',
|
|
33397
|
+
BIGNUM: 'number',
|
|
33398
|
+
DECIMAL: 'number',
|
|
33399
|
+
NUMERIC: 'number',
|
|
33400
|
+
FLOAT: 'number',
|
|
33401
|
+
REAL: 'number',
|
|
33402
|
+
'TIMESTAMP WITH TIME ZONE': 'date',
|
|
33403
|
+
TIMESTAMP: 'date',
|
|
33404
|
+
DATE: 'date',
|
|
33405
|
+
CHAR: 'string',
|
|
33406
|
+
VARCHAR: 'string',
|
|
33407
|
+
TEXT: 'string',
|
|
33408
|
+
UUID: 'string',
|
|
33409
|
+
BLOB: 'string',
|
|
33410
|
+
BIT: 'string',
|
|
33411
|
+
INTERVAL: 'string',
|
|
33412
|
+
LIST: 'string',
|
|
33413
|
+
BOOLEAN: 'boolean',
|
|
33414
|
+
};
|
|
33415
|
+
class Engine {
|
|
33416
|
+
async makeInit() {
|
|
33417
|
+
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
|
|
33418
|
+
let worker_url = bundle.mainWorker;
|
|
33419
|
+
// this is necessary to let browsers execute WASM code coming from a cross-origin host
|
|
33420
|
+
if (worker_url.startsWith('https://')) {
|
|
33421
|
+
worker_url = URL.createObjectURL(new Blob([`importScripts("${worker_url}");`], {
|
|
33422
|
+
type: 'text/javascript',
|
|
33423
|
+
}));
|
|
33424
|
+
}
|
|
33425
|
+
const worker = new Worker(worker_url);
|
|
33426
|
+
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
|
|
33427
|
+
this.db = new duckdb.AsyncDuckDB(logger, worker);
|
|
33428
|
+
await this.db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
33429
|
+
// setup duckdb options
|
|
33430
|
+
const conn = await this.db.connect();
|
|
33431
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33432
|
+
await conn.query(`INSTALL spatial; LOAD spatial;`);
|
|
33433
|
+
await conn.query(`SET TimeZone = '${timezone}';`);
|
|
33434
|
+
await conn.query(`SET threads = 1;`);
|
|
33435
|
+
// await conn.query(`SET memory_limit = '2GB';`) // used for experimenting when we encounter memory issues
|
|
33436
|
+
await conn.query(`SET preserve_insertion_order = false;`); // this reduces memory usage when loading a dataset
|
|
33437
|
+
conn.close();
|
|
33438
|
+
return this;
|
|
33439
|
+
}
|
|
33440
|
+
isReady() {
|
|
33441
|
+
if (!this.init_) {
|
|
33442
|
+
this.init_ = this.makeInit();
|
|
33443
|
+
}
|
|
33444
|
+
return this.init_;
|
|
33445
|
+
}
|
|
33446
|
+
/**
|
|
33447
|
+
* Returns information about a dataset once it's loaded:
|
|
33448
|
+
* - a list of properties description
|
|
33449
|
+
* - the name of the dataset geometry column (null if no geometry present)
|
|
33450
|
+
* @param datasetId name of the table under which the dataset will be stored
|
|
33451
|
+
* @param loadQuery duckdb-specific query for creating a table out of the data
|
|
33452
|
+
* @param forceReload if true, any existing data will be dropped and redownloaded
|
|
33453
|
+
*/
|
|
33454
|
+
async loadFile(datasetId, loadQuery, forceReload = false) {
|
|
33455
|
+
const conn = await this.db.connect();
|
|
33456
|
+
let results;
|
|
33457
|
+
// either we want to recreate the table, or we keep it if it already exists
|
|
33458
|
+
const safeLoadQuery = forceReload
|
|
33459
|
+
? `DROP TABLE IF EXISTS ${datasetId};
|
|
33460
|
+
${loadQuery}`
|
|
33461
|
+
: loadQuery.replace(/CREATE TABLE(?! IF NOT EXISTS)/gi, 'CREATE TABLE IF NOT EXISTS');
|
|
33462
|
+
// create the table
|
|
33463
|
+
try {
|
|
33464
|
+
results = await conn.query(safeLoadQuery);
|
|
33465
|
+
}
|
|
33466
|
+
catch (e) {
|
|
33467
|
+
throw new FetchError('parse', `DuckDB encountered an error when loading the data: ${e.message}`);
|
|
33468
|
+
}
|
|
33469
|
+
// read rows count
|
|
33470
|
+
results = await conn.query(`SELECT count(*) FROM ${datasetId}`);
|
|
33471
|
+
const { 'count_star()': recordsCount } = results.toArray()[0].toJSON();
|
|
33472
|
+
// read columns
|
|
33473
|
+
results = await conn.query(`SELECT * FROM information_schema.columns WHERE table_name = '${datasetId}';`);
|
|
33474
|
+
let geometryColumn = null;
|
|
33475
|
+
const properties = results
|
|
33476
|
+
.toArray()
|
|
33477
|
+
.map((row) => {
|
|
33478
|
+
const rowObj = row.toJSON();
|
|
33479
|
+
if (rowObj['data_type'] === 'GEOMETRY') {
|
|
33480
|
+
// the geometry is not part of the properties
|
|
33481
|
+
// note: right now we only keep one geometry column name, but if there are multiple they will
|
|
33482
|
+
// all get discarded
|
|
33483
|
+
geometryColumn = rowObj['column_name'];
|
|
33484
|
+
return null;
|
|
33485
|
+
}
|
|
33486
|
+
return {
|
|
33487
|
+
name: rowObj['column_name'],
|
|
33488
|
+
label: rowObj['column_name'],
|
|
33489
|
+
type: typesMapping[rowObj['data_type']] ?? 'other',
|
|
33490
|
+
};
|
|
33491
|
+
})
|
|
33492
|
+
.filter((prop) => prop !== null);
|
|
33493
|
+
conn.close();
|
|
33494
|
+
return {
|
|
33495
|
+
properties,
|
|
33496
|
+
geometryColumn,
|
|
33497
|
+
rowsCount: Number(recordsCount),
|
|
33498
|
+
};
|
|
33499
|
+
}
|
|
33500
|
+
// register a Uint8 buffer using a handle in the duckdb instance
|
|
33501
|
+
async registerData(name, buffer) {
|
|
33502
|
+
return this.db.registerFileBuffer(name, buffer);
|
|
33503
|
+
}
|
|
33504
|
+
/**
|
|
33505
|
+
* @param query duckdb-specific query for fetching items
|
|
33506
|
+
*/
|
|
33507
|
+
async queryItems(query) {
|
|
33508
|
+
const conn = await this.db.connect();
|
|
33509
|
+
const results = await conn.query(query);
|
|
33510
|
+
conn.close();
|
|
33511
|
+
return arrowTableToDataItems(results);
|
|
33512
|
+
}
|
|
33513
|
+
close() {
|
|
33514
|
+
this.db?.terminate();
|
|
33515
|
+
}
|
|
33516
|
+
}
|
|
33517
|
+
let engine = null;
|
|
33518
|
+
async function getEngine() {
|
|
33519
|
+
if (!engine) {
|
|
33520
|
+
engine = new Engine();
|
|
33521
|
+
}
|
|
33522
|
+
return engine.isReady();
|
|
33015
33523
|
}
|
|
33016
33524
|
|
|
33017
33525
|
class BaseReader {
|
|
@@ -33024,10 +33532,18 @@ class BaseReader {
|
|
|
33024
33532
|
this.sort = null;
|
|
33025
33533
|
this.startIndex = null;
|
|
33026
33534
|
this.count = null;
|
|
33535
|
+
this.loadPromise_ = Promise.resolve();
|
|
33536
|
+
this.cacheEnabled = false;
|
|
33537
|
+
}
|
|
33538
|
+
enableCache(enabled) {
|
|
33539
|
+
this.cacheEnabled = enabled;
|
|
33027
33540
|
}
|
|
33028
33541
|
load() {
|
|
33029
33542
|
throw new Error('not implemented');
|
|
33030
33543
|
}
|
|
33544
|
+
get isLoaded() {
|
|
33545
|
+
return this.loadPromise_;
|
|
33546
|
+
}
|
|
33031
33547
|
get properties() {
|
|
33032
33548
|
throw new Error('not implemented');
|
|
33033
33549
|
}
|
|
@@ -33076,178 +33592,237 @@ class BaseReader {
|
|
|
33076
33592
|
}
|
|
33077
33593
|
}
|
|
33078
33594
|
|
|
33079
|
-
|
|
33080
|
-
|
|
33081
|
-
|
|
33082
|
-
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33595
|
+
/**
|
|
33596
|
+
* This reader handles file formats supported natively by DuckDB
|
|
33597
|
+
*/
|
|
33598
|
+
class BaseFileReader extends BaseReader {
|
|
33599
|
+
// a table id should not exceed 63 chars
|
|
33600
|
+
generateDatasetId() {
|
|
33601
|
+
// generate a hash out of the url
|
|
33602
|
+
let hash = 0;
|
|
33603
|
+
for (const char of this.url) {
|
|
33604
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
33605
|
+
hash = hash >>> 0; // make it unsigned
|
|
33606
|
+
}
|
|
33607
|
+
return `datafetcher_${hash.toString(16)}`;
|
|
33608
|
+
}
|
|
33609
|
+
async getLoadQuery() {
|
|
33092
33610
|
throw new Error('not implemented');
|
|
33093
33611
|
}
|
|
33094
|
-
load() {
|
|
33095
|
-
this.
|
|
33612
|
+
async load() {
|
|
33613
|
+
this.datasetId = this.generateDatasetId();
|
|
33614
|
+
this.loadPromise_ = getEngine()
|
|
33615
|
+
.then((engine) => {
|
|
33616
|
+
this.engine = engine;
|
|
33617
|
+
return this.getLoadQuery();
|
|
33618
|
+
})
|
|
33619
|
+
.then((loadQuery) => this.engine.loadFile(this.datasetId, loadQuery, !this.cacheEnabled))
|
|
33620
|
+
.then((datasetInfo) => {
|
|
33621
|
+
this.properties_ = datasetInfo.properties;
|
|
33622
|
+
this.geometryColumn = datasetInfo.geometryColumn;
|
|
33623
|
+
this.rowsCount = datasetInfo.rowsCount;
|
|
33624
|
+
// returns void for the loaded promise
|
|
33625
|
+
});
|
|
33096
33626
|
}
|
|
33097
33627
|
get properties() {
|
|
33098
|
-
return this.
|
|
33628
|
+
return this.isLoaded.then(() => this.properties_);
|
|
33099
33629
|
}
|
|
33100
33630
|
get info() {
|
|
33101
|
-
return this.
|
|
33102
|
-
itemsCount:
|
|
33631
|
+
return this.isLoaded.then(() => ({
|
|
33632
|
+
itemsCount: this.rowsCount,
|
|
33633
|
+
hasGeometry: !!this.geometryColumn,
|
|
33103
33634
|
}));
|
|
33104
33635
|
}
|
|
33105
33636
|
async read() {
|
|
33106
|
-
|
|
33107
|
-
//
|
|
33108
|
-
|
|
33109
|
-
|
|
33110
|
-
|
|
33111
|
-
this.sort == null &&
|
|
33112
|
-
this.filter == null &&
|
|
33113
|
-
this.startIndex == null &&
|
|
33114
|
-
this.count == null) {
|
|
33115
|
-
return items;
|
|
33116
|
-
}
|
|
33117
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33118
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33119
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33120
|
-
return result.map(jsonToGeojsonFeature);
|
|
33121
|
-
}
|
|
33122
|
-
}
|
|
33123
|
-
|
|
33124
|
-
function parseCsv(text) {
|
|
33125
|
-
// first parse the header to guess the delimiter
|
|
33126
|
-
// note that we do that to not rely on Papaparse logic for guessing delimiter
|
|
33127
|
-
let delimiter;
|
|
33128
|
-
try {
|
|
33129
|
-
const header = text.split('\n')[0];
|
|
33130
|
-
const result = Papa.parse(header, {
|
|
33131
|
-
header: false,
|
|
33132
|
-
});
|
|
33133
|
-
delimiter = result.meta.delimiter;
|
|
33134
|
-
}
|
|
33135
|
-
catch (e) {
|
|
33136
|
-
throw new Error('CSV parsing failed: the delimiter could not be guessed');
|
|
33137
|
-
}
|
|
33138
|
-
const parsed = Papa.parse(text, {
|
|
33139
|
-
header: true,
|
|
33140
|
-
skipEmptyLines: true,
|
|
33141
|
-
delimiter,
|
|
33142
|
-
});
|
|
33143
|
-
if (parsed.errors.length) {
|
|
33144
|
-
throw new Error('CSV parsing failed for the following reasons:\n' +
|
|
33145
|
-
parsed.errors
|
|
33146
|
-
.map((error) => `* ${error.message} at row ${error.row}, column ${error.index}`)
|
|
33147
|
-
.join('\n'));
|
|
33637
|
+
await this.isLoaded;
|
|
33638
|
+
// if only certain fields are selected, omit the geometry
|
|
33639
|
+
const geometryColumn = this.selected === null ? this.geometryColumn : null;
|
|
33640
|
+
const query = generateSqlQuery(this.datasetId, this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations, geometryColumn);
|
|
33641
|
+
return this.engine.queryItems(query);
|
|
33148
33642
|
}
|
|
33149
|
-
const items = parsed.data.map(jsonToGeojsonFeature);
|
|
33150
|
-
return processItemProperties(items, true);
|
|
33151
33643
|
}
|
|
33644
|
+
|
|
33152
33645
|
class CsvReader extends BaseFileReader {
|
|
33153
|
-
|
|
33154
|
-
|
|
33646
|
+
async getLoadQuery() {
|
|
33647
|
+
// first we get a list of columns hich have a detected type of VARCHAR
|
|
33648
|
+
// 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
|
|
33649
|
+
return `
|
|
33650
|
+
SET VARIABLE strColumns = (SELECT list(name) FROM (SELECT unnest(Columns, recursive := true) FROM sniff_csv("${this.url}")) WHERE type = 'VARCHAR');
|
|
33651
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_csv("${this.url}",
|
|
33652
|
+
force_not_null = getvariable('strColumns'),
|
|
33653
|
+
auto_type_candidates = ['NULL', 'BOOLEAN', 'INTEGER', 'DOUBLE', 'DATE', 'VARCHAR']
|
|
33654
|
+
);`;
|
|
33155
33655
|
}
|
|
33156
33656
|
}
|
|
33157
33657
|
|
|
33158
|
-
/**
|
|
33159
|
-
* This parser only supports arrays of simple flat objects with properties
|
|
33160
|
-
* @param text
|
|
33161
|
-
*/
|
|
33162
|
-
function parseJson(text) {
|
|
33163
|
-
const parsed = JSON.parse(text);
|
|
33164
|
-
if (!Array.isArray(parsed)) {
|
|
33165
|
-
throw new Error('Could not parse JSON, expected an array at root level');
|
|
33166
|
-
}
|
|
33167
|
-
return processItemProperties(parsed.map(jsonToGeojsonFeature));
|
|
33168
|
-
}
|
|
33169
33658
|
class JsonReader extends BaseFileReader {
|
|
33170
|
-
|
|
33171
|
-
return
|
|
33659
|
+
async getLoadQuery() {
|
|
33660
|
+
return `
|
|
33661
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_json("${this.url}",
|
|
33662
|
+
maximum_object_size = 536870912 -- 500MB
|
|
33663
|
+
);`;
|
|
33172
33664
|
}
|
|
33173
33665
|
}
|
|
33174
33666
|
|
|
33175
|
-
/**
|
|
33176
|
-
* This parser supports both Geojson Feature collections or arrays
|
|
33177
|
-
* of Features
|
|
33178
|
-
* @param text
|
|
33179
|
-
*/
|
|
33180
|
-
function parseGeojson(text) {
|
|
33181
|
-
const parsed = JSON.parse(text);
|
|
33182
|
-
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33183
|
-
if (!Array.isArray(features)) {
|
|
33184
|
-
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33185
|
-
}
|
|
33186
|
-
return processItemProperties(features);
|
|
33187
|
-
}
|
|
33188
33667
|
class GeojsonReader extends BaseFileReader {
|
|
33189
|
-
|
|
33190
|
-
return
|
|
33668
|
+
async getLoadQuery() {
|
|
33669
|
+
return `
|
|
33670
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33671
|
+
allowed_drivers = ['GeoJSON']
|
|
33672
|
+
);`;
|
|
33191
33673
|
}
|
|
33192
33674
|
}
|
|
33193
33675
|
|
|
33676
|
+
async function inferDatasetType(url, typeHint) {
|
|
33677
|
+
const fileExtensionMatches = new URL(url, typeof window !== 'undefined' ? window.location.toString() : undefined).pathname.match(/\.(.+)$/);
|
|
33678
|
+
const fileExtension = fileExtensionMatches && fileExtensionMatches.length
|
|
33679
|
+
? fileExtensionMatches[1].toLowerCase()
|
|
33680
|
+
: null;
|
|
33681
|
+
// 1. type hint
|
|
33682
|
+
if (typeHint)
|
|
33683
|
+
return Promise.resolve(typeHint);
|
|
33684
|
+
// 2. content-type header
|
|
33685
|
+
const headers = await fetchHeaders(url);
|
|
33686
|
+
if ('supportedType' in headers)
|
|
33687
|
+
return headers.supportedType;
|
|
33688
|
+
// 3. file extension from url
|
|
33689
|
+
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
33690
|
+
return fileExtension;
|
|
33691
|
+
// no type inferred or hinted
|
|
33692
|
+
if ('mimeType' in headers)
|
|
33693
|
+
throw FetchError.unsupportedType(headers.mimeType);
|
|
33694
|
+
else
|
|
33695
|
+
throw FetchError.unknownType();
|
|
33696
|
+
}
|
|
33697
|
+
function fetchHeaders(url) {
|
|
33698
|
+
return sharedFetch(url, 'HEAD')
|
|
33699
|
+
.catch((error) => {
|
|
33700
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33701
|
+
})
|
|
33702
|
+
.then((response) => {
|
|
33703
|
+
if (!response.ok) {
|
|
33704
|
+
throw FetchError.http(response.status);
|
|
33705
|
+
}
|
|
33706
|
+
return parseHeaders(response.headers);
|
|
33707
|
+
});
|
|
33708
|
+
}
|
|
33709
|
+
function fetchDataAsText(url, cacheActive) {
|
|
33710
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33711
|
+
.catch((error) => {
|
|
33712
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33713
|
+
})
|
|
33714
|
+
.then(async (response) => {
|
|
33715
|
+
if (!response.ok) {
|
|
33716
|
+
const clonedResponse = response.clone();
|
|
33717
|
+
throw FetchError.http(response.status, await clonedResponse.text());
|
|
33718
|
+
}
|
|
33719
|
+
const clonedResponse = response.clone();
|
|
33720
|
+
return clonedResponse.text();
|
|
33721
|
+
});
|
|
33722
|
+
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
33723
|
+
}
|
|
33724
|
+
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
33725
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33726
|
+
.catch((error) => {
|
|
33727
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33728
|
+
})
|
|
33729
|
+
.then(async (response) => {
|
|
33730
|
+
if (!response.ok) {
|
|
33731
|
+
throw FetchError.http(response.status, await response.text());
|
|
33732
|
+
}
|
|
33733
|
+
// convert to a numeric array so that we can store the response in cache
|
|
33734
|
+
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
33735
|
+
});
|
|
33736
|
+
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
33737
|
+
return new Uint8Array(array).buffer;
|
|
33738
|
+
});
|
|
33739
|
+
}
|
|
33194
33740
|
/**
|
|
33195
|
-
* This
|
|
33196
|
-
*
|
|
33197
|
-
* @param
|
|
33741
|
+
* This creates a Proxy that allows reading and writing to the data item properties
|
|
33742
|
+
* as if it was a simple array of JSON objects
|
|
33743
|
+
* @param items
|
|
33198
33744
|
*/
|
|
33199
|
-
function
|
|
33200
|
-
return
|
|
33201
|
-
|
|
33202
|
-
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
|
|
33207
|
-
|
|
33745
|
+
function getJsonDataItemsProxy(items) {
|
|
33746
|
+
return new Proxy(items, {
|
|
33747
|
+
get(target, p) {
|
|
33748
|
+
if (typeof p === 'string' &&
|
|
33749
|
+
!Number.isNaN(parseInt(p)) &&
|
|
33750
|
+
target[p]?.properties) {
|
|
33751
|
+
return target[p].properties;
|
|
33752
|
+
}
|
|
33753
|
+
return target[p];
|
|
33754
|
+
},
|
|
33755
|
+
set() {
|
|
33756
|
+
throw new Error('This object is read-only');
|
|
33757
|
+
},
|
|
33208
33758
|
});
|
|
33209
33759
|
}
|
|
33760
|
+
|
|
33210
33761
|
class ExcelReader extends BaseFileReader {
|
|
33211
|
-
|
|
33212
|
-
|
|
33762
|
+
async getLoadQuery() {
|
|
33763
|
+
// we download the file as an array buffer first, in order to be able to check if it's an XLS file
|
|
33764
|
+
let buffer = await fetchDataAsArrayBuffer(this.url, this.cacheEnabled);
|
|
33765
|
+
const bufferHandle = `B${this.datasetId}`;
|
|
33766
|
+
// checking against the magic number at the beginning of XLS files, see https://en.wikipedia.org/wiki/List_of_file_signatures
|
|
33767
|
+
const magicNumber = new Uint8Array(buffer, 0, 8); // first 8 bytes
|
|
33768
|
+
const isXls = Array.from(magicNumber)
|
|
33769
|
+
.map((n) => n.toString(16).toUpperCase())
|
|
33770
|
+
.join(' ') === 'D0 CF 11 E0 A1 B1 1A E1';
|
|
33771
|
+
// uh oh, this is an XLS file (not supported by duckdb); convert it to CSV using the xlsx package
|
|
33772
|
+
if (isXls) {
|
|
33773
|
+
buffer = await import('xlsx').then(({ read, utils }) => {
|
|
33774
|
+
const workbook = read(buffer);
|
|
33775
|
+
const json = utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
|
|
33776
|
+
return new TextEncoder().encode(JSON.stringify(json)).buffer;
|
|
33777
|
+
});
|
|
33778
|
+
}
|
|
33779
|
+
const duckDbFn = isXls ? 'read_json' : 'read_xlsx';
|
|
33780
|
+
await this.engine.registerData(bufferHandle, new Uint8Array(buffer));
|
|
33781
|
+
return `
|
|
33782
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM ${duckDbFn}("${bufferHandle}", ignore_errors = true);`;
|
|
33213
33783
|
}
|
|
33214
33784
|
}
|
|
33215
33785
|
|
|
33216
|
-
|
|
33217
|
-
|
|
33218
|
-
|
|
33786
|
+
class GmlReader extends BaseFileReader {
|
|
33787
|
+
async getLoadQuery() {
|
|
33788
|
+
return `
|
|
33789
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33790
|
+
allowed_drivers = ['GML']
|
|
33791
|
+
);`;
|
|
33792
|
+
}
|
|
33793
|
+
}
|
|
33794
|
+
|
|
33795
|
+
const formatGeojson = new GeoJSON$1();
|
|
33796
|
+
function parseGeojson(text) {
|
|
33797
|
+
const parsed = JSON.parse(text);
|
|
33798
|
+
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33799
|
+
if (!Array.isArray(features)) {
|
|
33800
|
+
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33801
|
+
}
|
|
33802
|
+
return features;
|
|
33803
|
+
}
|
|
33804
|
+
function parseGml(text, featureType, version) {
|
|
33805
|
+
const parts = featureType.split(':');
|
|
33806
|
+
const regex = new RegExp(`xmlns:${parts[0]}=["']([^'"]*)["']`);
|
|
33219
33807
|
const match = regex.exec(text);
|
|
33220
33808
|
if (match && match.length >= 2) {
|
|
33221
|
-
const
|
|
33809
|
+
const wfs = new WFS({
|
|
33222
33810
|
featureNS: match[1],
|
|
33223
|
-
featureType:
|
|
33811
|
+
featureType: parts[1],
|
|
33224
33812
|
version: version,
|
|
33225
33813
|
});
|
|
33226
33814
|
let features;
|
|
33227
33815
|
try {
|
|
33228
|
-
features =
|
|
33816
|
+
features = wfs.readFeatures(text);
|
|
33229
33817
|
}
|
|
33230
33818
|
catch (e) {
|
|
33231
|
-
throw Error(
|
|
33819
|
+
throw Error(`Couldn't parse WFS with GML features: ${e.message}`);
|
|
33232
33820
|
}
|
|
33233
|
-
const geojsonItem =
|
|
33234
|
-
return
|
|
33821
|
+
const geojsonItem = formatGeojson.writeFeaturesObject(features);
|
|
33822
|
+
return geojsonItem.features;
|
|
33235
33823
|
}
|
|
33236
33824
|
throw Error("Couldn't retrieve namespace url");
|
|
33237
33825
|
}
|
|
33238
|
-
class GmlReader extends BaseFileReader {
|
|
33239
|
-
constructor(url, namespace, version, cacheActive = true) {
|
|
33240
|
-
super(url);
|
|
33241
|
-
this.url = url;
|
|
33242
|
-
this.namespace = namespace;
|
|
33243
|
-
this.version = version;
|
|
33244
|
-
this.cacheActive = cacheActive;
|
|
33245
|
-
}
|
|
33246
|
-
getData() {
|
|
33247
|
-
return fetchDataAsText(this.url, this.cacheActive).then((text) => parseGml(text, this.namespace, this.version));
|
|
33248
|
-
}
|
|
33249
|
-
}
|
|
33250
|
-
|
|
33251
33826
|
async function getWfsEndpoint(wfsUrl) {
|
|
33252
33827
|
try {
|
|
33253
33828
|
return await new WfsEndpoint(wfsUrl).isReady();
|
|
@@ -33275,21 +33850,65 @@ async function getWfsEndpoint(wfsUrl) {
|
|
|
33275
33850
|
}
|
|
33276
33851
|
}
|
|
33277
33852
|
}
|
|
33278
|
-
class WfsReader extends
|
|
33279
|
-
constructor(url,
|
|
33280
|
-
super(url
|
|
33281
|
-
this.endpoint =
|
|
33282
|
-
this.
|
|
33283
|
-
|
|
33853
|
+
class WfsReader extends BaseReader {
|
|
33854
|
+
constructor(url, featureTypeName) {
|
|
33855
|
+
super(url);
|
|
33856
|
+
this.endpoint = getWfsEndpoint(url);
|
|
33857
|
+
this.featureType = this.endpoint
|
|
33858
|
+
.then((endpoint) => {
|
|
33859
|
+
const featureTypes = endpoint.getFeatureTypes();
|
|
33860
|
+
return endpoint.getFeatureTypeFull(featureTypes.length === 1 && !featureTypeName
|
|
33861
|
+
? featureTypes[0].name
|
|
33862
|
+
: featureTypeName);
|
|
33863
|
+
})
|
|
33864
|
+
.then((featureType) => {
|
|
33865
|
+
if (!featureType) {
|
|
33866
|
+
throw new Error('wfs.featuretype.notfound');
|
|
33867
|
+
}
|
|
33868
|
+
return featureType;
|
|
33869
|
+
});
|
|
33870
|
+
}
|
|
33871
|
+
get backupReader() {
|
|
33872
|
+
if (this.backupReader_) {
|
|
33873
|
+
return this.backupReader_;
|
|
33874
|
+
}
|
|
33875
|
+
this.backupReader_ = Promise.all([this.endpoint, this.featureType]).then(([endpoint, featureType]) => {
|
|
33876
|
+
let reader;
|
|
33877
|
+
if (endpoint.supportsJson(featureType.name)) {
|
|
33878
|
+
reader = new GeojsonReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33879
|
+
asJson: true,
|
|
33880
|
+
outputCrs: 'EPSG:4326',
|
|
33881
|
+
}));
|
|
33882
|
+
}
|
|
33883
|
+
else {
|
|
33884
|
+
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33885
|
+
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33886
|
+
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33887
|
+
reader = new GmlReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33888
|
+
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33889
|
+
outputCrs: 'EPSG:4326',
|
|
33890
|
+
}));
|
|
33891
|
+
}
|
|
33892
|
+
}
|
|
33893
|
+
reader.enableCache(this.cacheEnabled);
|
|
33894
|
+
reader.load();
|
|
33895
|
+
return reader;
|
|
33896
|
+
});
|
|
33897
|
+
return this.backupReader_;
|
|
33284
33898
|
}
|
|
33285
33899
|
get properties() {
|
|
33286
|
-
return this.
|
|
33287
|
-
.getFeatureTypeFull(this.featureTypeName)
|
|
33288
|
-
.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33900
|
+
return this.featureType.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33289
33901
|
const originalType = featureType.properties[prop];
|
|
33290
|
-
|
|
33291
|
-
|
|
33292
|
-
|
|
33902
|
+
let type;
|
|
33903
|
+
if (originalType === 'float' || originalType === 'integer') {
|
|
33904
|
+
type = 'number';
|
|
33905
|
+
}
|
|
33906
|
+
else if (originalType === 'boolean') {
|
|
33907
|
+
type = 'string'; // we don't handle booleans yet in the data fetcher
|
|
33908
|
+
}
|
|
33909
|
+
else {
|
|
33910
|
+
type = originalType;
|
|
33911
|
+
}
|
|
33293
33912
|
return {
|
|
33294
33913
|
name: prop,
|
|
33295
33914
|
label: prop,
|
|
@@ -33298,83 +33917,63 @@ class WfsReader extends BaseCacheReader {
|
|
|
33298
33917
|
}));
|
|
33299
33918
|
}
|
|
33300
33919
|
get info() {
|
|
33301
|
-
return this.
|
|
33920
|
+
return this.featureType.then((result) => ({
|
|
33302
33921
|
itemsCount: result.objectCount,
|
|
33922
|
+
hasGeometry: !!result.geometryName,
|
|
33303
33923
|
}));
|
|
33304
33924
|
}
|
|
33305
|
-
|
|
33306
|
-
|
|
33307
|
-
const featureTypes = wfsEndpoint.getFeatureTypes();
|
|
33308
|
-
const featureType = wfsEndpoint.getFeatureTypeSummary(featureTypes.length === 1 && !featureTypeName
|
|
33309
|
-
? featureTypes[0].name
|
|
33310
|
-
: featureTypeName);
|
|
33311
|
-
if (!featureType) {
|
|
33312
|
-
throw new Error('wfs.featuretype.notfound');
|
|
33313
|
-
}
|
|
33314
|
-
if (wfsEndpoint.supportsStartIndex()) {
|
|
33315
|
-
return new WfsReader(wfsUrlEndpoint, wfsEndpoint, featureType.name);
|
|
33316
|
-
}
|
|
33317
|
-
else if (wfsEndpoint.supportsJson(featureType.name)) {
|
|
33318
|
-
return new GeojsonReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33319
|
-
asJson: true,
|
|
33320
|
-
outputCrs: 'EPSG:4326',
|
|
33321
|
-
}));
|
|
33322
|
-
}
|
|
33323
|
-
else {
|
|
33324
|
-
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33325
|
-
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33326
|
-
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33327
|
-
return new GmlReader(wfsEndpoint.getFeatureUrl(featureType.name, {
|
|
33328
|
-
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33329
|
-
outputCrs: 'EPSG:4326',
|
|
33330
|
-
}), featureType.name, wfsEndpoint.getVersion());
|
|
33331
|
-
}
|
|
33332
|
-
throw new Error('wfs.geojsongml.notsupported');
|
|
33333
|
-
}
|
|
33925
|
+
load() {
|
|
33926
|
+
// Nothing to load for Wfs
|
|
33334
33927
|
}
|
|
33335
|
-
async
|
|
33336
|
-
|
|
33337
|
-
|
|
33928
|
+
async read() {
|
|
33929
|
+
const endpoint = await this.endpoint;
|
|
33930
|
+
const featureType = await this.featureType;
|
|
33931
|
+
// if we can't use the WFS protocol we fall back to the backup reader
|
|
33932
|
+
if (this.aggregations || this.groupedBy || !endpoint.supportsStartIndex()) {
|
|
33933
|
+
const backupReader = await this.backupReader;
|
|
33934
|
+
backupReader.selectAll();
|
|
33935
|
+
if (this.selected) {
|
|
33936
|
+
backupReader.select(...this.selected);
|
|
33937
|
+
}
|
|
33938
|
+
if (this.aggregations) {
|
|
33939
|
+
backupReader.aggregate(...this.aggregations);
|
|
33940
|
+
}
|
|
33941
|
+
if (this.groupedBy) {
|
|
33942
|
+
backupReader.groupBy(...this.groupedBy);
|
|
33943
|
+
}
|
|
33944
|
+
if (this.sort) {
|
|
33945
|
+
backupReader.orderBy(...this.sort);
|
|
33946
|
+
}
|
|
33947
|
+
if (this.startIndex !== null && this.count !== null) {
|
|
33948
|
+
backupReader.limit(this.startIndex, this.count);
|
|
33949
|
+
}
|
|
33950
|
+
return backupReader.read();
|
|
33338
33951
|
}
|
|
33339
|
-
const asJson =
|
|
33952
|
+
const asJson = endpoint.supportsJson(featureType.name);
|
|
33340
33953
|
const attributes = this.selected ?? undefined;
|
|
33341
|
-
let
|
|
33954
|
+
let sortBy = null;
|
|
33955
|
+
if (this.sort) {
|
|
33956
|
+
const mapSort = (s) => [s[0] === 'desc' ? 'D' : 'A', s[1]];
|
|
33957
|
+
sortBy = Array.isArray(this.sort[0])
|
|
33958
|
+
? this.sort.map(mapSort)
|
|
33959
|
+
: mapSort(this.sort);
|
|
33960
|
+
}
|
|
33961
|
+
const url = endpoint.getFeatureUrl(featureType.name, {
|
|
33342
33962
|
...(this.startIndex !== null && { startIndex: this.startIndex }),
|
|
33343
33963
|
...(this.count !== null && { maxFeatures: this.count }),
|
|
33344
33964
|
asJson,
|
|
33345
33965
|
outputCrs: 'EPSG:4326',
|
|
33346
33966
|
attributes,
|
|
33347
|
-
|
|
33967
|
+
sortBy,
|
|
33348
33968
|
});
|
|
33349
|
-
|
|
33350
|
-
const finalUrl = new URL(url);
|
|
33351
|
-
const sorts = this.sort
|
|
33352
|
-
.map((fieldSort) => `${fieldSort[1]}+${fieldSort[0] === 'asc' ? 'A' : 'D'}`)
|
|
33353
|
-
.join(',');
|
|
33354
|
-
// Direct update on string url to prevent encoding of +A and +D
|
|
33355
|
-
url = `${url}${finalUrl.search ? '&' : ''}SORTBY=${sorts}`;
|
|
33356
|
-
}
|
|
33357
|
-
return fetchDataAsText(url, this.cacheActive).then((text) => asJson
|
|
33969
|
+
return fetchDataAsText(url, this.cacheEnabled).then((text) => asJson
|
|
33358
33970
|
? parseGeojson(text)
|
|
33359
|
-
: parseGml(text,
|
|
33360
|
-
}
|
|
33361
|
-
async getQueryData() {
|
|
33362
|
-
const items = (await this.getData()).items;
|
|
33363
|
-
const jsonItems = getJsonDataItemsProxy(items);
|
|
33364
|
-
const query = generateSqlQuery(this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations);
|
|
33365
|
-
const result = await import('alasql').then((module) => module.default(query, [jsonItems]));
|
|
33366
|
-
return result.map(jsonToGeojsonFeature);
|
|
33367
|
-
}
|
|
33368
|
-
load() {
|
|
33369
|
-
// Nothing to load for Wfs
|
|
33370
|
-
}
|
|
33371
|
-
async read() {
|
|
33372
|
-
return (await this.getData(this.aggregations, this.groupedBy)).items;
|
|
33971
|
+
: parseGml(text, featureType.name, endpoint.getVersion()));
|
|
33373
33972
|
}
|
|
33374
33973
|
}
|
|
33375
33974
|
|
|
33376
|
-
async function openDataset(url,
|
|
33377
|
-
const fileType = await inferDatasetType(url, typeHint);
|
|
33975
|
+
async function openDataset(url, options) {
|
|
33976
|
+
const fileType = await inferDatasetType(url, options?.typeHint);
|
|
33378
33977
|
let reader;
|
|
33379
33978
|
try {
|
|
33380
33979
|
switch (fileType) {
|
|
@@ -33391,18 +33990,18 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33391
33990
|
reader = new ExcelReader(url);
|
|
33392
33991
|
break;
|
|
33393
33992
|
case 'gml':
|
|
33394
|
-
reader = new GmlReader(url
|
|
33993
|
+
reader = new GmlReader(url);
|
|
33395
33994
|
break;
|
|
33396
33995
|
case 'wfs':
|
|
33397
|
-
reader =
|
|
33996
|
+
reader = new WfsReader(url, options?.wfsFeatureType);
|
|
33398
33997
|
break;
|
|
33399
33998
|
}
|
|
33400
|
-
reader.
|
|
33999
|
+
reader.enableCache(options?.enableCache ?? true);
|
|
33401
34000
|
reader.load();
|
|
33402
34001
|
return reader;
|
|
33403
34002
|
}
|
|
33404
34003
|
catch (e) {
|
|
33405
|
-
//WfsReader may already raise a FetchError
|
|
34004
|
+
// WfsReader may already raise a FetchError
|
|
33406
34005
|
if (e instanceof FetchError)
|
|
33407
34006
|
throw e;
|
|
33408
34007
|
else
|
|
@@ -33413,13 +34012,13 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33413
34012
|
* This fetches the full dataset at the given URL and parses it according to its mime type.
|
|
33414
34013
|
* All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
|
|
33415
34014
|
* File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
|
|
33416
|
-
* File type is determined
|
|
34015
|
+
* File type is determined like so:
|
|
33417
34016
|
* 1. if a type hint is given, use it
|
|
33418
34017
|
* 2. otherwise, look for a Content-Type header in the response with a supported mime type
|
|
33419
34018
|
* 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
|
|
33420
34019
|
*/
|
|
33421
|
-
async function readDataset(url,
|
|
33422
|
-
const reader = await openDataset(url,
|
|
34020
|
+
async function readDataset(url, options) {
|
|
34021
|
+
const reader = await openDataset(url, options);
|
|
33423
34022
|
try {
|
|
33424
34023
|
return await reader.read();
|
|
33425
34024
|
}
|
|
@@ -33650,9 +34249,11 @@ class DataService {
|
|
|
33650
34249
|
getDataset(link, cacheActive) {
|
|
33651
34250
|
if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
|
|
33652
34251
|
const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString());
|
|
33653
|
-
return from(openDataset(wfsUrlEndpoint,
|
|
34252
|
+
return from(openDataset(wfsUrlEndpoint, {
|
|
34253
|
+
typeHint: 'wfs',
|
|
33654
34254
|
wfsFeatureType: link.name,
|
|
33655
|
-
|
|
34255
|
+
enableCache: cacheActive,
|
|
34256
|
+
}));
|
|
33656
34257
|
}
|
|
33657
34258
|
else if (link.type === 'download') {
|
|
33658
34259
|
const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString());
|
|
@@ -33660,12 +34261,15 @@ class DataService {
|
|
|
33660
34261
|
const supportedType = SupportedTypes.indexOf(format) > -1
|
|
33661
34262
|
? format
|
|
33662
34263
|
: undefined;
|
|
33663
|
-
return from(openDataset(linkProxifiedUrl,
|
|
34264
|
+
return from(openDataset(linkProxifiedUrl, {
|
|
34265
|
+
typeHint: supportedType,
|
|
34266
|
+
enableCache: cacheActive,
|
|
34267
|
+
})).pipe();
|
|
33664
34268
|
}
|
|
33665
34269
|
else if (link.type === 'service' &&
|
|
33666
34270
|
link.accessServiceProtocol === 'esriRest') {
|
|
33667
34271
|
const url = this.getDownloadUrlFromEsriRest(link.url.toString(), 'geojson');
|
|
33668
|
-
return from(openDataset(url, 'geojson',
|
|
34272
|
+
return from(openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })).pipe();
|
|
33669
34273
|
}
|
|
33670
34274
|
else if (link.type === 'service' &&
|
|
33671
34275
|
link.accessServiceProtocol === 'ogcFeatures') {
|
|
@@ -33679,7 +34283,10 @@ class DataService {
|
|
|
33679
34283
|
}
|
|
33680
34284
|
const urlWithoutLimit = new URL(geojsonUrl);
|
|
33681
34285
|
urlWithoutLimit.searchParams.delete('limit');
|
|
33682
|
-
return openDataset(urlWithoutLimit.toString(),
|
|
34286
|
+
return openDataset(urlWithoutLimit.toString(), {
|
|
34287
|
+
typeHint: 'geojson',
|
|
34288
|
+
enableCache: cacheActive,
|
|
34289
|
+
});
|
|
33683
34290
|
}));
|
|
33684
34291
|
}
|
|
33685
34292
|
return throwError(() => 'protocol not supported');
|
|
@@ -33931,20 +34538,31 @@ class DataTableComponent {
|
|
|
33931
34538
|
this.eltRef = inject(ElementRef);
|
|
33932
34539
|
this.cdr = inject(ChangeDetectorRef);
|
|
33933
34540
|
this.translateService = inject(TranslateService);
|
|
33934
|
-
this.
|
|
34541
|
+
this.columnsFromFeatureCatalog = null;
|
|
34542
|
+
this.columnsFromDataset = [];
|
|
33935
34543
|
this.selected = new EventEmitter();
|
|
33936
|
-
this.properties$ = new BehaviorSubject(null);
|
|
33937
34544
|
this.loading$ = new BehaviorSubject(false);
|
|
33938
34545
|
this.error = null;
|
|
33939
34546
|
}
|
|
33940
34547
|
set featureAttributes(value) {
|
|
33941
|
-
this.
|
|
33942
|
-
|
|
34548
|
+
this.columnsFromFeatureCatalog = value.map((attrs) => ({
|
|
34549
|
+
name: attrs.value,
|
|
34550
|
+
label: attrs.label,
|
|
34551
|
+
}));
|
|
33943
34552
|
}
|
|
33944
34553
|
set dataset(value) {
|
|
33945
34554
|
this.dataset_ = value;
|
|
33946
34555
|
this.dataset_.load();
|
|
33947
|
-
this.dataset_.info.then((info) =>
|
|
34556
|
+
this.dataset_.info.then((info) => {
|
|
34557
|
+
this.count = info.itemsCount;
|
|
34558
|
+
this.cdr.detectChanges();
|
|
34559
|
+
});
|
|
34560
|
+
}
|
|
34561
|
+
get columns() {
|
|
34562
|
+
return this.columnsFromFeatureCatalog ?? this.columnsFromDataset;
|
|
34563
|
+
}
|
|
34564
|
+
get columnNames() {
|
|
34565
|
+
return this.columns.map((c) => c.name);
|
|
33948
34566
|
}
|
|
33949
34567
|
ngOnInit() {
|
|
33950
34568
|
this.dataSource = new DataTableDataSource();
|
|
@@ -33979,11 +34597,12 @@ class DataTableComponent {
|
|
|
33979
34597
|
}
|
|
33980
34598
|
async readData() {
|
|
33981
34599
|
this.loading$.next(true);
|
|
33982
|
-
// wait for properties to be read
|
|
33983
|
-
const properties = await firstValueFrom(this.properties$.pipe(filter((p) => !!p)));
|
|
33984
|
-
const propsWithoutGeom = properties.filter((p) => !p.toLowerCase().startsWith('geom'));
|
|
33985
|
-
this.dataset_.select(...propsWithoutGeom);
|
|
33986
34600
|
try {
|
|
34601
|
+
// wait for properties to be read
|
|
34602
|
+
if (!this.columnsFromFeatureCatalog) {
|
|
34603
|
+
this.columnsFromDataset = await this.dataset_.properties;
|
|
34604
|
+
}
|
|
34605
|
+
this.dataset_.select(...this.columnNames);
|
|
33987
34606
|
await this.dataSource.showData(this.dataset_.read());
|
|
33988
34607
|
this.error = null;
|
|
33989
34608
|
}
|
|
@@ -34013,7 +34632,7 @@ class DataTableComponent {
|
|
|
34013
34632
|
}
|
|
34014
34633
|
}
|
|
34015
34634
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34016
|
-
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
|
|
34635
|
+
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 }); }
|
|
34017
34636
|
}
|
|
34018
34637
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
34019
34638
|
type: Component,
|
|
@@ -34025,10 +34644,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
34025
34644
|
CommonModule,
|
|
34026
34645
|
LoadingMaskComponent,
|
|
34027
34646
|
PopupAlertComponent,
|
|
34028
|
-
LetDirective,
|
|
34029
34647
|
TranslatePipe,
|
|
34030
34648
|
TranslateDirective,
|
|
34031
|
-
], 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
|
|
34649
|
+
], 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"] }]
|
|
34032
34650
|
}], propDecorators: { featureAttributes: [{
|
|
34033
34651
|
type: Input
|
|
34034
34652
|
}], dataset: [{
|
|
@@ -34131,7 +34749,7 @@ class ChartViewComponent {
|
|
|
34131
34749
|
}), shareReplay$1(1));
|
|
34132
34750
|
this.properties$ = combineLatest([this.dataset$, this.featureCatalog$]).pipe(switchMap$1(([dataset, catalog]) => this.setProperties(dataset, catalog)), shareReplay$1(1));
|
|
34133
34751
|
this.yChoices$ = this.properties$.pipe(map$1((properties) => properties
|
|
34134
|
-
.filter((prop) => prop.type === 'number'
|
|
34752
|
+
.filter((prop) => prop.type === 'number')
|
|
34135
34753
|
.map((prop) => ({ value: prop.name, label: prop.label || prop.name }))), tap$1((choices) => {
|
|
34136
34754
|
if (!choices.find((choice) => choice.value === this.yProperty$.value)) {
|
|
34137
34755
|
const newProp = choices[0]?.value || '';
|
|
@@ -34158,6 +34776,7 @@ class ChartViewComponent {
|
|
|
34158
34776
|
this.aggregation$,
|
|
34159
34777
|
]).pipe(filter$1(([_, x, y]) => !!x || !!y), switchMap$1(([dataset, xProp, yProp, aggregation]) => {
|
|
34160
34778
|
const fieldAgg = aggregation === 'count' ? ['count'] : [aggregation, yProp];
|
|
34779
|
+
this.loading = true;
|
|
34161
34780
|
return dataset
|
|
34162
34781
|
.groupBy(['distinct', xProp])
|
|
34163
34782
|
.aggregate(fieldAgg)
|
|
@@ -34399,6 +35018,7 @@ class GeoTableViewComponent {
|
|
|
34399
35018
|
}));
|
|
34400
35019
|
}
|
|
34401
35020
|
async initMapContext() {
|
|
35021
|
+
this.dataset.load();
|
|
34402
35022
|
this.dataset.selectAll();
|
|
34403
35023
|
return {
|
|
34404
35024
|
layers: [
|
|
@@ -34572,8 +35192,7 @@ class MdViewFacade {
|
|
|
34572
35192
|
}));
|
|
34573
35193
|
this.error$ = this.store.pipe(select(getMetadataError));
|
|
34574
35194
|
this.related$ = this.store.pipe(select(getRelated));
|
|
34575
|
-
this.
|
|
34576
|
-
this.sourceOf$ = this.store.pipe(select(getSourceOf));
|
|
35195
|
+
this.linkedRecords$ = this.store.pipe(select(getLinkedRecords));
|
|
34577
35196
|
this.chartConfig$ = this.store.pipe(select(getChartConfig));
|
|
34578
35197
|
this.allLinks$ = this.metadata$.pipe(map$1((record) => 'onlineResources' in record ? record.onlineResources : []), shareReplay$1(1));
|
|
34579
35198
|
this.resourceDoi$ = this.metadata$.pipe(map$1((record) => {
|
|
@@ -34692,12 +35311,9 @@ class MdViewEffects {
|
|
|
34692
35311
|
this.loadRelatedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSimilarRecords(full)), map$1((related) => {
|
|
34693
35312
|
return setRelated({ related });
|
|
34694
35313
|
}), catchError(() => of(setRelated({ related: null })))));
|
|
34695
|
-
this.
|
|
34696
|
-
return
|
|
34697
|
-
}), catchError(() => of(
|
|
34698
|
-
this.loadSourceOf$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSourceOf(full)), map$1((sourceOf) => {
|
|
34699
|
-
return setSourceOf({ sourceOf });
|
|
34700
|
-
}), catchError(() => of(setSourceOf({ sourceOf: null })))));
|
|
35314
|
+
this.loadLinkedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getLinkedRecords(full)), map$1((linkedRecords) => {
|
|
35315
|
+
return setLinkedRecords({ linkedRecords });
|
|
35316
|
+
}), catchError(() => of(setLinkedRecords({ linkedRecords: null })))));
|
|
34701
35317
|
/*
|
|
34702
35318
|
UserFeedback effects
|
|
34703
35319
|
*/
|
|
@@ -36431,6 +37047,11 @@ const DEFAULT_CONFIGURATION = {
|
|
|
36431
37047
|
},
|
|
36432
37048
|
hidden: '${record.kind == "service"}',
|
|
36433
37049
|
},
|
|
37050
|
+
{
|
|
37051
|
+
model: 'associatedRecords',
|
|
37052
|
+
formFieldConfig: {},
|
|
37053
|
+
hidden: '${record.kind == "service"}',
|
|
37054
|
+
},
|
|
36434
37055
|
],
|
|
36435
37056
|
},
|
|
36436
37057
|
// Section: Geographical coverage
|
|
@@ -37393,7 +38014,7 @@ class GenericKeywordsComponent {
|
|
|
37393
38014
|
this.deletedKeyword.emit(keyword);
|
|
37394
38015
|
}
|
|
37395
38016
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37396
|
-
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 }); }
|
|
38017
|
+
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 }); }
|
|
37397
38018
|
}
|
|
37398
38019
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, decorators: [{
|
|
37399
38020
|
type: Component,
|
|
@@ -37568,7 +38189,7 @@ class FormFieldTemporalExtentsComponent {
|
|
|
37568
38189
|
provideNgIconsConfig({
|
|
37569
38190
|
size: '1.5rem',
|
|
37570
38191
|
}),
|
|
37571
|
-
], ngImport: i0, template: "<div class=\"flex gap-2
|
|
38192
|
+
], 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 }); }
|
|
37572
38193
|
}
|
|
37573
38194
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldTemporalExtentsComponent, decorators: [{
|
|
37574
38195
|
type: Component,
|
|
@@ -37585,7 +38206,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37585
38206
|
provideNgIconsConfig({
|
|
37586
38207
|
size: '1.5rem',
|
|
37587
38208
|
}),
|
|
37588
|
-
], template: "<div class=\"flex gap-2
|
|
38209
|
+
], 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"] }]
|
|
37589
38210
|
}], propDecorators: { value: [{
|
|
37590
38211
|
type: Input
|
|
37591
38212
|
}], valueChange: [{
|
|
@@ -37801,6 +38422,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37801
38422
|
], 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" }]
|
|
37802
38423
|
}] });
|
|
37803
38424
|
|
|
38425
|
+
class FormFieldAssociatedRecordsComponent {
|
|
38426
|
+
constructor() {
|
|
38427
|
+
this.valueChange = new EventEmitter();
|
|
38428
|
+
}
|
|
38429
|
+
get list() {
|
|
38430
|
+
return this.value ?? [];
|
|
38431
|
+
}
|
|
38432
|
+
get first() {
|
|
38433
|
+
return this.list[0];
|
|
38434
|
+
}
|
|
38435
|
+
get rest() {
|
|
38436
|
+
return this.list.slice(1);
|
|
38437
|
+
}
|
|
38438
|
+
get hasParentLink() {
|
|
38439
|
+
return this.list.length > 0;
|
|
38440
|
+
}
|
|
38441
|
+
get uniqueIdentifier() {
|
|
38442
|
+
return this.first?.uniqueIdentifier ?? '';
|
|
38443
|
+
}
|
|
38444
|
+
get selectedType() {
|
|
38445
|
+
return this.first?.associationType;
|
|
38446
|
+
}
|
|
38447
|
+
get choices() {
|
|
38448
|
+
return associationTypeValues.map((value) => ({
|
|
38449
|
+
value,
|
|
38450
|
+
label: `domain.record.associationType.${value}`,
|
|
38451
|
+
}));
|
|
38452
|
+
}
|
|
38453
|
+
onToggle(checked) {
|
|
38454
|
+
this.valueChange.emit(checked
|
|
38455
|
+
? [
|
|
38456
|
+
{
|
|
38457
|
+
uniqueIdentifier: '',
|
|
38458
|
+
associationType: associationTypeValues[0],
|
|
38459
|
+
},
|
|
38460
|
+
...this.rest,
|
|
38461
|
+
]
|
|
38462
|
+
: this.rest);
|
|
38463
|
+
}
|
|
38464
|
+
onUniqueIdentifierChange(uniqueIdentifier) {
|
|
38465
|
+
this.valueChange.emit(uniqueIdentifier
|
|
38466
|
+
? [{ ...this.first, uniqueIdentifier }, ...this.rest]
|
|
38467
|
+
: this.rest);
|
|
38468
|
+
}
|
|
38469
|
+
onTypeChange(associationType) {
|
|
38470
|
+
this.valueChange.emit([
|
|
38471
|
+
{ ...this.first, associationType: associationType },
|
|
38472
|
+
...this.rest,
|
|
38473
|
+
]);
|
|
38474
|
+
}
|
|
38475
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38476
|
+
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 }); }
|
|
38477
|
+
}
|
|
38478
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, decorators: [{
|
|
38479
|
+
type: Component,
|
|
38480
|
+
args: [{ selector: 'gn-ui-form-field-associated-records', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
38481
|
+
CheckToggleComponent,
|
|
38482
|
+
TextInputComponent,
|
|
38483
|
+
DropdownSelectorComponent,
|
|
38484
|
+
FormFieldWrapperComponent,
|
|
38485
|
+
TranslatePipe,
|
|
38486
|
+
], 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" }]
|
|
38487
|
+
}], propDecorators: { value: [{
|
|
38488
|
+
type: Input
|
|
38489
|
+
}], valueChange: [{
|
|
38490
|
+
type: Output
|
|
38491
|
+
}] } });
|
|
38492
|
+
|
|
37804
38493
|
class ContactCardComponent {
|
|
37805
38494
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37806
38495
|
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 }); }
|
|
@@ -37917,7 +38606,7 @@ class FormFieldContactsForResourceComponent {
|
|
|
37917
38606
|
provideNgIconsConfig({
|
|
37918
38607
|
size: '1.5rem',
|
|
37919
38608
|
}),
|
|
37920
|
-
], 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 }); }
|
|
38609
|
+
], 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 }); }
|
|
37921
38610
|
}
|
|
37922
38611
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsForResourceComponent, decorators: [{
|
|
37923
38612
|
type: Component,
|
|
@@ -38017,7 +38706,7 @@ class FormFieldContactsComponent {
|
|
|
38017
38706
|
this.subscription.unsubscribe();
|
|
38018
38707
|
}
|
|
38019
38708
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38020
|
-
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 }); }
|
|
38709
|
+
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 }); }
|
|
38021
38710
|
}
|
|
38022
38711
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, decorators: [{
|
|
38023
38712
|
type: Component,
|
|
@@ -38370,7 +39059,7 @@ class OnlineServiceResourceInputComponent {
|
|
|
38370
39059
|
provideNgIconsConfig({
|
|
38371
39060
|
size: '1.5em',
|
|
38372
39061
|
}),
|
|
38373
|
-
], 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 }); }
|
|
39062
|
+
], 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 }); }
|
|
38374
39063
|
}
|
|
38375
39064
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: OnlineServiceResourceInputComponent, decorators: [{
|
|
38376
39065
|
type: Component,
|
|
@@ -39186,6 +39875,9 @@ class FormFieldComponent {
|
|
|
39186
39875
|
get valueAsUpdateFrequency() {
|
|
39187
39876
|
return this.value;
|
|
39188
39877
|
}
|
|
39878
|
+
get valueAsAssociatedRecords() {
|
|
39879
|
+
return this.value;
|
|
39880
|
+
}
|
|
39189
39881
|
get valueAsTemporalExtents() {
|
|
39190
39882
|
return this.value;
|
|
39191
39883
|
}
|
|
@@ -39225,7 +39917,7 @@ class FormFieldComponent {
|
|
|
39225
39917
|
}
|
|
39226
39918
|
}
|
|
39227
39919
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39228
|
-
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 }); }
|
|
39920
|
+
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 }); }
|
|
39229
39921
|
}
|
|
39230
39922
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
39231
39923
|
type: Component,
|
|
@@ -39237,6 +39929,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39237
39929
|
FormFieldLicenseComponent,
|
|
39238
39930
|
FormFieldDateComponent,
|
|
39239
39931
|
FormFieldUpdateFrequencyComponent,
|
|
39932
|
+
FormFieldAssociatedRecordsComponent,
|
|
39240
39933
|
FormFieldTemporalExtentsComponent,
|
|
39241
39934
|
FormFieldSimpleComponent,
|
|
39242
39935
|
FormFieldRichComponent,
|
|
@@ -39254,7 +39947,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39254
39947
|
FormFieldTopicsComponent,
|
|
39255
39948
|
TextFieldModule,
|
|
39256
39949
|
NgIconComponent,
|
|
39257
|
-
], 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"] }]
|
|
39950
|
+
], 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"] }]
|
|
39258
39951
|
}], propDecorators: { uniqueIdentifier: [{
|
|
39259
39952
|
type: Input
|
|
39260
39953
|
}], recordKind: [{
|
|
@@ -39839,7 +40532,7 @@ class RouterService {
|
|
|
39839
40532
|
return ROUTER_ROUTE_ORGANIZATION;
|
|
39840
40533
|
}
|
|
39841
40534
|
getDefaultSort() {
|
|
39842
|
-
return SortByEnum.
|
|
40535
|
+
return SortByEnum.RESOURCE_DATE;
|
|
39843
40536
|
}
|
|
39844
40537
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39845
40538
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, providedIn: 'root' }); }
|
|
@@ -39899,7 +40592,7 @@ function flattenQueryParams(params) {
|
|
|
39899
40592
|
const start = flattened[key].start;
|
|
39900
40593
|
const end = flattened[key].end;
|
|
39901
40594
|
flattened[key] = [
|
|
39902
|
-
`${start ? formatDate(start) : ''}..${formatDate(end)
|
|
40595
|
+
`${start ? formatDate(start) : ''}..${end ? formatDate(end) : ''}`,
|
|
39903
40596
|
];
|
|
39904
40597
|
}
|
|
39905
40598
|
}
|
|
@@ -40256,5 +40949,5 @@ const CHART_TYPE_VALUES = [
|
|
|
40256
40949
|
* Generated bundle index. Do not edit.
|
|
40257
40950
|
*/
|
|
40258
40951
|
|
|
40259
|
-
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_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingComponent, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, 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 };
|
|
40952
|
+
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, isBoundingBoxWithinWorldExtent, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
|
|
40260
40953
|
//# sourceMappingURL=geonetwork-ui.mjs.map
|