geonetwork-ui 2.10.3-dev.4154db07d → 2.11.0-dev.4976ded4f
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 +1473 -811
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +230 -82
- package/index.d.ts.map +1 -1
- package/package.json +8 -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 +70 -10
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +40 -16
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +40 -2
- package/src/libs/common/domain/src/lib/model/search/filter.model.ts +13 -1
- package/src/libs/common/domain/src/lib/model/search/sort-by.model.ts +1 -5
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -2
- package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +3 -2
- package/src/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.ts +2 -1
- package/src/libs/feature/dataviz/src/lib/service/data.service.ts +22 -22
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.html +33 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.ts +94 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.html +16 -12
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +6 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +6 -0
- package/src/libs/feature/editor/src/lib/fields.config.ts +5 -0
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +1 -0
- package/src/libs/feature/notifications/src/lib/notifications.service.ts +6 -4
- package/src/libs/feature/record/src/lib/state/mdview.actions.ts +4 -8
- package/src/libs/feature/record/src/lib/state/mdview.effects.ts +7 -16
- package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -3
- package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +4 -9
- package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +2 -7
- package/src/libs/feature/router/src/lib/default/router.service.ts +1 -1
- package/src/libs/feature/router/src/lib/default/state/query-params.utils.ts +1 -1
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +9 -4
- package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +46 -19
- package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +17 -8
- package/src/libs/feature/search/src/lib/sort-by/sort-by.component.ts +1 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +3 -1
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +27 -2
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +6 -7
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +31 -19
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.ts +2 -2
- package/src/libs/ui/inputs/src/index.ts +2 -0
- package/src/libs/ui/inputs/src/lib/date-adapter.providers.ts +30 -0
- package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +3 -24
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.css +37 -3
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.html +135 -16
- package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.ts +166 -29
- package/src/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.ts +3 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.css +1 -0
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.html +20 -7
- package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.ts +46 -5
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.css +0 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +117 -0
- package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +191 -0
- package/src/libs/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/services/date.service.ts +3 -3
- package/src/libs/util/shared/src/lib/utils/file.ts +15 -0
- package/src/libs/util/shared/src/lib/utils/geojson.ts +8 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/tailwind.base.css +5 -0
- package/translations/de.json +26 -3
- package/translations/en.json +25 -2
- package/translations/es.json +23 -0
- package/translations/fr.json +26 -3
- package/translations/it.json +24 -1
- package/translations/nl.json +23 -0
- package/translations/pt.json +23 -0
- package/translations/sk.json +24 -1
- package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +0 -14
|
@@ -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, takeUntil, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1 } from 'rxjs';
|
|
10
10
|
import * as i0 from '@angular/core';
|
|
11
|
-
import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef,
|
|
11
|
+
import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef, afterNextRender, booleanAttribute, Input, Directive, HostListener, Renderer2, DestroyRef, EventEmitter, Output, ViewChild, ChangeDetectionStrategy, Component, ViewEncapsulation, ChangeDetectorRef, HostBinding, ViewContainerRef, TemplateRef, ViewChildren, ContentChild, input, output, signal, viewChild, computed, ContentChildren, NgZone, ComponentFactoryResolver, viewChildren } from '@angular/core';
|
|
12
12
|
import { HttpClient, HttpHeaders, HttpParams, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, HttpEventType } from '@angular/common/http';
|
|
13
13
|
import * as i4 from '@ngx-translate/core';
|
|
14
14
|
import { TranslateLoader, TranslateCompiler, TranslateDefaultParser, TranslateParser, TranslateService, provideTranslateService, TranslateDirective, TranslatePipe, TranslateModule } from '@ngx-translate/core';
|
|
@@ -18,7 +18,7 @@ import { map as map$1, shareReplay as shareReplay$1, catchError, tap as tap$1, f
|
|
|
18
18
|
import { lt, valid, coerce, satisfies, ltr } from 'semver';
|
|
19
19
|
import chroma from 'chroma-js';
|
|
20
20
|
import * as i1$1 from '@angular/common';
|
|
21
|
-
import { Location, CommonModule,
|
|
21
|
+
import { Location, CommonModule, NgTemplateOutlet, NgClass, AsyncPipe } from '@angular/common';
|
|
22
22
|
import { formatDistance } from 'date-fns/formatDistance';
|
|
23
23
|
import { Scroll, NavigationEnd, Router, RouteReuseStrategy } from '@angular/router';
|
|
24
24
|
import { WmtsEndpoint, WmsEndpoint, WfsEndpoint, OgcApiEndpoint, sharedFetch, useCache, StacEndpoint, TmsEndpoint } from '@camptocamp/ogc-client';
|
|
@@ -41,10 +41,10 @@ import * as TOML from '@ltd/j-toml';
|
|
|
41
41
|
import { Style, Stroke, Fill, Circle } from 'ol/style.js';
|
|
42
42
|
import CircleStyle from 'ol/style/Circle.js';
|
|
43
43
|
import EmblaCarousel from 'embla-carousel';
|
|
44
|
-
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn,
|
|
44
|
+
import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirTrash, iconoirSquareDashed, iconoirImport, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
|
|
45
45
|
import { MatButtonModule } from '@angular/material/button';
|
|
46
|
-
import * as i1$
|
|
47
|
-
import {
|
|
46
|
+
import * as i1$7 from '@angular/cdk/overlay';
|
|
47
|
+
import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
48
48
|
import * as i1$3 from '@angular/forms';
|
|
49
49
|
import { UntypedFormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
50
50
|
import * as i1$2 from '@angular/material/autocomplete';
|
|
@@ -52,16 +52,18 @@ import { MatAutocompleteModule, MatAutocompleteTrigger, MatAutocomplete } from '
|
|
|
52
52
|
import tippy from 'tippy.js';
|
|
53
53
|
import * as i2 from '@angular/material/progress-spinner';
|
|
54
54
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
55
|
-
import { matClose, matContentCopy,
|
|
55
|
+
import { matClose, matContentCopy, matExpandMore, matExpandLess, matSearch, matStarBorder, matStar, matRemove, matAdd, matChevronRight, matChevronLeft, matArrowForwardIos, matArrowBackIos, matMoodBad, matQuestionMark, matFace, matZoomOutMap, matOpenInNew, matPersonOutline, matMailOutline, matWarningAmber, matCheck, matCheckCircleOutline, matWarning, matMoreVert } from '@ng-icons/material-icons/baseline';
|
|
56
56
|
import * as i1$4 from '@angular/material/checkbox';
|
|
57
57
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
58
58
|
import * as i1$5 from '@angular/material/tooltip';
|
|
59
59
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
60
|
-
import {
|
|
60
|
+
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
|
|
61
|
+
import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
|
62
|
+
import { enUS } from 'date-fns/locale/en-US';
|
|
61
63
|
import * as i1$6 from '@angular/material/datepicker';
|
|
62
64
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
63
|
-
import * as i1$
|
|
64
|
-
import { NgxDropzoneModule } from 'ngx-dropzone';
|
|
65
|
+
import * as i1$8 from 'ngx-dropzone';
|
|
66
|
+
import { NgxDropzoneModule, NgxDropzoneComponent } from 'ngx-dropzone';
|
|
65
67
|
import * as i1$9 from '@angular/material/button-toggle';
|
|
66
68
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
67
69
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -79,10 +81,10 @@ import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
|
|
|
79
81
|
import Duration from 'duration-relativetimeformat';
|
|
80
82
|
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
|
|
81
83
|
import { trigger, transition, animate, keyframes, style } from '@angular/animations';
|
|
82
|
-
import * as
|
|
83
|
-
import {
|
|
84
|
-
import
|
|
85
|
-
import
|
|
84
|
+
import * as duckdb from '@duckdb/duckdb-wasm';
|
|
85
|
+
import { Vector, DataType } from 'apache-arrow';
|
|
86
|
+
import WFS from 'ol/format/WFS';
|
|
87
|
+
import GeoJSON$1 from 'ol/format/GeoJSON';
|
|
86
88
|
import { Chart, BarController, BarElement, CategoryScale, LinearScale, LineController, LineElement, PointElement, PieController, ArcElement, ScatterController, Tooltip, Colors, Legend } from 'chart.js';
|
|
87
89
|
import * as i2$4 from '@angular/material/sort';
|
|
88
90
|
import { MatSortModule, MatSort } from '@angular/material/sort';
|
|
@@ -90,7 +92,6 @@ import * as i1$b from '@angular/material/table';
|
|
|
90
92
|
import { MatTableModule } from '@angular/material/table';
|
|
91
93
|
import * as i3 from '@angular/material/paginator';
|
|
92
94
|
import { MatPaginatorIntl, MatPaginatorModule, MatPaginator } from '@angular/material/paginator';
|
|
93
|
-
import { LetDirective } from '@ngrx/component';
|
|
94
95
|
import { Meta } from '@angular/platform-browser';
|
|
95
96
|
import { tablerFolderOpen } from '@ng-icons/tabler-icons';
|
|
96
97
|
import * as i3$1 from '@angular/material/radio';
|
|
@@ -674,6 +675,149 @@ function matchMimeType(format) {
|
|
|
674
675
|
return format || null;
|
|
675
676
|
}
|
|
676
677
|
|
|
678
|
+
const RoleValues = [
|
|
679
|
+
'unspecified',
|
|
680
|
+
'other',
|
|
681
|
+
'author', // Party who authored the resource
|
|
682
|
+
'collaborator', // party who assists with the generation of the resource other than the principal investigator
|
|
683
|
+
'contributor', // party contributing to the resource
|
|
684
|
+
'custodian', // Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource
|
|
685
|
+
'distributor', // Party who distributes the resource
|
|
686
|
+
'editor', // party who reviewed or modified the resource to improve the content
|
|
687
|
+
'funder', // party providing monetary support for the resource
|
|
688
|
+
'mediator', // a class of entity that mediates access to the resource and for whom the resource is intended or useful
|
|
689
|
+
'originator', // Party who created the resource
|
|
690
|
+
'owner', // Party that owns the resource
|
|
691
|
+
'point_of_contact', // Party who can be contacted for acquiring knowledge about or acquisition of the resource
|
|
692
|
+
'principal_investigator', // Key party responsible for gathering information and conducting research
|
|
693
|
+
'processor', // Party who has processed the data in a manner such that the resource has been modified
|
|
694
|
+
'publisher', // Party who published the resource
|
|
695
|
+
'resource_provider', // Party that supplies the resource
|
|
696
|
+
'rights_holder', // party owning or managing rights over the resource
|
|
697
|
+
'sponsor', // party that sponsors the resource
|
|
698
|
+
'stakeholder', // party who has an interest in the resource or the use of the resource
|
|
699
|
+
'user', // Party who uses the resource
|
|
700
|
+
];
|
|
701
|
+
const RoleLabels = new Map([
|
|
702
|
+
['unspecified', marker('domain.contact.role.unspecified')],
|
|
703
|
+
['other', marker('domain.contact.role.other')],
|
|
704
|
+
['author', marker('domain.contact.role.author')],
|
|
705
|
+
['collaborator', marker('domain.contact.role.collaborator')],
|
|
706
|
+
['contributor', marker('domain.contact.role.contributor')],
|
|
707
|
+
['custodian', marker('domain.contact.role.custodian')],
|
|
708
|
+
['distributor', marker('domain.contact.role.distributor')],
|
|
709
|
+
['editor', marker('domain.contact.role.editor')],
|
|
710
|
+
['funder', marker('domain.contact.role.funder')],
|
|
711
|
+
['mediator', marker('domain.contact.role.mediator')],
|
|
712
|
+
['originator', marker('domain.contact.role.originator')],
|
|
713
|
+
['owner', marker('domain.contact.role.owner')],
|
|
714
|
+
['point_of_contact', marker('domain.contact.role.point_of_contact')],
|
|
715
|
+
[
|
|
716
|
+
'principal_investigator',
|
|
717
|
+
marker('domain.contact.role.principal_investigator'),
|
|
718
|
+
],
|
|
719
|
+
['processor', marker('domain.contact.role.processor')],
|
|
720
|
+
['publisher', marker('domain.contact.role.publisher')],
|
|
721
|
+
['resource_provider', marker('domain.contact.role.resource_provider')],
|
|
722
|
+
['rights_holder', marker('domain.contact.role.rights_holder')],
|
|
723
|
+
['sponsor', marker('domain.contact.role.sponsor')],
|
|
724
|
+
['stakeholder', marker('domain.contact.role.stakeholder')],
|
|
725
|
+
['user', marker('domain.contact.role.user')],
|
|
726
|
+
]);
|
|
727
|
+
|
|
728
|
+
marker('domain.record.updateFrequency.unknown');
|
|
729
|
+
marker('domain.record.updateFrequency.notPlanned');
|
|
730
|
+
marker('domain.record.updateFrequency.asNeeded');
|
|
731
|
+
marker('domain.record.updateFrequency.irregular');
|
|
732
|
+
marker('domain.record.updateFrequency.continual');
|
|
733
|
+
marker('domain.record.updateFrequency.periodic');
|
|
734
|
+
const updateFrequencyCodeValues = [
|
|
735
|
+
'unknown',
|
|
736
|
+
'notPlanned',
|
|
737
|
+
'asNeeded',
|
|
738
|
+
'irregular',
|
|
739
|
+
'continual',
|
|
740
|
+
'periodic',
|
|
741
|
+
'daily',
|
|
742
|
+
'weekly',
|
|
743
|
+
'fortnightly',
|
|
744
|
+
'semimonthly',
|
|
745
|
+
'monthly',
|
|
746
|
+
'quarterly',
|
|
747
|
+
'biannually',
|
|
748
|
+
'annually',
|
|
749
|
+
'biennially',
|
|
750
|
+
];
|
|
751
|
+
marker('domain.record.updateFrequency.day');
|
|
752
|
+
marker('domain.record.updateFrequency.week');
|
|
753
|
+
marker('domain.record.updateFrequency.month');
|
|
754
|
+
marker('domain.record.updateFrequency.year');
|
|
755
|
+
marker('domain.record.updateFrequency.daily');
|
|
756
|
+
marker('domain.record.updateFrequency.weekly');
|
|
757
|
+
marker('domain.record.updateFrequency.fortnightly');
|
|
758
|
+
marker('domain.record.updateFrequency.monthly');
|
|
759
|
+
marker('domain.record.updateFrequency.quarterly');
|
|
760
|
+
marker('domain.record.updateFrequency.biannually');
|
|
761
|
+
marker('domain.record.updateFrequency.annually');
|
|
762
|
+
marker('domain.record.updateFrequency.semimonthly');
|
|
763
|
+
marker('domain.record.updateFrequency.biennially');
|
|
764
|
+
marker('domain.record.status.completed');
|
|
765
|
+
marker('domain.record.status.ongoing');
|
|
766
|
+
marker('domain.record.status.under_development');
|
|
767
|
+
marker('domain.record.status.deprecated');
|
|
768
|
+
marker('domain.record.status.removed');
|
|
769
|
+
marker('domain.record.status.planned');
|
|
770
|
+
marker('domain.record.status.required');
|
|
771
|
+
const RecordStatusValues = [
|
|
772
|
+
'completed',
|
|
773
|
+
'ongoing',
|
|
774
|
+
'under_development',
|
|
775
|
+
'deprecated',
|
|
776
|
+
'removed',
|
|
777
|
+
'planned',
|
|
778
|
+
'required',
|
|
779
|
+
];
|
|
780
|
+
marker('record.metadata.api.accessServiceProtocol.wms');
|
|
781
|
+
marker('record.metadata.api.accessServiceProtocol.wfs');
|
|
782
|
+
marker('record.metadata.api.accessServiceProtocol.wps');
|
|
783
|
+
marker('record.metadata.api.accessServiceProtocol.wmts');
|
|
784
|
+
marker('record.metadata.api.accessServiceProtocol.esriRest');
|
|
785
|
+
marker('record.metadata.api.accessServiceProtocol.ogcFeatures');
|
|
786
|
+
marker('record.metadata.api.accessServiceProtocol.GPFDL');
|
|
787
|
+
marker('record.metadata.api.accessServiceProtocol.tms');
|
|
788
|
+
marker('record.metadata.api.accessServiceProtocol.maplibre-style');
|
|
789
|
+
marker('record.metadata.api.accessServiceProtocol.postgis');
|
|
790
|
+
marker('record.metadata.api.accessServiceProtocol.stac');
|
|
791
|
+
marker('record.metadata.api.accessServiceProtocol.other');
|
|
792
|
+
marker('domain.record.associationType.crossReference');
|
|
793
|
+
marker('domain.record.associationType.largerWorkCitation');
|
|
794
|
+
marker('domain.record.associationType.partOfSeamlessDatabase');
|
|
795
|
+
marker('domain.record.associationType.stereoMate');
|
|
796
|
+
marker('domain.record.associationType.isComposedOf');
|
|
797
|
+
marker('domain.record.associationType.collectiveTitle');
|
|
798
|
+
marker('domain.record.associationType.series');
|
|
799
|
+
marker('domain.record.associationType.dependency');
|
|
800
|
+
marker('domain.record.associationType.revisionOf');
|
|
801
|
+
// DS_AssociationTypeCode values of the ISO19115-3 codelist, any unrecognized value
|
|
802
|
+
// being mapped to 'crossReference'
|
|
803
|
+
const associationTypeValues = [
|
|
804
|
+
'crossReference',
|
|
805
|
+
'largerWorkCitation',
|
|
806
|
+
'partOfSeamlessDatabase',
|
|
807
|
+
'stereoMate',
|
|
808
|
+
'isComposedOf',
|
|
809
|
+
'collectiveTitle',
|
|
810
|
+
'series',
|
|
811
|
+
'dependency',
|
|
812
|
+
'revisionOf',
|
|
813
|
+
];
|
|
814
|
+
|
|
815
|
+
function getAssociationTypeFromCode(associationTypeCode) {
|
|
816
|
+
return associationTypeValues.includes(associationTypeCode)
|
|
817
|
+
? associationTypeCode
|
|
818
|
+
: 'crossReference';
|
|
819
|
+
}
|
|
820
|
+
|
|
677
821
|
function readGeometry(el) {
|
|
678
822
|
const xmlDoc = createDocument(el);
|
|
679
823
|
xmlDoc.root.attributes['xmlns'] = 'http://www.opengis.net/gml/3.2';
|
|
@@ -802,121 +946,6 @@ function getStatusFromStatusCode(statusCode) {
|
|
|
802
946
|
}
|
|
803
947
|
}
|
|
804
948
|
|
|
805
|
-
const RoleValues = [
|
|
806
|
-
'unspecified',
|
|
807
|
-
'other',
|
|
808
|
-
'author', // Party who authored the resource
|
|
809
|
-
'collaborator', // party who assists with the generation of the resource other than the principal investigator
|
|
810
|
-
'contributor', // party contributing to the resource
|
|
811
|
-
'custodian', // Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource
|
|
812
|
-
'distributor', // Party who distributes the resource
|
|
813
|
-
'editor', // party who reviewed or modified the resource to improve the content
|
|
814
|
-
'funder', // party providing monetary support for the resource
|
|
815
|
-
'mediator', // a class of entity that mediates access to the resource and for whom the resource is intended or useful
|
|
816
|
-
'originator', // Party who created the resource
|
|
817
|
-
'owner', // Party that owns the resource
|
|
818
|
-
'point_of_contact', // Party who can be contacted for acquiring knowledge about or acquisition of the resource
|
|
819
|
-
'principal_investigator', // Key party responsible for gathering information and conducting research
|
|
820
|
-
'processor', // Party who has processed the data in a manner such that the resource has been modified
|
|
821
|
-
'publisher', // Party who published the resource
|
|
822
|
-
'resource_provider', // Party that supplies the resource
|
|
823
|
-
'rights_holder', // party owning or managing rights over the resource
|
|
824
|
-
'sponsor', // party that sponsors the resource
|
|
825
|
-
'stakeholder', // party who has an interest in the resource or the use of the resource
|
|
826
|
-
'user', // Party who uses the resource
|
|
827
|
-
];
|
|
828
|
-
const RoleLabels = new Map([
|
|
829
|
-
['unspecified', marker('domain.contact.role.unspecified')],
|
|
830
|
-
['other', marker('domain.contact.role.other')],
|
|
831
|
-
['author', marker('domain.contact.role.author')],
|
|
832
|
-
['collaborator', marker('domain.contact.role.collaborator')],
|
|
833
|
-
['contributor', marker('domain.contact.role.contributor')],
|
|
834
|
-
['custodian', marker('domain.contact.role.custodian')],
|
|
835
|
-
['distributor', marker('domain.contact.role.distributor')],
|
|
836
|
-
['editor', marker('domain.contact.role.editor')],
|
|
837
|
-
['funder', marker('domain.contact.role.funder')],
|
|
838
|
-
['mediator', marker('domain.contact.role.mediator')],
|
|
839
|
-
['originator', marker('domain.contact.role.originator')],
|
|
840
|
-
['owner', marker('domain.contact.role.owner')],
|
|
841
|
-
['point_of_contact', marker('domain.contact.role.point_of_contact')],
|
|
842
|
-
[
|
|
843
|
-
'principal_investigator',
|
|
844
|
-
marker('domain.contact.role.principal_investigator'),
|
|
845
|
-
],
|
|
846
|
-
['processor', marker('domain.contact.role.processor')],
|
|
847
|
-
['publisher', marker('domain.contact.role.publisher')],
|
|
848
|
-
['resource_provider', marker('domain.contact.role.resource_provider')],
|
|
849
|
-
['rights_holder', marker('domain.contact.role.rights_holder')],
|
|
850
|
-
['sponsor', marker('domain.contact.role.sponsor')],
|
|
851
|
-
['stakeholder', marker('domain.contact.role.stakeholder')],
|
|
852
|
-
['user', marker('domain.contact.role.user')],
|
|
853
|
-
]);
|
|
854
|
-
|
|
855
|
-
marker('domain.record.updateFrequency.unknown');
|
|
856
|
-
marker('domain.record.updateFrequency.notPlanned');
|
|
857
|
-
marker('domain.record.updateFrequency.asNeeded');
|
|
858
|
-
marker('domain.record.updateFrequency.irregular');
|
|
859
|
-
marker('domain.record.updateFrequency.continual');
|
|
860
|
-
marker('domain.record.updateFrequency.periodic');
|
|
861
|
-
const updateFrequencyCodeValues = [
|
|
862
|
-
'unknown',
|
|
863
|
-
'notPlanned',
|
|
864
|
-
'asNeeded',
|
|
865
|
-
'irregular',
|
|
866
|
-
'continual',
|
|
867
|
-
'periodic',
|
|
868
|
-
'daily',
|
|
869
|
-
'weekly',
|
|
870
|
-
'fortnightly',
|
|
871
|
-
'semimonthly',
|
|
872
|
-
'monthly',
|
|
873
|
-
'quarterly',
|
|
874
|
-
'biannually',
|
|
875
|
-
'annually',
|
|
876
|
-
'biennially',
|
|
877
|
-
];
|
|
878
|
-
marker('domain.record.updateFrequency.day');
|
|
879
|
-
marker('domain.record.updateFrequency.week');
|
|
880
|
-
marker('domain.record.updateFrequency.month');
|
|
881
|
-
marker('domain.record.updateFrequency.year');
|
|
882
|
-
marker('domain.record.updateFrequency.daily');
|
|
883
|
-
marker('domain.record.updateFrequency.weekly');
|
|
884
|
-
marker('domain.record.updateFrequency.fortnightly');
|
|
885
|
-
marker('domain.record.updateFrequency.monthly');
|
|
886
|
-
marker('domain.record.updateFrequency.quarterly');
|
|
887
|
-
marker('domain.record.updateFrequency.biannually');
|
|
888
|
-
marker('domain.record.updateFrequency.annually');
|
|
889
|
-
marker('domain.record.updateFrequency.semimonthly');
|
|
890
|
-
marker('domain.record.updateFrequency.biennially');
|
|
891
|
-
marker('domain.record.status.completed');
|
|
892
|
-
marker('domain.record.status.ongoing');
|
|
893
|
-
marker('domain.record.status.under_development');
|
|
894
|
-
marker('domain.record.status.deprecated');
|
|
895
|
-
marker('domain.record.status.removed');
|
|
896
|
-
marker('domain.record.status.planned');
|
|
897
|
-
marker('domain.record.status.required');
|
|
898
|
-
const RecordStatusValues = [
|
|
899
|
-
'completed',
|
|
900
|
-
'ongoing',
|
|
901
|
-
'under_development',
|
|
902
|
-
'deprecated',
|
|
903
|
-
'removed',
|
|
904
|
-
'planned',
|
|
905
|
-
'required',
|
|
906
|
-
];
|
|
907
|
-
marker('record.metadata.api.accessServiceProtocol.wms');
|
|
908
|
-
marker('record.metadata.api.accessServiceProtocol.wfs');
|
|
909
|
-
marker('record.metadata.api.accessServiceProtocol.wps');
|
|
910
|
-
marker('record.metadata.api.accessServiceProtocol.wmts');
|
|
911
|
-
marker('record.metadata.api.accessServiceProtocol.esriRest');
|
|
912
|
-
marker('record.metadata.api.accessServiceProtocol.ogcFeatures');
|
|
913
|
-
marker('record.metadata.api.accessServiceProtocol.GPFDL');
|
|
914
|
-
marker('record.metadata.api.accessServiceProtocol.tms');
|
|
915
|
-
marker('record.metadata.api.accessServiceProtocol.maplibre-style');
|
|
916
|
-
marker('record.metadata.api.accessServiceProtocol.postgis');
|
|
917
|
-
marker('record.metadata.api.accessServiceProtocol.stac');
|
|
918
|
-
marker('record.metadata.api.accessServiceProtocol.other');
|
|
919
|
-
|
|
920
949
|
function getUpdateFrequencyFromFrequencyCode(frequencyCode) {
|
|
921
950
|
return frequencyCode &&
|
|
922
951
|
updateFrequencyCodeValues.includes(frequencyCode)
|
|
@@ -1484,14 +1513,17 @@ function extractSourceRecords(liLineageEl) {
|
|
|
1484
1513
|
function readSourceRecords$1(rootEl) {
|
|
1485
1514
|
return extractSourceRecords(pipe(findNestedElement('gmd:dataQualityInfo', 'gmd:DQ_DataQuality', 'gmd:lineage', 'gmd:LI_Lineage'))(rootEl));
|
|
1486
1515
|
}
|
|
1487
|
-
function extractAssociatedRecords(containerName, aggregateName,
|
|
1516
|
+
function extractAssociatedRecords(containerName, aggregateName, readIdentifier) {
|
|
1488
1517
|
return pipe(findChildrenElement(containerName, false), mapArray((el) => {
|
|
1489
1518
|
const aggregateEl = findChildElement(aggregateName, false)(el);
|
|
1490
|
-
const
|
|
1491
|
-
const
|
|
1492
|
-
if (!
|
|
1519
|
+
const uniqueIdentifier = readIdentifier(aggregateEl);
|
|
1520
|
+
const associationTypeCode = pipe(findNestedElement('gmd:associationType', 'gmd:DS_AssociationTypeCode'), readAttribute('codeListValue'))(aggregateEl);
|
|
1521
|
+
if (!uniqueIdentifier || !associationTypeCode)
|
|
1493
1522
|
return null;
|
|
1494
|
-
return {
|
|
1523
|
+
return {
|
|
1524
|
+
uniqueIdentifier,
|
|
1525
|
+
associationType: getAssociationTypeFromCode(associationTypeCode),
|
|
1526
|
+
};
|
|
1495
1527
|
}), filterArray((r) => r !== null));
|
|
1496
1528
|
}
|
|
1497
1529
|
function readAssociatedRecords$1(rootEl) {
|
|
@@ -2039,8 +2071,8 @@ function writeSourceRecords$1(record, rootEl) {
|
|
|
2039
2071
|
}
|
|
2040
2072
|
function writeAssociatedRecords$1(record, rootEl) {
|
|
2041
2073
|
pipe(findOrCreateIdentification(), removeChildrenByName('gmd:aggregationInfo'), appendChildren(...record.associatedRecords
|
|
2042
|
-
.filter((assoc) => assoc.
|
|
2043
|
-
.map((assoc) => pipe(createNestedElement('gmd:aggregationInfo', 'gmd:MD_AggregateInformation'), appendChildren(pipe(createNestedElement('gmd:aggregateDataSetIdentifier', 'gmd:MD_Identifier', 'gmd:code'), writeCharacterString(assoc.
|
|
2074
|
+
.filter((assoc) => assoc.uniqueIdentifier && assoc.associationType)
|
|
2075
|
+
.map((assoc) => pipe(createNestedElement('gmd:aggregationInfo', 'gmd:MD_AggregateInformation'), appendChildren(pipe(createNestedElement('gmd:aggregateDataSetIdentifier', 'gmd:MD_Identifier', 'gmd:code'), writeCharacterString(assoc.uniqueIdentifier)), pipe(createNestedElement('gmd:associationType', 'gmd:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)))))))(rootEl);
|
|
2044
2076
|
}
|
|
2045
2077
|
function getServiceEndpointProtocol(endpoint) {
|
|
2046
2078
|
switch (endpoint.accessServiceProtocol.toLowerCase()) {
|
|
@@ -2752,8 +2784,8 @@ function writeSourceRecords(record, rootEl) {
|
|
|
2752
2784
|
}
|
|
2753
2785
|
function writeAssociatedRecords(record, rootEl) {
|
|
2754
2786
|
pipe(findOrCreateIdentification(), removeChildrenByName('mri:associatedResource'), appendChildren(...record.associatedRecords
|
|
2755
|
-
.filter((assoc) => assoc.
|
|
2756
|
-
.map((assoc) => pipe(createNestedElement('mri:associatedResource', 'mri:MD_AssociatedResource'), appendChildren(pipe(createNestedElement('mri:associationType', 'mri:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)), pipe(createElement('mri:metadataReference'), writeAttribute('uuidref', assoc.
|
|
2787
|
+
.filter((assoc) => assoc.uniqueIdentifier && assoc.associationType)
|
|
2788
|
+
.map((assoc) => pipe(createNestedElement('mri:associatedResource', 'mri:MD_AssociatedResource'), appendChildren(pipe(createNestedElement('mri:associationType', 'mri:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)), pipe(createElement('mri:metadataReference'), writeAttribute('uuidref', assoc.uniqueIdentifier)))))))(rootEl);
|
|
2757
2789
|
}
|
|
2758
2790
|
|
|
2759
2791
|
class Iso191153Converter extends Iso19139Converter {
|
|
@@ -18876,14 +18908,29 @@ class Gn4FieldMapper {
|
|
|
18876
18908
|
featureTypes: selectField(source, 'featureTypes'),
|
|
18877
18909
|
}, output),
|
|
18878
18910
|
related: (output, source) => {
|
|
18879
|
-
const
|
|
18911
|
+
const related = selectField(source, 'related');
|
|
18912
|
+
const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
|
|
18880
18913
|
const featureCatalogIdentifier = selectField(fcatSource, 'uuid');
|
|
18881
|
-
const sourceOfLinks = getAsArray(selectField(
|
|
18914
|
+
const sourceOfLinks = getAsArray(selectField(related, 'hassources'));
|
|
18882
18915
|
const sourceOfIdentifiers = sourceOfLinks
|
|
18883
18916
|
.filter((link) => link['origin'] === 'catalog')
|
|
18884
18917
|
.map((link) => {
|
|
18885
18918
|
return selectField(selectField(link, '_source'), 'uuid');
|
|
18886
18919
|
});
|
|
18920
|
+
const siblingLinks = getAsArray(selectField(related, 'siblings'));
|
|
18921
|
+
const siblings = siblingLinks
|
|
18922
|
+
.filter((link) => link['origin'] === 'catalog')
|
|
18923
|
+
.map((link) => ({
|
|
18924
|
+
uniqueIdentifier: selectField(selectField(link, '_source'), 'uuid'),
|
|
18925
|
+
associationType: getAssociationTypeFromCode(selectField(selectField(link, 'properties'), 'associationType')),
|
|
18926
|
+
}));
|
|
18927
|
+
const associatedLinks = getAsArray(selectField(related, 'associated'));
|
|
18928
|
+
const associatedIdentifiers = associatedLinks
|
|
18929
|
+
.filter((link) => link['origin'] === 'catalog')
|
|
18930
|
+
.map((link) => {
|
|
18931
|
+
return selectField(selectField(link, '_source'), 'uuid');
|
|
18932
|
+
})
|
|
18933
|
+
.filter((uuid) => !siblings.some((sibling) => sibling.uniqueIdentifier === uuid));
|
|
18887
18934
|
const extraValues = {};
|
|
18888
18935
|
if (featureCatalogIdentifier) {
|
|
18889
18936
|
extraValues.featureCatalogIdentifier = featureCatalogIdentifier;
|
|
@@ -18891,6 +18938,12 @@ class Gn4FieldMapper {
|
|
|
18891
18938
|
if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
|
|
18892
18939
|
extraValues.sourceOfIdentifiers = sourceOfIdentifiers;
|
|
18893
18940
|
}
|
|
18941
|
+
if (associatedIdentifiers && associatedIdentifiers.length > 0) {
|
|
18942
|
+
extraValues.associatedIdentifiers = associatedIdentifiers;
|
|
18943
|
+
}
|
|
18944
|
+
if (siblings && siblings.length > 0) {
|
|
18945
|
+
extraValues.siblings = siblings;
|
|
18946
|
+
}
|
|
18894
18947
|
return Object.keys(extraValues).length > 0
|
|
18895
18948
|
? this.addExtra(extraValues, output)
|
|
18896
18949
|
: output;
|
|
@@ -19416,10 +19469,10 @@ class DateService {
|
|
|
19416
19469
|
const dateObj = this.getDateObject(date);
|
|
19417
19470
|
return { locale, dateObj };
|
|
19418
19471
|
}
|
|
19419
|
-
async
|
|
19472
|
+
async getDateFnsLocale() {
|
|
19420
19473
|
const lang = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE;
|
|
19421
19474
|
const locales = await this.dateLocales;
|
|
19422
|
-
return locales[lang];
|
|
19475
|
+
return locales[lang] ?? locales[DEFAULT_LANGUAGE];
|
|
19423
19476
|
}
|
|
19424
19477
|
formatDate(date, options) {
|
|
19425
19478
|
const { locale, dateObj } = this.getLocaleAndDate(date);
|
|
@@ -19432,7 +19485,7 @@ class DateService {
|
|
|
19432
19485
|
async formatRelativeDateTime(date) {
|
|
19433
19486
|
const dateObj = this.getDateObject(date);
|
|
19434
19487
|
const now = new Date();
|
|
19435
|
-
const locale = await this.
|
|
19488
|
+
const locale = await this.getDateFnsLocale();
|
|
19436
19489
|
return formatDistance(dateObj, now, {
|
|
19437
19490
|
addSuffix: true,
|
|
19438
19491
|
locale: locale,
|
|
@@ -19467,6 +19520,18 @@ function propagateToDocumentOnly(event) {
|
|
|
19467
19520
|
}, 0);
|
|
19468
19521
|
}
|
|
19469
19522
|
|
|
19523
|
+
function isFileExtensionValid(fileName, acceptedExtensions) {
|
|
19524
|
+
return acceptedExtensions.some((ext) => fileName.toLowerCase().endsWith(ext));
|
|
19525
|
+
}
|
|
19526
|
+
function readFileAsText(file) {
|
|
19527
|
+
return new Promise((resolve, reject) => {
|
|
19528
|
+
const reader = new FileReader();
|
|
19529
|
+
reader.onload = () => resolve(reader.result);
|
|
19530
|
+
reader.onerror = () => reject(reader.error);
|
|
19531
|
+
reader.readAsText(file);
|
|
19532
|
+
});
|
|
19533
|
+
}
|
|
19534
|
+
|
|
19470
19535
|
function formatUserInfo(userInfo, displayCount = false) {
|
|
19471
19536
|
const infos = (typeof userInfo === 'string' ? userInfo : '').split('|');
|
|
19472
19537
|
const count = displayCount ? ` ${infos[3].split(' ')[1]}` : '';
|
|
@@ -19526,6 +19591,11 @@ function getGeometryFromGeoJSON(data) {
|
|
|
19526
19591
|
}
|
|
19527
19592
|
return null;
|
|
19528
19593
|
}
|
|
19594
|
+
function isBoundingBox(value) {
|
|
19595
|
+
return (Array.isArray(value) &&
|
|
19596
|
+
value.length === 4 &&
|
|
19597
|
+
value.every((item) => typeof item === 'number'));
|
|
19598
|
+
}
|
|
19529
19599
|
function getGeometryBoundingBox(geometry) {
|
|
19530
19600
|
// use the bounding box if specified in the GeoJSON object
|
|
19531
19601
|
if (geometry.bbox) {
|
|
@@ -20311,6 +20381,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20311
20381
|
}]
|
|
20312
20382
|
}] });
|
|
20313
20383
|
|
|
20384
|
+
class AutofocusDirective {
|
|
20385
|
+
constructor() {
|
|
20386
|
+
this.el = inject(ElementRef);
|
|
20387
|
+
this.injector = inject(Injector);
|
|
20388
|
+
}
|
|
20389
|
+
set autofocus(active) {
|
|
20390
|
+
if (!active)
|
|
20391
|
+
return;
|
|
20392
|
+
afterNextRender(() => this.el.nativeElement.focus(), {
|
|
20393
|
+
injector: this.injector,
|
|
20394
|
+
});
|
|
20395
|
+
}
|
|
20396
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
20397
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.19", type: AutofocusDirective, isStandalone: true, selector: "[gnUiAutofocus]", inputs: { autofocus: ["gnUiAutofocus", "autofocus", booleanAttribute] }, ngImport: i0 }); }
|
|
20398
|
+
}
|
|
20399
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutofocusDirective, decorators: [{
|
|
20400
|
+
type: Directive,
|
|
20401
|
+
args: [{
|
|
20402
|
+
selector: '[gnUiAutofocus]',
|
|
20403
|
+
standalone: true,
|
|
20404
|
+
}]
|
|
20405
|
+
}], propDecorators: { autofocus: [{
|
|
20406
|
+
type: Input,
|
|
20407
|
+
args: [{ alias: 'gnUiAutofocus', transform: booleanAttribute }]
|
|
20408
|
+
}] } });
|
|
20409
|
+
|
|
20314
20410
|
class ImageFallbackDirective {
|
|
20315
20411
|
constructor() {
|
|
20316
20412
|
this.el = inject(ElementRef);
|
|
@@ -20338,7 +20434,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
20338
20434
|
}] } });
|
|
20339
20435
|
|
|
20340
20436
|
var name = "geonetwork-ui";
|
|
20341
|
-
var version = "2.
|
|
20437
|
+
var version = "2.11.0-dev.4976ded4f";
|
|
20342
20438
|
var engines = {
|
|
20343
20439
|
node: ">=24"
|
|
20344
20440
|
};
|
|
@@ -20377,11 +20473,12 @@ var peerDependencies = {
|
|
|
20377
20473
|
};
|
|
20378
20474
|
var dependencies = {
|
|
20379
20475
|
"@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/
|
|
20476
|
+
"@camptocamp/ogc-client": "1.3.1-dev.200c02a",
|
|
20477
|
+
"@duckdb/duckdb-wasm": "~1.32.0",
|
|
20478
|
+
"@geospatial-sdk/core": "0.0.5-dev.78",
|
|
20479
|
+
"@geospatial-sdk/geocoding": "0.0.5-dev.78",
|
|
20480
|
+
"@geospatial-sdk/legend": "0.0.5-dev.78",
|
|
20481
|
+
"@geospatial-sdk/openlayers": "0.0.5-dev.78",
|
|
20385
20482
|
"@ltd/j-toml": "~1.38.0",
|
|
20386
20483
|
"@messageformat/core": "~3.4.0",
|
|
20387
20484
|
"@ng-icons/core": "~32.5.0",
|
|
@@ -20389,7 +20486,7 @@ var dependencies = {
|
|
|
20389
20486
|
"@ng-icons/material-icons": "~32.5.0",
|
|
20390
20487
|
"@ng-icons/tabler-icons": "~32.4.0",
|
|
20391
20488
|
"@rgrove/parse-xml": "4.2.0",
|
|
20392
|
-
|
|
20489
|
+
"apache-arrow": "~17.0.0",
|
|
20393
20490
|
"chart.js": "~4.5.1",
|
|
20394
20491
|
"chroma-js": "~3.2.0",
|
|
20395
20492
|
"date-fns": "4.1.0",
|
|
@@ -20402,7 +20499,6 @@ var dependencies = {
|
|
|
20402
20499
|
"ngx-dropzone": "~3.1.0",
|
|
20403
20500
|
"ngx-translate-messageformat-compiler": "~7.2.0",
|
|
20404
20501
|
ol: "~10.8.0",
|
|
20405
|
-
papaparse: "~5.5.3",
|
|
20406
20502
|
proj4: "~2.20.4",
|
|
20407
20503
|
rdflib: "~2.3.5",
|
|
20408
20504
|
semver: "~7.7.4",
|
|
@@ -20424,7 +20520,7 @@ var packageJson = {
|
|
|
20424
20520
|
|
|
20425
20521
|
const GEONETWORK_UI_VERSION = packageJson.version;
|
|
20426
20522
|
const GEONETWORK_UI_TAG_NAME = GEONETWORK_UI_VERSION.split('-')[1]?.startsWith('dev')
|
|
20427
|
-
? '
|
|
20523
|
+
? 'main'
|
|
20428
20524
|
: `v${packageJson.version}`;
|
|
20429
20525
|
|
|
20430
20526
|
const ValidatorMapper = {
|
|
@@ -20647,6 +20743,7 @@ class ElasticsearchService {
|
|
|
20647
20743
|
values: uuids,
|
|
20648
20744
|
},
|
|
20649
20745
|
},
|
|
20746
|
+
size: uuids.length,
|
|
20650
20747
|
};
|
|
20651
20748
|
}
|
|
20652
20749
|
getRelatedRecordPayload(record, size = 6, _source = [...ES_SOURCE_SUMMARY, 'createDate']) {
|
|
@@ -20697,10 +20794,28 @@ class ElasticsearchService {
|
|
|
20697
20794
|
};
|
|
20698
20795
|
}
|
|
20699
20796
|
buildPayloadSort(sortBy) {
|
|
20700
|
-
if (sortBy ===
|
|
20797
|
+
if (!sortBy || sortBy.length === 0)
|
|
20701
20798
|
return undefined;
|
|
20702
|
-
const fields = Array.isArray(sortBy[0])
|
|
20703
|
-
|
|
20799
|
+
const fields = Array.isArray(sortBy[0])
|
|
20800
|
+
? sortBy
|
|
20801
|
+
: [sortBy];
|
|
20802
|
+
return fields.map((field) => {
|
|
20803
|
+
// Sort by nested array of dates only works with the explicit syntax
|
|
20804
|
+
if (field[1].endsWith('.date')) {
|
|
20805
|
+
const nestedPath = field[1].slice(0, field[1].lastIndexOf('.date'));
|
|
20806
|
+
return {
|
|
20807
|
+
[field[1]]: {
|
|
20808
|
+
order: field[0],
|
|
20809
|
+
mode: field[0] === 'desc' ? 'max' : 'min',
|
|
20810
|
+
missing: '_last',
|
|
20811
|
+
nested: {
|
|
20812
|
+
path: nestedPath,
|
|
20813
|
+
},
|
|
20814
|
+
},
|
|
20815
|
+
};
|
|
20816
|
+
}
|
|
20817
|
+
return { [field[1]]: field[0] };
|
|
20818
|
+
});
|
|
20704
20819
|
}
|
|
20705
20820
|
injectLangInQueryStringFields(queryFieldsPriority) {
|
|
20706
20821
|
const queryLang = this.getQueryLang();
|
|
@@ -20736,7 +20851,13 @@ class ElasticsearchService {
|
|
|
20736
20851
|
isCurrentSearchLang() {
|
|
20737
20852
|
return this.metadataLang === 'current';
|
|
20738
20853
|
}
|
|
20739
|
-
|
|
20854
|
+
findSpatialFilterExtent(filters) {
|
|
20855
|
+
if (typeof filters === 'string') {
|
|
20856
|
+
return undefined;
|
|
20857
|
+
}
|
|
20858
|
+
return Object.values(filters).find(isBoundingBox);
|
|
20859
|
+
}
|
|
20860
|
+
filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
|
|
20740
20861
|
const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
|
|
20741
20862
|
const makeQuery = (filter) => {
|
|
20742
20863
|
if (typeof filter === 'string') {
|
|
@@ -20755,7 +20876,9 @@ class ElasticsearchService {
|
|
|
20755
20876
|
? filters
|
|
20756
20877
|
: Object.keys(filters)
|
|
20757
20878
|
.filter((fieldname) => fieldname !== 'gn-ui-crossFieldFilter')
|
|
20879
|
+
.filter((fieldname) => !isBoundingBox(filters[fieldname]))
|
|
20758
20880
|
.filter((fieldname) => !isDateRange(filters[fieldname]))
|
|
20881
|
+
.filter((fieldname) => !Array.isArray(filters[fieldname]))
|
|
20759
20882
|
.filter((fieldname) => filters[fieldname] &&
|
|
20760
20883
|
JSON.stringify(filters[fieldname]) !== '{}')
|
|
20761
20884
|
.map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
|
|
@@ -20791,6 +20914,21 @@ class ElasticsearchService {
|
|
|
20791
20914
|
},
|
|
20792
20915
|
},
|
|
20793
20916
|
},
|
|
20917
|
+
spatialFilterExtent && {
|
|
20918
|
+
geo_shape: {
|
|
20919
|
+
geom: {
|
|
20920
|
+
shape: {
|
|
20921
|
+
type: 'envelope',
|
|
20922
|
+
// spatialFilterExtent is [minX, minY, maxX, maxY]; envelope coordinates are [top-left, bottom-right]
|
|
20923
|
+
coordinates: [
|
|
20924
|
+
[spatialFilterExtent[0], spatialFilterExtent[3]],
|
|
20925
|
+
[spatialFilterExtent[2], spatialFilterExtent[1]],
|
|
20926
|
+
],
|
|
20927
|
+
},
|
|
20928
|
+
relation: 'intersects',
|
|
20929
|
+
},
|
|
20930
|
+
},
|
|
20931
|
+
},
|
|
20794
20932
|
].filter(Boolean);
|
|
20795
20933
|
return queryParts.length > 0 ? queryParts : undefined;
|
|
20796
20934
|
}
|
|
@@ -20817,7 +20955,9 @@ class ElasticsearchService {
|
|
|
20817
20955
|
},
|
|
20818
20956
|
});
|
|
20819
20957
|
}
|
|
20820
|
-
|
|
20958
|
+
// a spatial extent filter takes precedence over the preference geometry for boosting
|
|
20959
|
+
const spatialFilterExtent = this.findSpatialFilterExtent(fieldSearchFilters);
|
|
20960
|
+
const queryFilters = this.filtersToQuery(fieldSearchFilters, spatialFilterExtent);
|
|
20821
20961
|
if (queryFilters) {
|
|
20822
20962
|
filter.push(...queryFilters);
|
|
20823
20963
|
}
|
|
@@ -20828,7 +20968,10 @@ class ElasticsearchService {
|
|
|
20828
20968
|
},
|
|
20829
20969
|
});
|
|
20830
20970
|
}
|
|
20831
|
-
|
|
20971
|
+
const boostGeometry = spatialFilterExtent
|
|
20972
|
+
? bboxToPolygon(spatialFilterExtent)
|
|
20973
|
+
: geometry;
|
|
20974
|
+
if (boostGeometry) {
|
|
20832
20975
|
// boosts applied using the filter geometry:
|
|
20833
20976
|
// * records completely within the geometry receive a boost of 5
|
|
20834
20977
|
// * records intersecting the geometry receive a boost of 2
|
|
@@ -20837,7 +20980,7 @@ class ElasticsearchService {
|
|
|
20837
20980
|
should.push({
|
|
20838
20981
|
geo_shape: {
|
|
20839
20982
|
geom: {
|
|
20840
|
-
shape:
|
|
20983
|
+
shape: boostGeometry,
|
|
20841
20984
|
relation: 'within',
|
|
20842
20985
|
},
|
|
20843
20986
|
boost: 5.0,
|
|
@@ -20845,7 +20988,7 @@ class ElasticsearchService {
|
|
|
20845
20988
|
}, {
|
|
20846
20989
|
geo_shape: {
|
|
20847
20990
|
geom: {
|
|
20848
|
-
shape:
|
|
20991
|
+
shape: boostGeometry,
|
|
20849
20992
|
relation: 'intersects',
|
|
20850
20993
|
},
|
|
20851
20994
|
boost: 2.0,
|
|
@@ -20854,7 +20997,7 @@ class ElasticsearchService {
|
|
|
20854
20997
|
// this will boost the results variably depending on their distance from the given geometry
|
|
20855
20998
|
// note: this takes into account the `location` field of a record; this is generally the center of all spatial extents
|
|
20856
20999
|
// combined, and thus the actual size/coverage of the record spatial extent isn't relevant here
|
|
20857
|
-
const bbox = getGeometryBoundingBox(
|
|
21000
|
+
const bbox = getGeometryBoundingBox(boostGeometry);
|
|
20858
21001
|
const center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
|
20859
21002
|
const northToCenter = new LineString([
|
|
20860
21003
|
[center[0], bbox[3]],
|
|
@@ -21180,7 +21323,7 @@ class Gn4Repository {
|
|
|
21180
21323
|
}
|
|
21181
21324
|
getRecord(uniqueIdentifier) {
|
|
21182
21325
|
return this.gn4SearchApi
|
|
21183
|
-
.search('bucket', ['fcats', 'hassources'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21326
|
+
.search('bucket', ['fcats', 'hassources', 'siblings', 'associated'], JSON.stringify(this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])))
|
|
21184
21327
|
.pipe(map$1((results) => results.hits.hits[0]), switchMap((record) => record ? this.gn4Mapper.readRecord(record) : of(null)));
|
|
21185
21328
|
}
|
|
21186
21329
|
getMultipleRecords(uniqueIdentifiers) {
|
|
@@ -21234,19 +21377,28 @@ class Gn4Repository {
|
|
|
21234
21377
|
.search('bucket', null, JSON.stringify(this.gn4SearchHelper.getRelatedRecordPayload(similarTo, 3)))
|
|
21235
21378
|
.pipe(switchMap((results) => this.gn4Mapper.readRecords(results.hits.hits)));
|
|
21236
21379
|
}
|
|
21237
|
-
|
|
21238
|
-
const
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
|
|
21245
|
-
|
|
21246
|
-
|
|
21247
|
-
|
|
21380
|
+
getLinkedRecords(record) {
|
|
21381
|
+
const siblings = (record.extras?.['siblings'] ?? []);
|
|
21382
|
+
const relations = [
|
|
21383
|
+
['source', (record.extras?.['sourcesIdentifiers'] ?? [])],
|
|
21384
|
+
['sourceOf', (record.extras?.['sourceOfIdentifiers'] ?? [])],
|
|
21385
|
+
['sibling', siblings.map(({ uniqueIdentifier }) => uniqueIdentifier)],
|
|
21386
|
+
[
|
|
21387
|
+
'associated',
|
|
21388
|
+
(record.extras?.['associatedIdentifiers'] ?? []),
|
|
21389
|
+
],
|
|
21390
|
+
];
|
|
21391
|
+
const requested = relations.filter(([, identifiers]) => identifiers.length > 0);
|
|
21392
|
+
if (requested.length === 0) {
|
|
21393
|
+
return of([]);
|
|
21248
21394
|
}
|
|
21249
|
-
return
|
|
21395
|
+
return forkJoin(requested.map(([relation, identifiers]) => this.getMultipleRecords(identifiers).pipe(map$1((records) => (records ?? []).map((record) => ({
|
|
21396
|
+
record,
|
|
21397
|
+
relation,
|
|
21398
|
+
associationType: relation === 'sibling'
|
|
21399
|
+
? siblings.find(({ uniqueIdentifier }) => uniqueIdentifier === record.uniqueIdentifier)?.associationType
|
|
21400
|
+
: undefined,
|
|
21401
|
+
}))), catchError(() => of([]))))).pipe(map$1((groups) => groups.flat()));
|
|
21250
21402
|
}
|
|
21251
21403
|
aggregate(params) {
|
|
21252
21404
|
// if aggregations are empty, return an empty object right away
|
|
@@ -23225,6 +23377,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23225
23377
|
'search_preset',
|
|
23226
23378
|
'advanced_filters',
|
|
23227
23379
|
'limit',
|
|
23380
|
+
'spatial_extent_max_file_size',
|
|
23228
23381
|
], warnings, errors);
|
|
23229
23382
|
const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
|
|
23230
23383
|
searchConfig =
|
|
@@ -23242,6 +23395,7 @@ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
23242
23395
|
})),
|
|
23243
23396
|
ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
|
|
23244
23397
|
LIMIT: parsedSearchSection.limit,
|
|
23398
|
+
SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
|
|
23245
23399
|
};
|
|
23246
23400
|
const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
|
|
23247
23401
|
metadataQualityConfig =
|
|
@@ -24499,12 +24653,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24499
24653
|
type: Input
|
|
24500
24654
|
}] } });
|
|
24501
24655
|
|
|
24656
|
+
function provideLocalizedDateAdapter() {
|
|
24657
|
+
return [
|
|
24658
|
+
{ provide: MAT_DATE_LOCALE, useValue: enUS },
|
|
24659
|
+
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS },
|
|
24660
|
+
{
|
|
24661
|
+
provide: DateAdapter,
|
|
24662
|
+
useFactory: () => {
|
|
24663
|
+
const dateService = inject(DateService);
|
|
24664
|
+
const adapter = new DateFnsAdapter();
|
|
24665
|
+
dateService
|
|
24666
|
+
.getDateFnsLocale()
|
|
24667
|
+
.then((locale) => adapter.setLocale(locale));
|
|
24668
|
+
return adapter;
|
|
24669
|
+
},
|
|
24670
|
+
},
|
|
24671
|
+
];
|
|
24672
|
+
}
|
|
24673
|
+
|
|
24502
24674
|
class DatePickerComponent {
|
|
24503
24675
|
constructor() {
|
|
24504
|
-
this.dateAdapter = inject(DateAdapter);
|
|
24505
|
-
this.translate = inject(TranslateService);
|
|
24506
24676
|
this.dateChange = new EventEmitter();
|
|
24507
|
-
this.dateAdapter.setLocale(this.translate.getCurrentLang());
|
|
24508
24677
|
}
|
|
24509
24678
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
24510
24679
|
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 +24681,19 @@ class DatePickerComponent {
|
|
|
24512
24681
|
provideNgIconsConfig({
|
|
24513
24682
|
size: '1.5rem',
|
|
24514
24683
|
}),
|
|
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 }); }
|
|
24684
|
+
provideLocalizedDateAdapter(),
|
|
24685
|
+
], 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
24686
|
}
|
|
24521
24687
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
24522
24688
|
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: [
|
|
24689
|
+
args: [{ selector: 'gn-ui-date-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24529
24690
|
provideIcons({ iconoirCalendar }),
|
|
24530
24691
|
provideNgIconsConfig({
|
|
24531
24692
|
size: '1.5rem',
|
|
24532
24693
|
}),
|
|
24533
|
-
|
|
24534
|
-
provide: MAT_DATE_LOCALE,
|
|
24535
|
-
useFactory: (locale) => locale,
|
|
24536
|
-
},
|
|
24694
|
+
provideLocalizedDateAdapter(),
|
|
24537
24695
|
], 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
|
-
}],
|
|
24696
|
+
}], propDecorators: { date: [{
|
|
24539
24697
|
type: Input
|
|
24540
24698
|
}], dateChange: [{
|
|
24541
24699
|
type: Output
|
|
@@ -24543,58 +24701,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24543
24701
|
|
|
24544
24702
|
class DateRangeDropdownComponent {
|
|
24545
24703
|
constructor() {
|
|
24546
|
-
this.
|
|
24704
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
24705
|
+
this.dateAdapter = inject(DateAdapter);
|
|
24706
|
+
this.dateFormats = inject(MAT_DATE_FORMATS);
|
|
24547
24707
|
this.cdr = inject(ChangeDetectorRef);
|
|
24548
|
-
this.
|
|
24549
|
-
this.
|
|
24550
|
-
this.
|
|
24708
|
+
this.dateRange = {};
|
|
24709
|
+
this.dateRangeChange = new EventEmitter();
|
|
24710
|
+
this.overlayPositions = [
|
|
24711
|
+
{
|
|
24712
|
+
originX: 'start',
|
|
24713
|
+
originY: 'bottom',
|
|
24714
|
+
overlayX: 'start',
|
|
24715
|
+
overlayY: 'top',
|
|
24716
|
+
offsetY: 8,
|
|
24717
|
+
},
|
|
24718
|
+
{
|
|
24719
|
+
originX: 'start',
|
|
24720
|
+
originY: 'top',
|
|
24721
|
+
overlayX: 'start',
|
|
24722
|
+
overlayY: 'bottom',
|
|
24723
|
+
offsetY: -8,
|
|
24724
|
+
},
|
|
24725
|
+
];
|
|
24726
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
24727
|
+
this.overlayOpen = false;
|
|
24728
|
+
this.expandedBound = 'start';
|
|
24729
|
+
this.invalidBounds = { start: false, end: false };
|
|
24730
|
+
// redraw when the lazily loaded UI locale reaches the adapter
|
|
24731
|
+
this.dateAdapter.localeChanges
|
|
24732
|
+
.pipe(takeUntilDestroyed())
|
|
24733
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
24551
24734
|
}
|
|
24552
|
-
|
|
24553
|
-
this.
|
|
24735
|
+
get startDate() {
|
|
24736
|
+
return this.dateRange.start;
|
|
24554
24737
|
}
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
24738
|
+
get endDate() {
|
|
24739
|
+
return this.dateRange.end;
|
|
24740
|
+
}
|
|
24741
|
+
get selectedDatesCount() {
|
|
24742
|
+
return (this.startDate ? 1 : 0) + (this.endDate ? 1 : 0);
|
|
24743
|
+
}
|
|
24744
|
+
openOverlay() {
|
|
24745
|
+
this.expandedBound = 'start';
|
|
24746
|
+
this.overlayOpen = true;
|
|
24747
|
+
}
|
|
24748
|
+
closeOverlay() {
|
|
24749
|
+
this.overlayOpen = false;
|
|
24750
|
+
}
|
|
24751
|
+
toggleBound(bound) {
|
|
24752
|
+
this.expandedBound = this.expandedBound === bound ? null : bound;
|
|
24753
|
+
}
|
|
24754
|
+
formatDate(date) {
|
|
24755
|
+
return this.dateAdapter.format(date, this.dateFormats.display.dateInput);
|
|
24756
|
+
}
|
|
24757
|
+
onDateInput(bound, event) {
|
|
24758
|
+
const typedText = event.target.value.trim();
|
|
24759
|
+
const date = typedText
|
|
24760
|
+
? this.dateAdapter.parse(typedText, this.dateFormats.parse.dateInput)
|
|
24761
|
+
: null;
|
|
24762
|
+
if (!this.isAcceptable(bound, typedText, date)) {
|
|
24763
|
+
// keep the text as typed and flag it; the filter stays on its last value
|
|
24764
|
+
this.invalidBounds = { ...this.invalidBounds, [bound]: true };
|
|
24765
|
+
return;
|
|
24766
|
+
}
|
|
24767
|
+
if (bound === 'start')
|
|
24768
|
+
this.setStartDate(date);
|
|
24769
|
+
else
|
|
24770
|
+
this.setEndDate(date);
|
|
24771
|
+
}
|
|
24772
|
+
normalizeDateInput(bound, event) {
|
|
24773
|
+
if (this.invalidBounds[bound])
|
|
24774
|
+
return;
|
|
24775
|
+
const date = bound === 'start' ? this.startDate : this.endDate;
|
|
24776
|
+
const input = event.target;
|
|
24777
|
+
input.value = date ? this.formatDate(date) : '';
|
|
24778
|
+
}
|
|
24779
|
+
isAcceptable(bound, typedText, date) {
|
|
24780
|
+
if (!typedText)
|
|
24781
|
+
return true;
|
|
24782
|
+
if (!date || !this.dateAdapter.isValid(date))
|
|
24783
|
+
return false;
|
|
24784
|
+
return bound === 'start'
|
|
24785
|
+
? !this.endDate || date <= this.endDate
|
|
24786
|
+
: !this.startDate || date >= this.startDate;
|
|
24787
|
+
}
|
|
24788
|
+
setStartDate(date) {
|
|
24789
|
+
this.invalidBounds = { ...this.invalidBounds, start: false };
|
|
24790
|
+
this.applyDateRange({ ...this.dateRange, start: date });
|
|
24791
|
+
this.expandedBound = 'end';
|
|
24792
|
+
}
|
|
24793
|
+
setEndDate(date) {
|
|
24794
|
+
this.invalidBounds = { ...this.invalidBounds, end: false };
|
|
24795
|
+
this.applyDateRange({ ...this.dateRange, end: date });
|
|
24796
|
+
this.expandedBound = null;
|
|
24797
|
+
}
|
|
24798
|
+
clearDates(event) {
|
|
24799
|
+
this.invalidBounds = { start: false, end: false };
|
|
24800
|
+
this.expandedBound = 'start';
|
|
24801
|
+
this.applyDateRange({});
|
|
24802
|
+
propagateToDocumentOnly(event);
|
|
24803
|
+
}
|
|
24804
|
+
applyDateRange(dateRange) {
|
|
24805
|
+
this.dateRange = {
|
|
24806
|
+
...(dateRange.start && { start: dateRange.start }),
|
|
24807
|
+
...(dateRange.end && { end: dateRange.end }),
|
|
24808
|
+
};
|
|
24809
|
+
this.dateRangeChange.emit(this.dateRange);
|
|
24563
24810
|
}
|
|
24564
24811
|
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: "
|
|
24812
|
+
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
24813
|
provideIcons({
|
|
24567
|
-
|
|
24814
|
+
iconoirCalendar,
|
|
24815
|
+
matClose,
|
|
24568
24816
|
matExpandLess,
|
|
24817
|
+
matExpandMore,
|
|
24569
24818
|
}),
|
|
24570
|
-
|
|
24819
|
+
provideNgIconsConfig({
|
|
24820
|
+
size: '1.5rem',
|
|
24821
|
+
}),
|
|
24822
|
+
provideLocalizedDateAdapter(),
|
|
24823
|
+
], 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
24824
|
}
|
|
24572
24825
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangeDropdownComponent, decorators: [{
|
|
24573
24826
|
type: Component,
|
|
24574
24827
|
args: [{ selector: 'gn-ui-date-range-dropdown', standalone: true, imports: [
|
|
24575
|
-
|
|
24576
|
-
MatNativeDateModule,
|
|
24577
|
-
MatDatepickerModule,
|
|
24828
|
+
AutofocusDirective,
|
|
24578
24829
|
ButtonComponent,
|
|
24830
|
+
MatDatepickerModule,
|
|
24831
|
+
NgIcon,
|
|
24832
|
+
NgTemplateOutlet,
|
|
24833
|
+
OverlayModule,
|
|
24834
|
+
TranslateDirective,
|
|
24835
|
+
TranslatePipe,
|
|
24579
24836
|
], providers: [
|
|
24580
24837
|
provideIcons({
|
|
24581
|
-
|
|
24838
|
+
iconoirCalendar,
|
|
24839
|
+
matClose,
|
|
24582
24840
|
matExpandLess,
|
|
24841
|
+
matExpandMore,
|
|
24583
24842
|
}),
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24843
|
+
provideNgIconsConfig({
|
|
24844
|
+
size: '1.5rem',
|
|
24845
|
+
}),
|
|
24846
|
+
provideLocalizedDateAdapter(),
|
|
24847
|
+
], 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"] }]
|
|
24848
|
+
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
24588
24849
|
type: Input
|
|
24589
|
-
}],
|
|
24850
|
+
}], dateRange: [{
|
|
24590
24851
|
type: Input
|
|
24591
|
-
}],
|
|
24592
|
-
type: Output
|
|
24593
|
-
}], endDateChange: [{
|
|
24852
|
+
}], dateRangeChange: [{
|
|
24594
24853
|
type: Output
|
|
24595
|
-
}],
|
|
24854
|
+
}], overlayOrigin: [{
|
|
24596
24855
|
type: ViewChild,
|
|
24597
|
-
args: ['
|
|
24856
|
+
args: ['overlayOrigin']
|
|
24598
24857
|
}] } });
|
|
24599
24858
|
|
|
24600
24859
|
class DateRangePickerComponent {
|
|
@@ -24608,20 +24867,17 @@ class DateRangePickerComponent {
|
|
|
24608
24867
|
provideNgIconsConfig({
|
|
24609
24868
|
size: '1.5rem',
|
|
24610
24869
|
}),
|
|
24611
|
-
|
|
24870
|
+
provideLocalizedDateAdapter(),
|
|
24871
|
+
], 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
24872
|
}
|
|
24613
24873
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
24614
24874
|
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: [
|
|
24875
|
+
args: [{ selector: 'gn-ui-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatDatepickerModule, ButtonComponent, NgIconComponent], providers: [
|
|
24621
24876
|
provideIcons({ iconoirCalendar }),
|
|
24622
24877
|
provideNgIconsConfig({
|
|
24623
24878
|
size: '1.5rem',
|
|
24624
24879
|
}),
|
|
24880
|
+
provideLocalizedDateAdapter(),
|
|
24625
24881
|
], 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
24882
|
}], propDecorators: { startDate: [{
|
|
24627
24883
|
type: Input
|
|
@@ -24639,28 +24895,68 @@ class DragAndDropFileInputComponent {
|
|
|
24639
24895
|
constructor() {
|
|
24640
24896
|
this.placeholder = placeholder;
|
|
24641
24897
|
this.accept = '*';
|
|
24898
|
+
this.maxFileSizeMb = null;
|
|
24899
|
+
this.icon = null;
|
|
24900
|
+
this.dropzoneBackgroundColor = null;
|
|
24901
|
+
this.textClass = '';
|
|
24902
|
+
this.extraClass = '';
|
|
24903
|
+
this.showFileName = true;
|
|
24642
24904
|
this.fileChange = new EventEmitter();
|
|
24905
|
+
this.errorChange = new EventEmitter();
|
|
24643
24906
|
this.selectedFile = null;
|
|
24644
24907
|
}
|
|
24645
24908
|
get fileName() {
|
|
24646
24909
|
return this.selectedFile && this.selectedFile.name;
|
|
24647
24910
|
}
|
|
24911
|
+
get maxFileSizeBytes() {
|
|
24912
|
+
return typeof this.maxFileSizeMb === 'number'
|
|
24913
|
+
? megabytesToBytes(this.maxFileSizeMb)
|
|
24914
|
+
: null;
|
|
24915
|
+
}
|
|
24648
24916
|
selectFile(event) {
|
|
24917
|
+
if (event.rejectedFiles?.length) {
|
|
24918
|
+
const reason = event.rejectedFiles[0].reason;
|
|
24919
|
+
this.errorChange.emit(reason === 'size' ? 'file-too-large' : 'invalid-extension');
|
|
24920
|
+
return;
|
|
24921
|
+
}
|
|
24649
24922
|
this.selectedFile = event.addedFiles[0];
|
|
24650
24923
|
this.fileChange.emit(this.selectedFile);
|
|
24651
24924
|
}
|
|
24925
|
+
openFileSelector() {
|
|
24926
|
+
this.dropzone.showFileSelector();
|
|
24927
|
+
}
|
|
24928
|
+
clear() {
|
|
24929
|
+
this.selectedFile = null;
|
|
24930
|
+
}
|
|
24652
24931
|
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
|
|
24932
|
+
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
24933
|
}
|
|
24655
24934
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DragAndDropFileInputComponent, decorators: [{
|
|
24656
24935
|
type: Component,
|
|
24657
|
-
args: [{ selector: 'gn-ui-drag-and-drop-file-input', standalone: true, imports: [NgxDropzoneModule], template: "<div
|
|
24936
|
+
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
24937
|
}], propDecorators: { placeholder: [{
|
|
24659
24938
|
type: Input
|
|
24660
24939
|
}], accept: [{
|
|
24661
24940
|
type: Input
|
|
24941
|
+
}], maxFileSizeMb: [{
|
|
24942
|
+
type: Input
|
|
24943
|
+
}], icon: [{
|
|
24944
|
+
type: Input
|
|
24945
|
+
}], dropzoneBackgroundColor: [{
|
|
24946
|
+
type: Input
|
|
24947
|
+
}], textClass: [{
|
|
24948
|
+
type: Input
|
|
24949
|
+
}], extraClass: [{
|
|
24950
|
+
type: Input
|
|
24951
|
+
}], showFileName: [{
|
|
24952
|
+
type: Input
|
|
24662
24953
|
}], fileChange: [{
|
|
24663
24954
|
type: Output
|
|
24955
|
+
}], errorChange: [{
|
|
24956
|
+
type: Output
|
|
24957
|
+
}], dropzone: [{
|
|
24958
|
+
type: ViewChild,
|
|
24959
|
+
args: [NgxDropzoneComponent]
|
|
24664
24960
|
}] } });
|
|
24665
24961
|
|
|
24666
24962
|
class DropdownMultiselectComponent {
|
|
@@ -24815,7 +25111,7 @@ class DropdownMultiselectComponent {
|
|
|
24815
25111
|
matExpandMore,
|
|
24816
25112
|
matExpandLess,
|
|
24817
25113
|
}),
|
|
24818
|
-
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-
|
|
25114
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
24819
25115
|
}
|
|
24820
25116
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
|
|
24821
25117
|
type: Component,
|
|
@@ -24825,7 +25121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
24825
25121
|
matExpandMore,
|
|
24826
25122
|
matExpandLess,
|
|
24827
25123
|
}),
|
|
24828
|
-
], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-
|
|
25124
|
+
], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
|
|
24829
25125
|
}], propDecorators: { title: [{
|
|
24830
25126
|
type: Input
|
|
24831
25127
|
}], choices: [{
|
|
@@ -24997,7 +25293,7 @@ class DropdownSelectorComponent {
|
|
|
24997
25293
|
provideNgIconsConfig({
|
|
24998
25294
|
size: '1.5em',
|
|
24999
25295
|
}),
|
|
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$
|
|
25296
|
+
], 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
25297
|
}
|
|
25002
25298
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownSelectorComponent, decorators: [{
|
|
25003
25299
|
type: Component,
|
|
@@ -25737,6 +26033,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
25737
26033
|
type: Output
|
|
25738
26034
|
}] } });
|
|
25739
26035
|
|
|
26036
|
+
marker('search.filters.spatialExtent.import');
|
|
26037
|
+
marker('search.filters.spatialExtent.helpText');
|
|
26038
|
+
marker('search.filters.spatialExtent.error.title');
|
|
26039
|
+
marker('search.filters.spatialExtent.bboxPrefix');
|
|
26040
|
+
marker('search.filters.spatialExtent.bboxDelete');
|
|
26041
|
+
class SpatialExtentDropdownComponent {
|
|
26042
|
+
constructor() {
|
|
26043
|
+
this.cd = inject(ChangeDetectorRef);
|
|
26044
|
+
this.scrollStrategies = inject(ScrollStrategyOptions);
|
|
26045
|
+
this.maxFileSizeMb = null;
|
|
26046
|
+
this.bboxChange = new EventEmitter();
|
|
26047
|
+
this.errorChange = new EventEmitter();
|
|
26048
|
+
this.bbox = null;
|
|
26049
|
+
this.fileName = '';
|
|
26050
|
+
this.overlayPositions = [
|
|
26051
|
+
{
|
|
26052
|
+
originX: 'start',
|
|
26053
|
+
originY: 'bottom',
|
|
26054
|
+
overlayX: 'start',
|
|
26055
|
+
overlayY: 'top',
|
|
26056
|
+
offsetY: 8,
|
|
26057
|
+
},
|
|
26058
|
+
{
|
|
26059
|
+
originX: 'start',
|
|
26060
|
+
originY: 'top',
|
|
26061
|
+
overlayX: 'start',
|
|
26062
|
+
overlayY: 'bottom',
|
|
26063
|
+
offsetY: -8,
|
|
26064
|
+
},
|
|
26065
|
+
];
|
|
26066
|
+
this.scrollStrategy = this.scrollStrategies.reposition();
|
|
26067
|
+
this.overlayOpen = false;
|
|
26068
|
+
this.overlayMinWidth = 'none';
|
|
26069
|
+
this.errorKey = null;
|
|
26070
|
+
}
|
|
26071
|
+
get hasSelection() {
|
|
26072
|
+
return !!this.bbox;
|
|
26073
|
+
}
|
|
26074
|
+
openOverlay() {
|
|
26075
|
+
this.overlayMinWidth =
|
|
26076
|
+
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
|
|
26077
|
+
.width + 'px';
|
|
26078
|
+
this.overlayOpen = true;
|
|
26079
|
+
}
|
|
26080
|
+
closeOverlay() {
|
|
26081
|
+
this.overlayOpen = false;
|
|
26082
|
+
}
|
|
26083
|
+
toggleOverlay() {
|
|
26084
|
+
if (this.overlayOpen) {
|
|
26085
|
+
this.closeOverlay();
|
|
26086
|
+
}
|
|
26087
|
+
else {
|
|
26088
|
+
this.openOverlay();
|
|
26089
|
+
}
|
|
26090
|
+
}
|
|
26091
|
+
async handleFileSelected(file) {
|
|
26092
|
+
this.errorKey = null;
|
|
26093
|
+
let content;
|
|
26094
|
+
try {
|
|
26095
|
+
content = await readFileAsText(file);
|
|
26096
|
+
const parsed = JSON.parse(content);
|
|
26097
|
+
const geometry = getGeometryFromGeoJSON(parsed);
|
|
26098
|
+
if (!geometry) {
|
|
26099
|
+
this.setError(marker('search.filters.spatialExtent.error.noGeometry'));
|
|
26100
|
+
return;
|
|
26101
|
+
}
|
|
26102
|
+
const bbox = getGeometryBoundingBox(geometry);
|
|
26103
|
+
this.bbox = bbox;
|
|
26104
|
+
this.fileName = file.name;
|
|
26105
|
+
this.bboxChange.emit(bbox);
|
|
26106
|
+
this.cd.markForCheck();
|
|
26107
|
+
}
|
|
26108
|
+
catch {
|
|
26109
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26110
|
+
return;
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
26113
|
+
handleFileError(error) {
|
|
26114
|
+
if (error === 'file-too-large') {
|
|
26115
|
+
this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
|
|
26116
|
+
maxSize: this.maxFileSizeMb,
|
|
26117
|
+
});
|
|
26118
|
+
}
|
|
26119
|
+
else {
|
|
26120
|
+
this.setError(marker('search.filters.spatialExtent.error.invalidFormat'));
|
|
26121
|
+
}
|
|
26122
|
+
}
|
|
26123
|
+
setError(errorKey, params) {
|
|
26124
|
+
this.errorKey = errorKey;
|
|
26125
|
+
this.errorChange.emit({ key: errorKey, params });
|
|
26126
|
+
this.cd.markForCheck();
|
|
26127
|
+
}
|
|
26128
|
+
removeSelection(event) {
|
|
26129
|
+
this.bbox = null;
|
|
26130
|
+
this.fileName = '';
|
|
26131
|
+
this.errorKey = null;
|
|
26132
|
+
this.fileInput?.clear();
|
|
26133
|
+
this.bboxChange.emit(null);
|
|
26134
|
+
propagateToDocumentOnly(event);
|
|
26135
|
+
}
|
|
26136
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26137
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SpatialExtentDropdownComponent, isStandalone: true, selector: "gn-ui-spatial-extent-dropdown", inputs: { title: "title", maxFileSizeMb: "maxFileSizeMb" }, outputs: { bboxChange: "bboxChange", errorChange: "errorChange" }, providers: [
|
|
26138
|
+
provideIcons({
|
|
26139
|
+
iconoirCheckCircle,
|
|
26140
|
+
iconoirImport,
|
|
26141
|
+
iconoirSquareDashed,
|
|
26142
|
+
iconoirTrash,
|
|
26143
|
+
matClose,
|
|
26144
|
+
matExpandLess,
|
|
26145
|
+
matExpandMore,
|
|
26146
|
+
}),
|
|
26147
|
+
], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
26148
|
+
}
|
|
26149
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
|
|
26150
|
+
type: Component,
|
|
26151
|
+
args: [{ selector: 'gn-ui-spatial-extent-dropdown', standalone: true, imports: [
|
|
26152
|
+
ButtonComponent,
|
|
26153
|
+
NgIcon,
|
|
26154
|
+
OverlayModule,
|
|
26155
|
+
TranslatePipe,
|
|
26156
|
+
DragAndDropFileInputComponent,
|
|
26157
|
+
], providers: [
|
|
26158
|
+
provideIcons({
|
|
26159
|
+
iconoirCheckCircle,
|
|
26160
|
+
iconoirImport,
|
|
26161
|
+
iconoirSquareDashed,
|
|
26162
|
+
iconoirTrash,
|
|
26163
|
+
matClose,
|
|
26164
|
+
matExpandLess,
|
|
26165
|
+
matExpandMore,
|
|
26166
|
+
}),
|
|
26167
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"\n ('search.filters.spatialExtent.bboxDelete' | translate) +\n ' ' +\n fileName\n \"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxPrefix' | translate }}\n {{ fileName }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ 'search.filters.spatialExtent.bboxDelete' | translate }}\n {{ fileName }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
|
|
26168
|
+
}], propDecorators: { title: [{
|
|
26169
|
+
type: Input
|
|
26170
|
+
}], maxFileSizeMb: [{
|
|
26171
|
+
type: Input
|
|
26172
|
+
}], bboxChange: [{
|
|
26173
|
+
type: Output
|
|
26174
|
+
}], errorChange: [{
|
|
26175
|
+
type: Output
|
|
26176
|
+
}], overlayOrigin: [{
|
|
26177
|
+
type: ViewChild,
|
|
26178
|
+
args: ['overlayOrigin']
|
|
26179
|
+
}], overlay: [{
|
|
26180
|
+
type: ViewChild,
|
|
26181
|
+
args: [CdkConnectedOverlay]
|
|
26182
|
+
}], fileInput: [{
|
|
26183
|
+
type: ViewChild,
|
|
26184
|
+
args: [DragAndDropFileInputComponent]
|
|
26185
|
+
}] } });
|
|
26186
|
+
|
|
25740
26187
|
class CellPopinComponent {
|
|
25741
26188
|
constructor() {
|
|
25742
26189
|
this.scrollDispatcher = inject(ScrollDispatcher);
|
|
@@ -25813,7 +26260,7 @@ class CellPopinComponent {
|
|
|
25813
26260
|
this.isOpen = false;
|
|
25814
26261
|
}
|
|
25815
26262
|
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$
|
|
26263
|
+
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
26264
|
}
|
|
25818
26265
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CellPopinComponent, decorators: [{
|
|
25819
26266
|
type: Component,
|
|
@@ -27903,6 +28350,23 @@ class DateRangeSearchField extends SimpleSearchField {
|
|
|
27903
28350
|
return 'dateRange';
|
|
27904
28351
|
}
|
|
27905
28352
|
}
|
|
28353
|
+
class BoundingBoxSearchField extends SimpleSearchField {
|
|
28354
|
+
getAvailableValues() {
|
|
28355
|
+
return of([]);
|
|
28356
|
+
}
|
|
28357
|
+
getFiltersForValues(values) {
|
|
28358
|
+
return of({
|
|
28359
|
+
[this.esFieldName]: values.map(Number),
|
|
28360
|
+
});
|
|
28361
|
+
}
|
|
28362
|
+
getValuesForFilter(filters) {
|
|
28363
|
+
const filter = filters[this.esFieldName];
|
|
28364
|
+
return of(isBoundingBox(filter) ? filter : []);
|
|
28365
|
+
}
|
|
28366
|
+
getType() {
|
|
28367
|
+
return 'spatialExtent';
|
|
28368
|
+
}
|
|
28369
|
+
}
|
|
27906
28370
|
marker('search.filters.availableServices.view');
|
|
27907
28371
|
marker('search.filters.availableServices.download');
|
|
27908
28372
|
class AvailableServicesField extends SimpleSearchField {
|
|
@@ -28047,6 +28511,7 @@ marker('search.filters.producerOrg');
|
|
|
28047
28511
|
marker('search.filters.publisherOrg');
|
|
28048
28512
|
marker('search.filters.user');
|
|
28049
28513
|
marker('search.filters.changeDate');
|
|
28514
|
+
marker('search.filters.spatialExtent');
|
|
28050
28515
|
class FieldsService {
|
|
28051
28516
|
constructor() {
|
|
28052
28517
|
this.injector = inject(Injector);
|
|
@@ -28070,6 +28535,7 @@ class FieldsService {
|
|
|
28070
28535
|
user: new UserSearchField(this.injector),
|
|
28071
28536
|
changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
|
|
28072
28537
|
availableServices: new AvailableServicesField(this.injector),
|
|
28538
|
+
spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
|
|
28073
28539
|
};
|
|
28074
28540
|
}
|
|
28075
28541
|
get supportedFields() {
|
|
@@ -29332,7 +29798,7 @@ class ContactPillComponent {
|
|
|
29332
29798
|
this.overlayOpen = false;
|
|
29333
29799
|
}
|
|
29334
29800
|
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$
|
|
29801
|
+
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
29802
|
}
|
|
29337
29803
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactPillComponent, decorators: [{
|
|
29338
29804
|
type: Component,
|
|
@@ -31254,19 +31720,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31254
31720
|
type: Output
|
|
31255
31721
|
}] } });
|
|
31256
31722
|
|
|
31723
|
+
class NotificationsService {
|
|
31724
|
+
constructor() {
|
|
31725
|
+
this.notifications$ = new BehaviorSubject([]);
|
|
31726
|
+
}
|
|
31727
|
+
showNotification(content, timeoutMs, error) {
|
|
31728
|
+
error && console.error(error);
|
|
31729
|
+
const id = Math.floor(Math.random() * 1000000);
|
|
31730
|
+
this.notifications$.next([...this.notifications$.value, { ...content, id }]);
|
|
31731
|
+
if (typeof timeoutMs !== 'undefined') {
|
|
31732
|
+
setTimeout(() => {
|
|
31733
|
+
this.removeNotificationById(id);
|
|
31734
|
+
}, timeoutMs);
|
|
31735
|
+
}
|
|
31736
|
+
return id;
|
|
31737
|
+
}
|
|
31738
|
+
removeNotificationById(id) {
|
|
31739
|
+
this.notifications$.next(this.notifications$.value.filter((n) => n.id !== id));
|
|
31740
|
+
}
|
|
31741
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31742
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, providedIn: 'root' }); }
|
|
31743
|
+
}
|
|
31744
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsService, decorators: [{
|
|
31745
|
+
type: Injectable,
|
|
31746
|
+
args: [{
|
|
31747
|
+
providedIn: 'root',
|
|
31748
|
+
}]
|
|
31749
|
+
}] });
|
|
31750
|
+
|
|
31751
|
+
class NotificationsContainerComponent {
|
|
31752
|
+
constructor() {
|
|
31753
|
+
this.notificationsService = inject(NotificationsService);
|
|
31754
|
+
}
|
|
31755
|
+
trackById(index, notification) {
|
|
31756
|
+
return notification.id;
|
|
31757
|
+
}
|
|
31758
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
31759
|
+
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: [
|
|
31760
|
+
trigger('enterExit', [
|
|
31761
|
+
transition(':enter', [
|
|
31762
|
+
animate('150ms', keyframes([
|
|
31763
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31764
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31765
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31766
|
+
])),
|
|
31767
|
+
]),
|
|
31768
|
+
transition(':leave', [
|
|
31769
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31770
|
+
]),
|
|
31771
|
+
]),
|
|
31772
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31773
|
+
}
|
|
31774
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NotificationsContainerComponent, decorators: [{
|
|
31775
|
+
type: Component,
|
|
31776
|
+
args: [{ selector: 'gn-ui-notifications-container', standalone: true, imports: [CommonModule, NotificationComponent], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
|
|
31777
|
+
trigger('enterExit', [
|
|
31778
|
+
transition(':enter', [
|
|
31779
|
+
animate('150ms', keyframes([
|
|
31780
|
+
style({ transform: 'scale(1)', opacity: 0 }),
|
|
31781
|
+
style({ transform: 'scale(1.03)', opacity: 0.5 }),
|
|
31782
|
+
style({ transform: 'scale(1)', opacity: 1 }),
|
|
31783
|
+
])),
|
|
31784
|
+
]),
|
|
31785
|
+
transition(':leave', [
|
|
31786
|
+
animate('200ms', style({ transform: 'translateX(50px)', opacity: 0 })),
|
|
31787
|
+
]),
|
|
31788
|
+
]),
|
|
31789
|
+
], template: "<div class=\"flex flex-col gap-6 p-6 items-start pointer-events-none\">\n @for (\n notification of notificationsService.notifications$ | async;\n track trackById($index, notification)\n ) {\n <gn-ui-notification\n class=\"max-w-full pointer-events-auto\"\n [text]=\"notification.text\"\n [type]=\"notification.type\"\n [title]=\"notification.title\"\n [closeMessage]=\"notification.closeMessage\"\n (notificationClose)=\"\n notificationsService.removeNotificationById(notification.id)\n \"\n [@enterExit]\n ></gn-ui-notification>\n }\n</div>\n" }]
|
|
31790
|
+
}] });
|
|
31791
|
+
|
|
31257
31792
|
class FilterDropdownComponent {
|
|
31258
31793
|
constructor() {
|
|
31259
31794
|
this.searchFacade = inject(SearchFacade);
|
|
31260
31795
|
this.searchService = inject(SearchService);
|
|
31261
31796
|
this.fieldsService = inject(FieldsService);
|
|
31797
|
+
this.notificationsService = inject(NotificationsService);
|
|
31798
|
+
this.translateService = inject(TranslateService);
|
|
31799
|
+
this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
|
|
31262
31800
|
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((
|
|
31801
|
+
this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
|
|
31802
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31264
31803
|
}
|
|
31265
31804
|
onSelectedValues(values) {
|
|
31266
31805
|
this.fieldsService
|
|
31267
31806
|
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
31268
31807
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31269
31808
|
}
|
|
31809
|
+
onBboxChange(bbox) {
|
|
31810
|
+
console.log(bbox);
|
|
31811
|
+
this.clearSpatialExtentErrorNotification();
|
|
31812
|
+
}
|
|
31813
|
+
onSpatialExtentError(error) {
|
|
31814
|
+
this.clearSpatialExtentErrorNotification();
|
|
31815
|
+
this.spatialExtentErrorNotificationId =
|
|
31816
|
+
this.notificationsService.showNotification({
|
|
31817
|
+
type: 'error',
|
|
31818
|
+
title: this.translateService.instant('search.filters.spatialExtent.error.title'),
|
|
31819
|
+
text: this.translateService.instant(error.key, error.params),
|
|
31820
|
+
});
|
|
31821
|
+
}
|
|
31822
|
+
clearSpatialExtentErrorNotification() {
|
|
31823
|
+
if (this.spatialExtentErrorNotificationId === null)
|
|
31824
|
+
return;
|
|
31825
|
+
this.notificationsService.removeNotificationById(this.spatialExtentErrorNotificationId);
|
|
31826
|
+
this.spatialExtentErrorNotificationId = null;
|
|
31827
|
+
}
|
|
31270
31828
|
ngOnInit() {
|
|
31271
31829
|
this.fieldType = this.fieldsService.getFieldType(this.fieldName);
|
|
31272
31830
|
this.choices$ = this.fieldsService.getAvailableValues(this.fieldName).pipe(startWith$1([]), map$1((values) => values.map((v) => ({
|
|
@@ -31274,27 +31832,15 @@ class FilterDropdownComponent {
|
|
|
31274
31832
|
value: v.value.toString(), // converting to string for the dropdown
|
|
31275
31833
|
}))), catchError(() => of([])));
|
|
31276
31834
|
}
|
|
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
|
-
}
|
|
31835
|
+
onDateRangeChange(dateRange) {
|
|
31836
|
+
this.fieldsService
|
|
31837
|
+
.buildFiltersFromFieldValues({
|
|
31838
|
+
[this.fieldName]: dateRange,
|
|
31839
|
+
})
|
|
31840
|
+
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
31295
31841
|
}
|
|
31296
31842
|
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 [
|
|
31843
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FilterDropdownComponent, isStandalone: true, selector: "gn-ui-filter-dropdown", inputs: { fieldName: "fieldName", title: "title" }, ngImport: i0, template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DateRangeDropdownComponent, selector: "gn-ui-date-range-dropdown", inputs: ["title", "dateRange"], outputs: ["dateRangeChange"] }, { kind: "component", type: DropdownMultiselectComponent, selector: "gn-ui-dropdown-multiselect", inputs: ["title", "choices", "selected", "allowSearch", "maxRows", "searchInputValue"], outputs: ["selectValues"] }, { kind: "component", type: SpatialExtentDropdownComponent, selector: "gn-ui-spatial-extent-dropdown", inputs: ["title", "maxFileSizeMb"], outputs: ["bboxChange", "errorChange"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
31298
31844
|
}
|
|
31299
31845
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
|
|
31300
31846
|
type: Component,
|
|
@@ -31302,7 +31848,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31302
31848
|
CommonModule,
|
|
31303
31849
|
DateRangeDropdownComponent,
|
|
31304
31850
|
DropdownMultiselectComponent,
|
|
31305
|
-
|
|
31851
|
+
SpatialExtentDropdownComponent,
|
|
31852
|
+
], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n" }]
|
|
31306
31853
|
}], propDecorators: { fieldName: [{
|
|
31307
31854
|
type: Input
|
|
31308
31855
|
}], title: [{
|
|
@@ -31772,11 +32319,7 @@ const SortByEnum = {
|
|
|
31772
32319
|
RELEVANCY: ['desc', '_score'],
|
|
31773
32320
|
QUALITY_SCORE: ['desc', 'qualityScore'],
|
|
31774
32321
|
CHANGE_DATE: ['desc', 'changeDate'],
|
|
31775
|
-
|
|
31776
|
-
['desc', 'revisionDateForResource'],
|
|
31777
|
-
['desc', 'publicationDateForResource'],
|
|
31778
|
-
['desc', 'creationDateForResource'],
|
|
31779
|
-
],
|
|
32322
|
+
RESOURCE_DATE: ['desc', 'resourceDate.date'],
|
|
31780
32323
|
};
|
|
31781
32324
|
|
|
31782
32325
|
class SortByComponent {
|
|
@@ -31790,7 +32333,7 @@ class SortByComponent {
|
|
|
31790
32333
|
},
|
|
31791
32334
|
{
|
|
31792
32335
|
label: marker('results.sortBy.dateStamp'),
|
|
31793
|
-
value: SortByEnum.
|
|
32336
|
+
value: SortByEnum.RESOURCE_DATE,
|
|
31794
32337
|
},
|
|
31795
32338
|
{
|
|
31796
32339
|
label: marker('results.sortBy.popularity'),
|
|
@@ -31842,74 +32385,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31842
32385
|
args: ['gnUiSearchStateContainer']
|
|
31843
32386
|
}] } });
|
|
31844
32387
|
|
|
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
32388
|
class ResultsTableContainerComponent {
|
|
31914
32389
|
constructor() {
|
|
31915
32390
|
this.searchFacade = inject(SearchFacade);
|
|
@@ -31994,12 +32469,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
31994
32469
|
|
|
31995
32470
|
marker('search.filters.summaryLabel.user');
|
|
31996
32471
|
marker('search.filters.summaryLabel.changeDate');
|
|
32472
|
+
const OPEN_BOUND = '…';
|
|
31997
32473
|
class SearchFiltersSummaryItemComponent {
|
|
31998
32474
|
constructor() {
|
|
31999
32475
|
this.searchFacade = inject(SearchFacade);
|
|
32000
32476
|
this.searchService = inject(SearchService);
|
|
32001
32477
|
this.fieldsService = inject(FieldsService);
|
|
32002
|
-
this.
|
|
32478
|
+
this.dateService = inject(DateService);
|
|
32003
32479
|
this.translate = inject(TranslateService);
|
|
32004
32480
|
this.fieldValues$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$2((fieldValues) => Array.isArray(fieldValues[this.fieldName])
|
|
32005
32481
|
? fieldValues[this.fieldName]
|
|
@@ -32026,9 +32502,10 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32026
32502
|
getReadableValues(fieldValues) {
|
|
32027
32503
|
return fieldValues.map((value) => {
|
|
32028
32504
|
if (this.fieldType === 'dateRange') {
|
|
32505
|
+
const { start, end } = value;
|
|
32029
32506
|
return {
|
|
32030
32507
|
value,
|
|
32031
|
-
label: `${this.
|
|
32508
|
+
label: `${this.formatBound(start)} - ${this.formatBound(end)}`,
|
|
32032
32509
|
};
|
|
32033
32510
|
}
|
|
32034
32511
|
else if (this.fieldName === 'user') {
|
|
@@ -32039,6 +32516,15 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32039
32516
|
}
|
|
32040
32517
|
});
|
|
32041
32518
|
}
|
|
32519
|
+
formatBound(date) {
|
|
32520
|
+
return date
|
|
32521
|
+
? this.dateService.formatDate(date, {
|
|
32522
|
+
day: '2-digit',
|
|
32523
|
+
month: '2-digit',
|
|
32524
|
+
year: 'numeric',
|
|
32525
|
+
})
|
|
32526
|
+
: OPEN_BOUND;
|
|
32527
|
+
}
|
|
32042
32528
|
async removeFilterValue(fieldValue) {
|
|
32043
32529
|
const currentFieldValues = await firstValueFrom(this.fieldValues$);
|
|
32044
32530
|
const updatedFieldValues = currentFieldValues
|
|
@@ -32051,11 +32537,11 @@ class SearchFiltersSummaryItemComponent {
|
|
|
32051
32537
|
.subscribe((filters) => this.searchService.updateFilters(filters));
|
|
32052
32538
|
}
|
|
32053
32539
|
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" },
|
|
32540
|
+
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
32541
|
}
|
|
32056
32542
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SearchFiltersSummaryItemComponent, decorators: [{
|
|
32057
32543
|
type: Component,
|
|
32058
|
-
args: [{ selector: 'gn-ui-search-filters-summary-item', standalone: true, imports: [CommonModule, BadgeComponent],
|
|
32544
|
+
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
32545
|
}], propDecorators: { fieldName: [{
|
|
32060
32546
|
type: Input
|
|
32061
32547
|
}] } });
|
|
@@ -32299,11 +32785,11 @@ class AddLayerFromFileComponent {
|
|
|
32299
32785
|
}, 5000);
|
|
32300
32786
|
}
|
|
32301
32787
|
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" }] }); }
|
|
32788
|
+
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
32789
|
}
|
|
32304
32790
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AddLayerFromFileComponent, decorators: [{
|
|
32305
32791
|
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" }]
|
|
32792
|
+
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
32793
|
}] });
|
|
32308
32794
|
|
|
32309
32795
|
class LayersPanelComponent {
|
|
@@ -32468,8 +32954,7 @@ const closeMetadata = createAction('[Metadata view] close');
|
|
|
32468
32954
|
Related actions
|
|
32469
32955
|
*/
|
|
32470
32956
|
const setRelated = createAction('[Metadata view] Set related records', props());
|
|
32471
|
-
const
|
|
32472
|
-
const setSourceOf = createAction('[Metadata view] Set has sources', props());
|
|
32957
|
+
const setLinkedRecords = createAction('[Metadata view] Set associated records', props());
|
|
32473
32958
|
/*
|
|
32474
32959
|
ChartConfig actions
|
|
32475
32960
|
*/
|
|
@@ -32501,9 +32986,8 @@ var mdview_actions = /*#__PURE__*/Object.freeze({
|
|
|
32501
32986
|
loadUserFeedbacksSuccess: loadUserFeedbacksSuccess,
|
|
32502
32987
|
setChartConfig: setChartConfig,
|
|
32503
32988
|
setIncompleteMetadata: setIncompleteMetadata,
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
setSources: setSources
|
|
32989
|
+
setLinkedRecords: setLinkedRecords,
|
|
32990
|
+
setRelated: setRelated
|
|
32507
32991
|
});
|
|
32508
32992
|
|
|
32509
32993
|
const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView';
|
|
@@ -32546,12 +33030,9 @@ on(loadFullMetadata, (state) => ({
|
|
|
32546
33030
|
on(setRelated, (state, { related }) => ({
|
|
32547
33031
|
...state,
|
|
32548
33032
|
related,
|
|
32549
|
-
})), on(
|
|
32550
|
-
...state,
|
|
32551
|
-
sources,
|
|
32552
|
-
})), on(setSourceOf, (state, { sourceOf }) => ({
|
|
33033
|
+
})), on(setLinkedRecords, (state, { linkedRecords }) => ({
|
|
32553
33034
|
...state,
|
|
32554
|
-
|
|
33035
|
+
linkedRecords,
|
|
32555
33036
|
})),
|
|
32556
33037
|
/*
|
|
32557
33038
|
ChartConfig reducers
|
|
@@ -32613,8 +33094,7 @@ const getMetadataError = createSelector(getMdViewState, (state) => state.error);
|
|
|
32613
33094
|
Related selectors
|
|
32614
33095
|
*/
|
|
32615
33096
|
const getRelated = createSelector(getMdViewState, (state) => state.related);
|
|
32616
|
-
const
|
|
32617
|
-
const getSourceOf = createSelector(getMdViewState, (state) => state.sourceOf);
|
|
33097
|
+
const getLinkedRecords = createSelector(getMdViewState, (state) => state.linkedRecords);
|
|
32618
33098
|
/*
|
|
32619
33099
|
Metadata selectors
|
|
32620
33100
|
*/
|
|
@@ -32715,212 +33195,10 @@ function parseHeaders(httpHeaders) {
|
|
|
32715
33195
|
return result;
|
|
32716
33196
|
}
|
|
32717
33197
|
|
|
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();
|
|
32738
|
-
}
|
|
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
|
-
});
|
|
33198
|
+
const GEOMETRY_COLUMN_ALIAS = '__geometry__';
|
|
33199
|
+
function fieldToSql(name) {
|
|
33200
|
+
return `"${name.replace(/"/g, '""')}"`; // escape double quotes in field names
|
|
32750
33201
|
}
|
|
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
33202
|
function filterToSql(filter) {
|
|
32925
33203
|
const operator = filter[0];
|
|
32926
33204
|
const args = filter.slice(1);
|
|
@@ -32935,10 +33213,10 @@ function filterToSql(filter) {
|
|
|
32935
33213
|
case '=':
|
|
32936
33214
|
case '!=':
|
|
32937
33215
|
case 'like':
|
|
32938
|
-
return
|
|
33216
|
+
return `${fieldToSql(args[0])} ${operator.toUpperCase()} ${valueToSql(args[1])}`;
|
|
32939
33217
|
case 'in': {
|
|
32940
33218
|
const values = args.slice(1);
|
|
32941
|
-
return
|
|
33219
|
+
return `${fieldToSql(args[0])} IN (${values.map(valueToSql).join(', ')})`;
|
|
32942
33220
|
}
|
|
32943
33221
|
case 'and':
|
|
32944
33222
|
case 'or': {
|
|
@@ -32957,17 +33235,18 @@ function aggregationToSql(aggregation) {
|
|
|
32957
33235
|
const field = aggregation[1];
|
|
32958
33236
|
switch (operation) {
|
|
32959
33237
|
case 'average':
|
|
32960
|
-
return `AVG(
|
|
33238
|
+
return `CAST(AVG(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`average(${field})`)}`;
|
|
32961
33239
|
case 'sum':
|
|
32962
33240
|
case 'max':
|
|
32963
33241
|
case 'min':
|
|
32964
|
-
return
|
|
33242
|
+
return `CAST(${operation.toUpperCase()}(${fieldToSql(field)}) AS DOUBLE) as ${fieldToSql(`${operation}(${field})`)}`;
|
|
32965
33243
|
case 'count':
|
|
32966
|
-
return 'COUNT(*) as
|
|
33244
|
+
return 'CAST(COUNT(*) AS INTEGER) as "count()"'; // we don't need Bigint precision here
|
|
32967
33245
|
}
|
|
32968
33246
|
}
|
|
32969
33247
|
/**
|
|
32970
33248
|
* Leave arguments at null if not used
|
|
33249
|
+
* @param tableName
|
|
32971
33250
|
* @param selected
|
|
32972
33251
|
* @param filter
|
|
32973
33252
|
* @param sort
|
|
@@ -32976,22 +33255,25 @@ function aggregationToSql(aggregation) {
|
|
|
32976
33255
|
* @param groupBy
|
|
32977
33256
|
* @param aggregations
|
|
32978
33257
|
*/
|
|
32979
|
-
function generateSqlQuery(selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null) {
|
|
33258
|
+
function generateSqlQuery(tableName, selected = null, filter = null, sort = null, startIndex = null, count = null, groupBy = null, aggregations = null, geometryColumn = null) {
|
|
32980
33259
|
let sqlSelect = 'SELECT *';
|
|
32981
|
-
const sqlFrom =
|
|
33260
|
+
const sqlFrom = ` FROM ${tableName}`;
|
|
32982
33261
|
let sqlOrderBy = '';
|
|
32983
33262
|
let sqlWhere = '';
|
|
32984
33263
|
let sqlLimit = '';
|
|
32985
33264
|
let sqlGroupBy = '';
|
|
32986
33265
|
if (selected !== null) {
|
|
32987
|
-
sqlSelect = `SELECT ${selected.map(
|
|
33266
|
+
sqlSelect = `SELECT ${selected.map(fieldToSql).join(', ')}`;
|
|
33267
|
+
}
|
|
33268
|
+
if (geometryColumn !== null) {
|
|
33269
|
+
sqlSelect += `, ST_AsGeoJSON(${fieldToSql(geometryColumn)}) as ${GEOMETRY_COLUMN_ALIAS}`;
|
|
32988
33270
|
}
|
|
32989
33271
|
if (filter !== null) {
|
|
32990
33272
|
sqlWhere = ` WHERE ${filterToSql(filter)}`;
|
|
32991
33273
|
}
|
|
32992
33274
|
if (sort?.length) {
|
|
32993
33275
|
sqlOrderBy = ` ORDER BY ${sort
|
|
32994
|
-
.map((sort) =>
|
|
33276
|
+
.map((sort) => `${fieldToSql(sort[1])} ${sort[0].toUpperCase()}`)
|
|
32995
33277
|
.join(', ')}`;
|
|
32996
33278
|
}
|
|
32997
33279
|
if (startIndex !== null && count !== null) {
|
|
@@ -33001,17 +33283,212 @@ function generateSqlQuery(selected = null, filter = null, sort = null, startInde
|
|
|
33001
33283
|
sqlSelect = `SELECT ${aggregations.map(aggregationToSql).join(', ')}`;
|
|
33002
33284
|
const groupedByDistinct = groupBy.filter((group) => group[0] === 'distinct');
|
|
33003
33285
|
const sqlGroupByFields = groupedByDistinct
|
|
33004
|
-
.map((group) =>
|
|
33286
|
+
.map((group) => fieldToSql(group[1]))
|
|
33005
33287
|
.join(', ');
|
|
33006
33288
|
const sqlGroupBySelect = groupedByDistinct
|
|
33007
|
-
.map((group) =>
|
|
33289
|
+
.map((group) => `${fieldToSql(group[1])} as ${fieldToSql(`distinct(${group[1]})`)}`)
|
|
33008
33290
|
.join(', ');
|
|
33009
33291
|
if (sqlGroupByFields && sqlGroupBySelect) {
|
|
33010
33292
|
sqlGroupBy = ` GROUP BY ${sqlGroupByFields}`;
|
|
33011
33293
|
sqlSelect += `, ${sqlGroupBySelect}`;
|
|
33012
33294
|
}
|
|
33013
33295
|
}
|
|
33014
|
-
return sqlSelect + sqlFrom + sqlGroupBy +
|
|
33296
|
+
return sqlSelect + sqlFrom + sqlGroupBy + sqlWhere + sqlOrderBy + sqlLimit;
|
|
33297
|
+
}
|
|
33298
|
+
|
|
33299
|
+
function arrowTableToDataItems(table) {
|
|
33300
|
+
const fields = table.schema.fields;
|
|
33301
|
+
return table.toArray().map((row) => {
|
|
33302
|
+
const rowJson = row.toJSON();
|
|
33303
|
+
const feature = {
|
|
33304
|
+
type: 'Feature',
|
|
33305
|
+
geometry: null,
|
|
33306
|
+
properties: {},
|
|
33307
|
+
};
|
|
33308
|
+
const keys = Object.keys(rowJson);
|
|
33309
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33310
|
+
const key = keys[i];
|
|
33311
|
+
const dataType = fields[i].type;
|
|
33312
|
+
let value = rowJson[key];
|
|
33313
|
+
// this might happen if we get an array inside a field
|
|
33314
|
+
if (value instanceof Vector) {
|
|
33315
|
+
value = Array.from(value);
|
|
33316
|
+
}
|
|
33317
|
+
// cast bigints to ints
|
|
33318
|
+
if (typeof value === 'bigint') {
|
|
33319
|
+
value = Number(value);
|
|
33320
|
+
}
|
|
33321
|
+
// rename columns with empty name
|
|
33322
|
+
if (!key) {
|
|
33323
|
+
feature.properties['unknown'] = value;
|
|
33324
|
+
continue;
|
|
33325
|
+
}
|
|
33326
|
+
// assign properties that look like an id to the geojson `id` field
|
|
33327
|
+
if (/^(object|feature)?_?id$/.test(key.toLowerCase()) &&
|
|
33328
|
+
(typeof value == 'string' || typeof value === 'number')) {
|
|
33329
|
+
feature.id = value;
|
|
33330
|
+
}
|
|
33331
|
+
// if a date is in timestamp (number) format, convert it to native
|
|
33332
|
+
if (typeof value === 'number' &&
|
|
33333
|
+
(DataType.isTimestamp(dataType) || DataType.isDate(dataType))) {
|
|
33334
|
+
value = new Date(value);
|
|
33335
|
+
}
|
|
33336
|
+
// if a binary field (most likely a geometry column): skip
|
|
33337
|
+
if (DataType.isBinary(dataType)) {
|
|
33338
|
+
continue;
|
|
33339
|
+
}
|
|
33340
|
+
// geometry column
|
|
33341
|
+
if (key === GEOMETRY_COLUMN_ALIAS && DataType.isUtf8(dataType)) {
|
|
33342
|
+
feature.geometry = JSON.parse(value);
|
|
33343
|
+
continue;
|
|
33344
|
+
}
|
|
33345
|
+
feature.properties[key] = value;
|
|
33346
|
+
}
|
|
33347
|
+
return feature;
|
|
33348
|
+
});
|
|
33349
|
+
}
|
|
33350
|
+
|
|
33351
|
+
// init code taken from https://github.com/duckdb/duckdb-wasm/blob/main/packages/duckdb-wasm/README.md
|
|
33352
|
+
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
|
|
33353
|
+
// from https://duckdb.org/docs/current/sql/data_types/overview
|
|
33354
|
+
const typesMapping = {
|
|
33355
|
+
INTEGER: 'number',
|
|
33356
|
+
SMALLINT: 'number',
|
|
33357
|
+
TINYINT: 'number',
|
|
33358
|
+
BIGINT: 'number',
|
|
33359
|
+
HUGEINT: 'number',
|
|
33360
|
+
UINTEGER: 'number',
|
|
33361
|
+
USMALLINT: 'number',
|
|
33362
|
+
UTINYINT: 'number',
|
|
33363
|
+
UBIGINT: 'number',
|
|
33364
|
+
UHUGEINT: 'number',
|
|
33365
|
+
DOUBLE: 'number',
|
|
33366
|
+
BIGNUM: 'number',
|
|
33367
|
+
DECIMAL: 'number',
|
|
33368
|
+
NUMERIC: 'number',
|
|
33369
|
+
FLOAT: 'number',
|
|
33370
|
+
REAL: 'number',
|
|
33371
|
+
'TIMESTAMP WITH TIME ZONE': 'date',
|
|
33372
|
+
TIMESTAMP: 'date',
|
|
33373
|
+
DATE: 'date',
|
|
33374
|
+
CHAR: 'string',
|
|
33375
|
+
VARCHAR: 'string',
|
|
33376
|
+
TEXT: 'string',
|
|
33377
|
+
UUID: 'string',
|
|
33378
|
+
BLOB: 'string',
|
|
33379
|
+
BIT: 'string',
|
|
33380
|
+
INTERVAL: 'string',
|
|
33381
|
+
LIST: 'string',
|
|
33382
|
+
BOOLEAN: 'boolean',
|
|
33383
|
+
};
|
|
33384
|
+
class Engine {
|
|
33385
|
+
async makeInit() {
|
|
33386
|
+
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
|
|
33387
|
+
let worker_url = bundle.mainWorker;
|
|
33388
|
+
// this is necessary to let browsers execute WASM code coming from a cross-origin host
|
|
33389
|
+
if (worker_url.startsWith('https://')) {
|
|
33390
|
+
worker_url = URL.createObjectURL(new Blob([`importScripts("${worker_url}");`], {
|
|
33391
|
+
type: 'text/javascript',
|
|
33392
|
+
}));
|
|
33393
|
+
}
|
|
33394
|
+
const worker = new Worker(worker_url);
|
|
33395
|
+
const logger = new duckdb.ConsoleLogger(duckdb.LogLevel.WARNING);
|
|
33396
|
+
this.db = new duckdb.AsyncDuckDB(logger, worker);
|
|
33397
|
+
await this.db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
33398
|
+
// setup duckdb options
|
|
33399
|
+
const conn = await this.db.connect();
|
|
33400
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33401
|
+
await conn.query(`INSTALL spatial; LOAD spatial;`);
|
|
33402
|
+
await conn.query(`SET TimeZone = '${timezone}';`);
|
|
33403
|
+
await conn.query(`SET threads = 1;`);
|
|
33404
|
+
// await conn.query(`SET memory_limit = '2GB';`) // used for experimenting when we encounter memory issues
|
|
33405
|
+
await conn.query(`SET preserve_insertion_order = false;`); // this reduces memory usage when loading a dataset
|
|
33406
|
+
conn.close();
|
|
33407
|
+
return this;
|
|
33408
|
+
}
|
|
33409
|
+
isReady() {
|
|
33410
|
+
if (!this.init_) {
|
|
33411
|
+
this.init_ = this.makeInit();
|
|
33412
|
+
}
|
|
33413
|
+
return this.init_;
|
|
33414
|
+
}
|
|
33415
|
+
/**
|
|
33416
|
+
* Returns information about a dataset once it's loaded:
|
|
33417
|
+
* - a list of properties description
|
|
33418
|
+
* - the name of the dataset geometry column (null if no geometry present)
|
|
33419
|
+
* @param datasetId name of the table under which the dataset will be stored
|
|
33420
|
+
* @param loadQuery duckdb-specific query for creating a table out of the data
|
|
33421
|
+
* @param forceReload if true, any existing data will be dropped and redownloaded
|
|
33422
|
+
*/
|
|
33423
|
+
async loadFile(datasetId, loadQuery, forceReload = false) {
|
|
33424
|
+
const conn = await this.db.connect();
|
|
33425
|
+
let results;
|
|
33426
|
+
// either we want to recreate the table, or we keep it if it already exists
|
|
33427
|
+
const safeLoadQuery = forceReload
|
|
33428
|
+
? `DROP TABLE IF EXISTS ${datasetId};
|
|
33429
|
+
${loadQuery}`
|
|
33430
|
+
: loadQuery.replace(/CREATE TABLE(?! IF NOT EXISTS)/gi, 'CREATE TABLE IF NOT EXISTS');
|
|
33431
|
+
// create the table
|
|
33432
|
+
try {
|
|
33433
|
+
results = await conn.query(safeLoadQuery);
|
|
33434
|
+
}
|
|
33435
|
+
catch (e) {
|
|
33436
|
+
throw new FetchError('parse', `DuckDB encountered an error when loading the data: ${e.message}`);
|
|
33437
|
+
}
|
|
33438
|
+
// read rows count
|
|
33439
|
+
results = await conn.query(`SELECT count(*) FROM ${datasetId}`);
|
|
33440
|
+
const { 'count_star()': recordsCount } = results.toArray()[0].toJSON();
|
|
33441
|
+
// read columns
|
|
33442
|
+
results = await conn.query(`SELECT * FROM information_schema.columns WHERE table_name = '${datasetId}';`);
|
|
33443
|
+
let geometryColumn = null;
|
|
33444
|
+
const properties = results
|
|
33445
|
+
.toArray()
|
|
33446
|
+
.map((row) => {
|
|
33447
|
+
const rowObj = row.toJSON();
|
|
33448
|
+
if (rowObj['data_type'] === 'GEOMETRY') {
|
|
33449
|
+
// the geometry is not part of the properties
|
|
33450
|
+
// note: right now we only keep one geometry column name, but if there are multiple they will
|
|
33451
|
+
// all get discarded
|
|
33452
|
+
geometryColumn = rowObj['column_name'];
|
|
33453
|
+
return null;
|
|
33454
|
+
}
|
|
33455
|
+
return {
|
|
33456
|
+
name: rowObj['column_name'],
|
|
33457
|
+
label: rowObj['column_name'],
|
|
33458
|
+
type: typesMapping[rowObj['data_type']] ?? 'other',
|
|
33459
|
+
};
|
|
33460
|
+
})
|
|
33461
|
+
.filter((prop) => prop !== null);
|
|
33462
|
+
conn.close();
|
|
33463
|
+
return {
|
|
33464
|
+
properties,
|
|
33465
|
+
geometryColumn,
|
|
33466
|
+
rowsCount: Number(recordsCount),
|
|
33467
|
+
};
|
|
33468
|
+
}
|
|
33469
|
+
// register a Uint8 buffer using a handle in the duckdb instance
|
|
33470
|
+
async registerData(name, buffer) {
|
|
33471
|
+
return this.db.registerFileBuffer(name, buffer);
|
|
33472
|
+
}
|
|
33473
|
+
/**
|
|
33474
|
+
* @param query duckdb-specific query for fetching items
|
|
33475
|
+
*/
|
|
33476
|
+
async queryItems(query) {
|
|
33477
|
+
const conn = await this.db.connect();
|
|
33478
|
+
const results = await conn.query(query);
|
|
33479
|
+
conn.close();
|
|
33480
|
+
return arrowTableToDataItems(results);
|
|
33481
|
+
}
|
|
33482
|
+
close() {
|
|
33483
|
+
this.db?.terminate();
|
|
33484
|
+
}
|
|
33485
|
+
}
|
|
33486
|
+
let engine = null;
|
|
33487
|
+
async function getEngine() {
|
|
33488
|
+
if (!engine) {
|
|
33489
|
+
engine = new Engine();
|
|
33490
|
+
}
|
|
33491
|
+
return engine.isReady();
|
|
33015
33492
|
}
|
|
33016
33493
|
|
|
33017
33494
|
class BaseReader {
|
|
@@ -33024,10 +33501,18 @@ class BaseReader {
|
|
|
33024
33501
|
this.sort = null;
|
|
33025
33502
|
this.startIndex = null;
|
|
33026
33503
|
this.count = null;
|
|
33504
|
+
this.loadPromise_ = Promise.resolve();
|
|
33505
|
+
this.cacheEnabled = false;
|
|
33506
|
+
}
|
|
33507
|
+
enableCache(enabled) {
|
|
33508
|
+
this.cacheEnabled = enabled;
|
|
33027
33509
|
}
|
|
33028
33510
|
load() {
|
|
33029
33511
|
throw new Error('not implemented');
|
|
33030
33512
|
}
|
|
33513
|
+
get isLoaded() {
|
|
33514
|
+
return this.loadPromise_;
|
|
33515
|
+
}
|
|
33031
33516
|
get properties() {
|
|
33032
33517
|
throw new Error('not implemented');
|
|
33033
33518
|
}
|
|
@@ -33076,178 +33561,237 @@ class BaseReader {
|
|
|
33076
33561
|
}
|
|
33077
33562
|
}
|
|
33078
33563
|
|
|
33079
|
-
|
|
33080
|
-
|
|
33081
|
-
|
|
33082
|
-
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33564
|
+
/**
|
|
33565
|
+
* This reader handles file formats supported natively by DuckDB
|
|
33566
|
+
*/
|
|
33567
|
+
class BaseFileReader extends BaseReader {
|
|
33568
|
+
// a table id should not exceed 63 chars
|
|
33569
|
+
generateDatasetId() {
|
|
33570
|
+
// generate a hash out of the url
|
|
33571
|
+
let hash = 0;
|
|
33572
|
+
for (const char of this.url) {
|
|
33573
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
33574
|
+
hash = hash >>> 0; // make it unsigned
|
|
33575
|
+
}
|
|
33576
|
+
return `datafetcher_${hash.toString(16)}`;
|
|
33577
|
+
}
|
|
33578
|
+
async getLoadQuery() {
|
|
33092
33579
|
throw new Error('not implemented');
|
|
33093
33580
|
}
|
|
33094
|
-
load() {
|
|
33095
|
-
this.
|
|
33581
|
+
async load() {
|
|
33582
|
+
this.datasetId = this.generateDatasetId();
|
|
33583
|
+
this.loadPromise_ = getEngine()
|
|
33584
|
+
.then((engine) => {
|
|
33585
|
+
this.engine = engine;
|
|
33586
|
+
return this.getLoadQuery();
|
|
33587
|
+
})
|
|
33588
|
+
.then((loadQuery) => this.engine.loadFile(this.datasetId, loadQuery, !this.cacheEnabled))
|
|
33589
|
+
.then((datasetInfo) => {
|
|
33590
|
+
this.properties_ = datasetInfo.properties;
|
|
33591
|
+
this.geometryColumn = datasetInfo.geometryColumn;
|
|
33592
|
+
this.rowsCount = datasetInfo.rowsCount;
|
|
33593
|
+
// returns void for the loaded promise
|
|
33594
|
+
});
|
|
33096
33595
|
}
|
|
33097
33596
|
get properties() {
|
|
33098
|
-
return this.
|
|
33597
|
+
return this.isLoaded.then(() => this.properties_);
|
|
33099
33598
|
}
|
|
33100
33599
|
get info() {
|
|
33101
|
-
return this.
|
|
33102
|
-
itemsCount:
|
|
33600
|
+
return this.isLoaded.then(() => ({
|
|
33601
|
+
itemsCount: this.rowsCount,
|
|
33602
|
+
hasGeometry: !!this.geometryColumn,
|
|
33103
33603
|
}));
|
|
33104
33604
|
}
|
|
33105
33605
|
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'));
|
|
33606
|
+
await this.isLoaded;
|
|
33607
|
+
// if only certain fields are selected, omit the geometry
|
|
33608
|
+
const geometryColumn = this.selected === null ? this.geometryColumn : null;
|
|
33609
|
+
const query = generateSqlQuery(this.datasetId, this.selected, this.filter, this.sort, this.startIndex, this.count, this.groupedBy, this.aggregations, geometryColumn);
|
|
33610
|
+
return this.engine.queryItems(query);
|
|
33148
33611
|
}
|
|
33149
|
-
const items = parsed.data.map(jsonToGeojsonFeature);
|
|
33150
|
-
return processItemProperties(items, true);
|
|
33151
33612
|
}
|
|
33613
|
+
|
|
33152
33614
|
class CsvReader extends BaseFileReader {
|
|
33153
|
-
|
|
33154
|
-
|
|
33615
|
+
async getLoadQuery() {
|
|
33616
|
+
// first we get a list of columns hich have a detected type of VARCHAR
|
|
33617
|
+
// 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
|
|
33618
|
+
return `
|
|
33619
|
+
SET VARIABLE strColumns = (SELECT list(name) FROM (SELECT unnest(Columns, recursive := true) FROM sniff_csv("${this.url}")) WHERE type = 'VARCHAR');
|
|
33620
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_csv("${this.url}",
|
|
33621
|
+
force_not_null = getvariable('strColumns'),
|
|
33622
|
+
auto_type_candidates = ['NULL', 'BOOLEAN', 'INTEGER', 'DOUBLE', 'DATE', 'VARCHAR']
|
|
33623
|
+
);`;
|
|
33155
33624
|
}
|
|
33156
33625
|
}
|
|
33157
33626
|
|
|
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
33627
|
class JsonReader extends BaseFileReader {
|
|
33170
|
-
|
|
33171
|
-
return
|
|
33628
|
+
async getLoadQuery() {
|
|
33629
|
+
return `
|
|
33630
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM read_json("${this.url}",
|
|
33631
|
+
maximum_object_size = 536870912 -- 500MB
|
|
33632
|
+
);`;
|
|
33172
33633
|
}
|
|
33173
33634
|
}
|
|
33174
33635
|
|
|
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
33636
|
class GeojsonReader extends BaseFileReader {
|
|
33189
|
-
|
|
33190
|
-
return
|
|
33637
|
+
async getLoadQuery() {
|
|
33638
|
+
return `
|
|
33639
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33640
|
+
allowed_drivers = ['GeoJSON']
|
|
33641
|
+
);`;
|
|
33191
33642
|
}
|
|
33192
33643
|
}
|
|
33193
33644
|
|
|
33645
|
+
async function inferDatasetType(url, typeHint) {
|
|
33646
|
+
const fileExtensionMatches = new URL(url, typeof window !== 'undefined' ? window.location.toString() : undefined).pathname.match(/\.(.+)$/);
|
|
33647
|
+
const fileExtension = fileExtensionMatches && fileExtensionMatches.length
|
|
33648
|
+
? fileExtensionMatches[1].toLowerCase()
|
|
33649
|
+
: null;
|
|
33650
|
+
// 1. type hint
|
|
33651
|
+
if (typeHint)
|
|
33652
|
+
return Promise.resolve(typeHint);
|
|
33653
|
+
// 2. content-type header
|
|
33654
|
+
const headers = await fetchHeaders(url);
|
|
33655
|
+
if ('supportedType' in headers)
|
|
33656
|
+
return headers.supportedType;
|
|
33657
|
+
// 3. file extension from url
|
|
33658
|
+
else if (SupportedTypes.indexOf(fileExtension) > -1)
|
|
33659
|
+
return fileExtension;
|
|
33660
|
+
// no type inferred or hinted
|
|
33661
|
+
if ('mimeType' in headers)
|
|
33662
|
+
throw FetchError.unsupportedType(headers.mimeType);
|
|
33663
|
+
else
|
|
33664
|
+
throw FetchError.unknownType();
|
|
33665
|
+
}
|
|
33666
|
+
function fetchHeaders(url) {
|
|
33667
|
+
return sharedFetch(url, 'HEAD')
|
|
33668
|
+
.catch((error) => {
|
|
33669
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33670
|
+
})
|
|
33671
|
+
.then((response) => {
|
|
33672
|
+
if (!response.ok) {
|
|
33673
|
+
throw FetchError.http(response.status);
|
|
33674
|
+
}
|
|
33675
|
+
return parseHeaders(response.headers);
|
|
33676
|
+
});
|
|
33677
|
+
}
|
|
33678
|
+
function fetchDataAsText(url, cacheActive) {
|
|
33679
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33680
|
+
.catch((error) => {
|
|
33681
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33682
|
+
})
|
|
33683
|
+
.then(async (response) => {
|
|
33684
|
+
if (!response.ok) {
|
|
33685
|
+
const clonedResponse = response.clone();
|
|
33686
|
+
throw FetchError.http(response.status, await clonedResponse.text());
|
|
33687
|
+
}
|
|
33688
|
+
const clonedResponse = response.clone();
|
|
33689
|
+
return clonedResponse.text();
|
|
33690
|
+
});
|
|
33691
|
+
return cacheActive ? useCache(fetchFactory, url, 'asText') : fetchFactory();
|
|
33692
|
+
}
|
|
33693
|
+
function fetchDataAsArrayBuffer(url, cacheActive) {
|
|
33694
|
+
const fetchFactory = () => sharedFetch(url)
|
|
33695
|
+
.catch((error) => {
|
|
33696
|
+
throw FetchError.corsOrNetwork(error.message);
|
|
33697
|
+
})
|
|
33698
|
+
.then(async (response) => {
|
|
33699
|
+
if (!response.ok) {
|
|
33700
|
+
throw FetchError.http(response.status, await response.text());
|
|
33701
|
+
}
|
|
33702
|
+
// convert to a numeric array so that we can store the response in cache
|
|
33703
|
+
return Array.from(new Uint8Array(await response.arrayBuffer()));
|
|
33704
|
+
});
|
|
33705
|
+
return (cacheActive ? useCache(fetchFactory, url, 'asArrayBuffer') : fetchFactory()).then((array) => {
|
|
33706
|
+
return new Uint8Array(array).buffer;
|
|
33707
|
+
});
|
|
33708
|
+
}
|
|
33194
33709
|
/**
|
|
33195
|
-
* This
|
|
33196
|
-
*
|
|
33197
|
-
* @param
|
|
33710
|
+
* This creates a Proxy that allows reading and writing to the data item properties
|
|
33711
|
+
* as if it was a simple array of JSON objects
|
|
33712
|
+
* @param items
|
|
33198
33713
|
*/
|
|
33199
|
-
function
|
|
33200
|
-
return
|
|
33201
|
-
|
|
33202
|
-
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
|
|
33207
|
-
|
|
33714
|
+
function getJsonDataItemsProxy(items) {
|
|
33715
|
+
return new Proxy(items, {
|
|
33716
|
+
get(target, p) {
|
|
33717
|
+
if (typeof p === 'string' &&
|
|
33718
|
+
!Number.isNaN(parseInt(p)) &&
|
|
33719
|
+
target[p]?.properties) {
|
|
33720
|
+
return target[p].properties;
|
|
33721
|
+
}
|
|
33722
|
+
return target[p];
|
|
33723
|
+
},
|
|
33724
|
+
set() {
|
|
33725
|
+
throw new Error('This object is read-only');
|
|
33726
|
+
},
|
|
33208
33727
|
});
|
|
33209
33728
|
}
|
|
33729
|
+
|
|
33210
33730
|
class ExcelReader extends BaseFileReader {
|
|
33211
|
-
|
|
33212
|
-
|
|
33731
|
+
async getLoadQuery() {
|
|
33732
|
+
// we download the file as an array buffer first, in order to be able to check if it's an XLS file
|
|
33733
|
+
let buffer = await fetchDataAsArrayBuffer(this.url, this.cacheEnabled);
|
|
33734
|
+
const bufferHandle = `B${this.datasetId}`;
|
|
33735
|
+
// checking against the magic number at the beginning of XLS files, see https://en.wikipedia.org/wiki/List_of_file_signatures
|
|
33736
|
+
const magicNumber = new Uint8Array(buffer, 0, 8); // first 8 bytes
|
|
33737
|
+
const isXls = Array.from(magicNumber)
|
|
33738
|
+
.map((n) => n.toString(16).toUpperCase())
|
|
33739
|
+
.join(' ') === 'D0 CF 11 E0 A1 B1 1A E1';
|
|
33740
|
+
// uh oh, this is an XLS file (not supported by duckdb); convert it to CSV using the xlsx package
|
|
33741
|
+
if (isXls) {
|
|
33742
|
+
buffer = await import('xlsx').then(({ read, utils }) => {
|
|
33743
|
+
const workbook = read(buffer);
|
|
33744
|
+
const json = utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
|
|
33745
|
+
return new TextEncoder().encode(JSON.stringify(json)).buffer;
|
|
33746
|
+
});
|
|
33747
|
+
}
|
|
33748
|
+
const duckDbFn = isXls ? 'read_json' : 'read_xlsx';
|
|
33749
|
+
await this.engine.registerData(bufferHandle, new Uint8Array(buffer));
|
|
33750
|
+
return `
|
|
33751
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM ${duckDbFn}("${bufferHandle}", ignore_errors = true);`;
|
|
33213
33752
|
}
|
|
33214
33753
|
}
|
|
33215
33754
|
|
|
33216
|
-
|
|
33217
|
-
|
|
33218
|
-
|
|
33755
|
+
class GmlReader extends BaseFileReader {
|
|
33756
|
+
async getLoadQuery() {
|
|
33757
|
+
return `
|
|
33758
|
+
CREATE TABLE ${this.datasetId} AS SELECT * FROM st_read("${this.url}",
|
|
33759
|
+
allowed_drivers = ['GML']
|
|
33760
|
+
);`;
|
|
33761
|
+
}
|
|
33762
|
+
}
|
|
33763
|
+
|
|
33764
|
+
const formatGeojson = new GeoJSON$1();
|
|
33765
|
+
function parseGeojson(text) {
|
|
33766
|
+
const parsed = JSON.parse(text);
|
|
33767
|
+
const features = parsed.type === 'FeatureCollection' ? parsed.features : parsed;
|
|
33768
|
+
if (!Array.isArray(features)) {
|
|
33769
|
+
throw new Error('Could not parse GeoJSON, expected a features collection or an array of features at root level');
|
|
33770
|
+
}
|
|
33771
|
+
return features;
|
|
33772
|
+
}
|
|
33773
|
+
function parseGml(text, featureType, version) {
|
|
33774
|
+
const parts = featureType.split(':');
|
|
33775
|
+
const regex = new RegExp(`xmlns:${parts[0]}=["']([^'"]*)["']`);
|
|
33219
33776
|
const match = regex.exec(text);
|
|
33220
33777
|
if (match && match.length >= 2) {
|
|
33221
|
-
const
|
|
33778
|
+
const wfs = new WFS({
|
|
33222
33779
|
featureNS: match[1],
|
|
33223
|
-
featureType:
|
|
33780
|
+
featureType: parts[1],
|
|
33224
33781
|
version: version,
|
|
33225
33782
|
});
|
|
33226
33783
|
let features;
|
|
33227
33784
|
try {
|
|
33228
|
-
features =
|
|
33785
|
+
features = wfs.readFeatures(text);
|
|
33229
33786
|
}
|
|
33230
33787
|
catch (e) {
|
|
33231
|
-
throw Error(
|
|
33788
|
+
throw Error(`Couldn't parse WFS with GML features: ${e.message}`);
|
|
33232
33789
|
}
|
|
33233
|
-
const geojsonItem =
|
|
33234
|
-
return
|
|
33790
|
+
const geojsonItem = formatGeojson.writeFeaturesObject(features);
|
|
33791
|
+
return geojsonItem.features;
|
|
33235
33792
|
}
|
|
33236
33793
|
throw Error("Couldn't retrieve namespace url");
|
|
33237
33794
|
}
|
|
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
33795
|
async function getWfsEndpoint(wfsUrl) {
|
|
33252
33796
|
try {
|
|
33253
33797
|
return await new WfsEndpoint(wfsUrl).isReady();
|
|
@@ -33275,21 +33819,65 @@ async function getWfsEndpoint(wfsUrl) {
|
|
|
33275
33819
|
}
|
|
33276
33820
|
}
|
|
33277
33821
|
}
|
|
33278
|
-
class WfsReader extends
|
|
33279
|
-
constructor(url,
|
|
33280
|
-
super(url
|
|
33281
|
-
this.endpoint =
|
|
33282
|
-
this.
|
|
33283
|
-
|
|
33822
|
+
class WfsReader extends BaseReader {
|
|
33823
|
+
constructor(url, featureTypeName) {
|
|
33824
|
+
super(url);
|
|
33825
|
+
this.endpoint = getWfsEndpoint(url);
|
|
33826
|
+
this.featureType = this.endpoint
|
|
33827
|
+
.then((endpoint) => {
|
|
33828
|
+
const featureTypes = endpoint.getFeatureTypes();
|
|
33829
|
+
return endpoint.getFeatureTypeFull(featureTypes.length === 1 && !featureTypeName
|
|
33830
|
+
? featureTypes[0].name
|
|
33831
|
+
: featureTypeName);
|
|
33832
|
+
})
|
|
33833
|
+
.then((featureType) => {
|
|
33834
|
+
if (!featureType) {
|
|
33835
|
+
throw new Error('wfs.featuretype.notfound');
|
|
33836
|
+
}
|
|
33837
|
+
return featureType;
|
|
33838
|
+
});
|
|
33839
|
+
}
|
|
33840
|
+
get backupReader() {
|
|
33841
|
+
if (this.backupReader_) {
|
|
33842
|
+
return this.backupReader_;
|
|
33843
|
+
}
|
|
33844
|
+
this.backupReader_ = Promise.all([this.endpoint, this.featureType]).then(([endpoint, featureType]) => {
|
|
33845
|
+
let reader;
|
|
33846
|
+
if (endpoint.supportsJson(featureType.name)) {
|
|
33847
|
+
reader = new GeojsonReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33848
|
+
asJson: true,
|
|
33849
|
+
outputCrs: 'EPSG:4326',
|
|
33850
|
+
}));
|
|
33851
|
+
}
|
|
33852
|
+
else {
|
|
33853
|
+
if (featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')) &&
|
|
33854
|
+
(featureType.defaultCrs === 'EPSG:4326' ||
|
|
33855
|
+
featureType.otherCrs?.includes('EPSG:4326'))) {
|
|
33856
|
+
reader = new GmlReader(endpoint.getFeatureUrl(featureType.name, {
|
|
33857
|
+
outputFormat: featureType.outputFormats.find((f) => f.toLowerCase().includes('gml')),
|
|
33858
|
+
outputCrs: 'EPSG:4326',
|
|
33859
|
+
}));
|
|
33860
|
+
}
|
|
33861
|
+
}
|
|
33862
|
+
reader.enableCache(this.cacheEnabled);
|
|
33863
|
+
reader.load();
|
|
33864
|
+
return reader;
|
|
33865
|
+
});
|
|
33866
|
+
return this.backupReader_;
|
|
33284
33867
|
}
|
|
33285
33868
|
get properties() {
|
|
33286
|
-
return this.
|
|
33287
|
-
.getFeatureTypeFull(this.featureTypeName)
|
|
33288
|
-
.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33869
|
+
return this.featureType.then((featureType) => Object.keys(featureType.properties).map((prop) => {
|
|
33289
33870
|
const originalType = featureType.properties[prop];
|
|
33290
|
-
|
|
33291
|
-
|
|
33292
|
-
|
|
33871
|
+
let type;
|
|
33872
|
+
if (originalType === 'float' || originalType === 'integer') {
|
|
33873
|
+
type = 'number';
|
|
33874
|
+
}
|
|
33875
|
+
else if (originalType === 'boolean') {
|
|
33876
|
+
type = 'string'; // we don't handle booleans yet in the data fetcher
|
|
33877
|
+
}
|
|
33878
|
+
else {
|
|
33879
|
+
type = originalType;
|
|
33880
|
+
}
|
|
33293
33881
|
return {
|
|
33294
33882
|
name: prop,
|
|
33295
33883
|
label: prop,
|
|
@@ -33298,83 +33886,63 @@ class WfsReader extends BaseCacheReader {
|
|
|
33298
33886
|
}));
|
|
33299
33887
|
}
|
|
33300
33888
|
get info() {
|
|
33301
|
-
return this.
|
|
33889
|
+
return this.featureType.then((result) => ({
|
|
33302
33890
|
itemsCount: result.objectCount,
|
|
33891
|
+
hasGeometry: !!result.geometryName,
|
|
33303
33892
|
}));
|
|
33304
33893
|
}
|
|
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
|
-
}
|
|
33894
|
+
load() {
|
|
33895
|
+
// Nothing to load for Wfs
|
|
33334
33896
|
}
|
|
33335
|
-
async
|
|
33336
|
-
|
|
33337
|
-
|
|
33897
|
+
async read() {
|
|
33898
|
+
const endpoint = await this.endpoint;
|
|
33899
|
+
const featureType = await this.featureType;
|
|
33900
|
+
// if we can't use the WFS protocol we fall back to the backup reader
|
|
33901
|
+
if (this.aggregations || this.groupedBy || !endpoint.supportsStartIndex()) {
|
|
33902
|
+
const backupReader = await this.backupReader;
|
|
33903
|
+
backupReader.selectAll();
|
|
33904
|
+
if (this.selected) {
|
|
33905
|
+
backupReader.select(...this.selected);
|
|
33906
|
+
}
|
|
33907
|
+
if (this.aggregations) {
|
|
33908
|
+
backupReader.aggregate(...this.aggregations);
|
|
33909
|
+
}
|
|
33910
|
+
if (this.groupedBy) {
|
|
33911
|
+
backupReader.groupBy(...this.groupedBy);
|
|
33912
|
+
}
|
|
33913
|
+
if (this.sort) {
|
|
33914
|
+
backupReader.orderBy(...this.sort);
|
|
33915
|
+
}
|
|
33916
|
+
if (this.startIndex !== null && this.count !== null) {
|
|
33917
|
+
backupReader.limit(this.startIndex, this.count);
|
|
33918
|
+
}
|
|
33919
|
+
return backupReader.read();
|
|
33338
33920
|
}
|
|
33339
|
-
const asJson =
|
|
33921
|
+
const asJson = endpoint.supportsJson(featureType.name);
|
|
33340
33922
|
const attributes = this.selected ?? undefined;
|
|
33341
|
-
let
|
|
33923
|
+
let sortBy = null;
|
|
33924
|
+
if (this.sort) {
|
|
33925
|
+
const mapSort = (s) => [s[0] === 'desc' ? 'D' : 'A', s[1]];
|
|
33926
|
+
sortBy = Array.isArray(this.sort[0])
|
|
33927
|
+
? this.sort.map(mapSort)
|
|
33928
|
+
: mapSort(this.sort);
|
|
33929
|
+
}
|
|
33930
|
+
const url = endpoint.getFeatureUrl(featureType.name, {
|
|
33342
33931
|
...(this.startIndex !== null && { startIndex: this.startIndex }),
|
|
33343
33932
|
...(this.count !== null && { maxFeatures: this.count }),
|
|
33344
33933
|
asJson,
|
|
33345
33934
|
outputCrs: 'EPSG:4326',
|
|
33346
33935
|
attributes,
|
|
33347
|
-
|
|
33936
|
+
sortBy,
|
|
33348
33937
|
});
|
|
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
|
|
33938
|
+
return fetchDataAsText(url, this.cacheEnabled).then((text) => asJson
|
|
33358
33939
|
? 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;
|
|
33940
|
+
: parseGml(text, featureType.name, endpoint.getVersion()));
|
|
33373
33941
|
}
|
|
33374
33942
|
}
|
|
33375
33943
|
|
|
33376
|
-
async function openDataset(url,
|
|
33377
|
-
const fileType = await inferDatasetType(url, typeHint);
|
|
33944
|
+
async function openDataset(url, options) {
|
|
33945
|
+
const fileType = await inferDatasetType(url, options?.typeHint);
|
|
33378
33946
|
let reader;
|
|
33379
33947
|
try {
|
|
33380
33948
|
switch (fileType) {
|
|
@@ -33391,18 +33959,18 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33391
33959
|
reader = new ExcelReader(url);
|
|
33392
33960
|
break;
|
|
33393
33961
|
case 'gml':
|
|
33394
|
-
reader = new GmlReader(url
|
|
33962
|
+
reader = new GmlReader(url);
|
|
33395
33963
|
break;
|
|
33396
33964
|
case 'wfs':
|
|
33397
|
-
reader =
|
|
33965
|
+
reader = new WfsReader(url, options?.wfsFeatureType);
|
|
33398
33966
|
break;
|
|
33399
33967
|
}
|
|
33400
|
-
reader.
|
|
33968
|
+
reader.enableCache(options?.enableCache ?? true);
|
|
33401
33969
|
reader.load();
|
|
33402
33970
|
return reader;
|
|
33403
33971
|
}
|
|
33404
33972
|
catch (e) {
|
|
33405
|
-
//WfsReader may already raise a FetchError
|
|
33973
|
+
// WfsReader may already raise a FetchError
|
|
33406
33974
|
if (e instanceof FetchError)
|
|
33407
33975
|
throw e;
|
|
33408
33976
|
else
|
|
@@ -33413,13 +33981,13 @@ async function openDataset(url, typeHint, options, cacheActive) {
|
|
|
33413
33981
|
* This fetches the full dataset at the given URL and parses it according to its mime type.
|
|
33414
33982
|
* All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
|
|
33415
33983
|
* File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
|
|
33416
|
-
* File type is determined
|
|
33984
|
+
* File type is determined like so:
|
|
33417
33985
|
* 1. if a type hint is given, use it
|
|
33418
33986
|
* 2. otherwise, look for a Content-Type header in the response with a supported mime type
|
|
33419
33987
|
* 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
|
|
33420
33988
|
*/
|
|
33421
|
-
async function readDataset(url,
|
|
33422
|
-
const reader = await openDataset(url,
|
|
33989
|
+
async function readDataset(url, options) {
|
|
33990
|
+
const reader = await openDataset(url, options);
|
|
33423
33991
|
try {
|
|
33424
33992
|
return await reader.read();
|
|
33425
33993
|
}
|
|
@@ -33650,9 +34218,11 @@ class DataService {
|
|
|
33650
34218
|
getDataset(link, cacheActive) {
|
|
33651
34219
|
if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
|
|
33652
34220
|
const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString());
|
|
33653
|
-
return from(openDataset(wfsUrlEndpoint,
|
|
34221
|
+
return from(openDataset(wfsUrlEndpoint, {
|
|
34222
|
+
typeHint: 'wfs',
|
|
33654
34223
|
wfsFeatureType: link.name,
|
|
33655
|
-
|
|
34224
|
+
enableCache: cacheActive,
|
|
34225
|
+
}));
|
|
33656
34226
|
}
|
|
33657
34227
|
else if (link.type === 'download') {
|
|
33658
34228
|
const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString());
|
|
@@ -33660,12 +34230,15 @@ class DataService {
|
|
|
33660
34230
|
const supportedType = SupportedTypes.indexOf(format) > -1
|
|
33661
34231
|
? format
|
|
33662
34232
|
: undefined;
|
|
33663
|
-
return from(openDataset(linkProxifiedUrl,
|
|
34233
|
+
return from(openDataset(linkProxifiedUrl, {
|
|
34234
|
+
typeHint: supportedType,
|
|
34235
|
+
enableCache: cacheActive,
|
|
34236
|
+
})).pipe();
|
|
33664
34237
|
}
|
|
33665
34238
|
else if (link.type === 'service' &&
|
|
33666
34239
|
link.accessServiceProtocol === 'esriRest') {
|
|
33667
34240
|
const url = this.getDownloadUrlFromEsriRest(link.url.toString(), 'geojson');
|
|
33668
|
-
return from(openDataset(url, 'geojson',
|
|
34241
|
+
return from(openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })).pipe();
|
|
33669
34242
|
}
|
|
33670
34243
|
else if (link.type === 'service' &&
|
|
33671
34244
|
link.accessServiceProtocol === 'ogcFeatures') {
|
|
@@ -33679,7 +34252,10 @@ class DataService {
|
|
|
33679
34252
|
}
|
|
33680
34253
|
const urlWithoutLimit = new URL(geojsonUrl);
|
|
33681
34254
|
urlWithoutLimit.searchParams.delete('limit');
|
|
33682
|
-
return openDataset(urlWithoutLimit.toString(),
|
|
34255
|
+
return openDataset(urlWithoutLimit.toString(), {
|
|
34256
|
+
typeHint: 'geojson',
|
|
34257
|
+
enableCache: cacheActive,
|
|
34258
|
+
});
|
|
33683
34259
|
}));
|
|
33684
34260
|
}
|
|
33685
34261
|
return throwError(() => 'protocol not supported');
|
|
@@ -33931,20 +34507,31 @@ class DataTableComponent {
|
|
|
33931
34507
|
this.eltRef = inject(ElementRef);
|
|
33932
34508
|
this.cdr = inject(ChangeDetectorRef);
|
|
33933
34509
|
this.translateService = inject(TranslateService);
|
|
33934
|
-
this.
|
|
34510
|
+
this.columnsFromFeatureCatalog = null;
|
|
34511
|
+
this.columnsFromDataset = [];
|
|
33935
34512
|
this.selected = new EventEmitter();
|
|
33936
|
-
this.properties$ = new BehaviorSubject(null);
|
|
33937
34513
|
this.loading$ = new BehaviorSubject(false);
|
|
33938
34514
|
this.error = null;
|
|
33939
34515
|
}
|
|
33940
34516
|
set featureAttributes(value) {
|
|
33941
|
-
this.
|
|
33942
|
-
|
|
34517
|
+
this.columnsFromFeatureCatalog = value.map((attrs) => ({
|
|
34518
|
+
name: attrs.value,
|
|
34519
|
+
label: attrs.label,
|
|
34520
|
+
}));
|
|
33943
34521
|
}
|
|
33944
34522
|
set dataset(value) {
|
|
33945
34523
|
this.dataset_ = value;
|
|
33946
34524
|
this.dataset_.load();
|
|
33947
|
-
this.dataset_.info.then((info) =>
|
|
34525
|
+
this.dataset_.info.then((info) => {
|
|
34526
|
+
this.count = info.itemsCount;
|
|
34527
|
+
this.cdr.detectChanges();
|
|
34528
|
+
});
|
|
34529
|
+
}
|
|
34530
|
+
get columns() {
|
|
34531
|
+
return this.columnsFromFeatureCatalog ?? this.columnsFromDataset;
|
|
34532
|
+
}
|
|
34533
|
+
get columnNames() {
|
|
34534
|
+
return this.columns.map((c) => c.name);
|
|
33948
34535
|
}
|
|
33949
34536
|
ngOnInit() {
|
|
33950
34537
|
this.dataSource = new DataTableDataSource();
|
|
@@ -33979,11 +34566,12 @@ class DataTableComponent {
|
|
|
33979
34566
|
}
|
|
33980
34567
|
async readData() {
|
|
33981
34568
|
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
34569
|
try {
|
|
34570
|
+
// wait for properties to be read
|
|
34571
|
+
if (!this.columnsFromFeatureCatalog) {
|
|
34572
|
+
this.columnsFromDataset = await this.dataset_.properties;
|
|
34573
|
+
}
|
|
34574
|
+
this.dataset_.select(...this.columnNames);
|
|
33987
34575
|
await this.dataSource.showData(this.dataset_.read());
|
|
33988
34576
|
this.error = null;
|
|
33989
34577
|
}
|
|
@@ -34013,7 +34601,7 @@ class DataTableComponent {
|
|
|
34013
34601
|
}
|
|
34014
34602
|
}
|
|
34015
34603
|
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
|
|
34604
|
+
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
34605
|
}
|
|
34018
34606
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
34019
34607
|
type: Component,
|
|
@@ -34025,10 +34613,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
34025
34613
|
CommonModule,
|
|
34026
34614
|
LoadingMaskComponent,
|
|
34027
34615
|
PopupAlertComponent,
|
|
34028
|
-
LetDirective,
|
|
34029
34616
|
TranslatePipe,
|
|
34030
34617
|
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
|
|
34618
|
+
], 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
34619
|
}], propDecorators: { featureAttributes: [{
|
|
34033
34620
|
type: Input
|
|
34034
34621
|
}], dataset: [{
|
|
@@ -34131,7 +34718,7 @@ class ChartViewComponent {
|
|
|
34131
34718
|
}), shareReplay$1(1));
|
|
34132
34719
|
this.properties$ = combineLatest([this.dataset$, this.featureCatalog$]).pipe(switchMap$1(([dataset, catalog]) => this.setProperties(dataset, catalog)), shareReplay$1(1));
|
|
34133
34720
|
this.yChoices$ = this.properties$.pipe(map$1((properties) => properties
|
|
34134
|
-
.filter((prop) => prop.type === 'number'
|
|
34721
|
+
.filter((prop) => prop.type === 'number')
|
|
34135
34722
|
.map((prop) => ({ value: prop.name, label: prop.label || prop.name }))), tap$1((choices) => {
|
|
34136
34723
|
if (!choices.find((choice) => choice.value === this.yProperty$.value)) {
|
|
34137
34724
|
const newProp = choices[0]?.value || '';
|
|
@@ -34158,6 +34745,7 @@ class ChartViewComponent {
|
|
|
34158
34745
|
this.aggregation$,
|
|
34159
34746
|
]).pipe(filter$1(([_, x, y]) => !!x || !!y), switchMap$1(([dataset, xProp, yProp, aggregation]) => {
|
|
34160
34747
|
const fieldAgg = aggregation === 'count' ? ['count'] : [aggregation, yProp];
|
|
34748
|
+
this.loading = true;
|
|
34161
34749
|
return dataset
|
|
34162
34750
|
.groupBy(['distinct', xProp])
|
|
34163
34751
|
.aggregate(fieldAgg)
|
|
@@ -34399,6 +34987,7 @@ class GeoTableViewComponent {
|
|
|
34399
34987
|
}));
|
|
34400
34988
|
}
|
|
34401
34989
|
async initMapContext() {
|
|
34990
|
+
this.dataset.load();
|
|
34402
34991
|
this.dataset.selectAll();
|
|
34403
34992
|
return {
|
|
34404
34993
|
layers: [
|
|
@@ -34572,8 +35161,7 @@ class MdViewFacade {
|
|
|
34572
35161
|
}));
|
|
34573
35162
|
this.error$ = this.store.pipe(select(getMetadataError));
|
|
34574
35163
|
this.related$ = this.store.pipe(select(getRelated));
|
|
34575
|
-
this.
|
|
34576
|
-
this.sourceOf$ = this.store.pipe(select(getSourceOf));
|
|
35164
|
+
this.linkedRecords$ = this.store.pipe(select(getLinkedRecords));
|
|
34577
35165
|
this.chartConfig$ = this.store.pipe(select(getChartConfig));
|
|
34578
35166
|
this.allLinks$ = this.metadata$.pipe(map$1((record) => 'onlineResources' in record ? record.onlineResources : []), shareReplay$1(1));
|
|
34579
35167
|
this.resourceDoi$ = this.metadata$.pipe(map$1((record) => {
|
|
@@ -34692,12 +35280,9 @@ class MdViewEffects {
|
|
|
34692
35280
|
this.loadRelatedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getSimilarRecords(full)), map$1((related) => {
|
|
34693
35281
|
return setRelated({ related });
|
|
34694
35282
|
}), 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 })))));
|
|
35283
|
+
this.loadLinkedRecords$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), switchMap$1(({ full }) => this.recordsRepository.getLinkedRecords(full)), map$1((linkedRecords) => {
|
|
35284
|
+
return setLinkedRecords({ linkedRecords });
|
|
35285
|
+
}), catchError(() => of(setLinkedRecords({ linkedRecords: null })))));
|
|
34701
35286
|
/*
|
|
34702
35287
|
UserFeedback effects
|
|
34703
35288
|
*/
|
|
@@ -36431,6 +37016,11 @@ const DEFAULT_CONFIGURATION = {
|
|
|
36431
37016
|
},
|
|
36432
37017
|
hidden: '${record.kind == "service"}',
|
|
36433
37018
|
},
|
|
37019
|
+
{
|
|
37020
|
+
model: 'associatedRecords',
|
|
37021
|
+
formFieldConfig: {},
|
|
37022
|
+
hidden: '${record.kind == "service"}',
|
|
37023
|
+
},
|
|
36434
37024
|
],
|
|
36435
37025
|
},
|
|
36436
37026
|
// Section: Geographical coverage
|
|
@@ -37568,7 +38158,7 @@ class FormFieldTemporalExtentsComponent {
|
|
|
37568
38158
|
provideNgIconsConfig({
|
|
37569
38159
|
size: '1.5rem',
|
|
37570
38160
|
}),
|
|
37571
|
-
], ngImport: i0, template: "<div class=\"flex gap-2
|
|
38161
|
+
], 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
38162
|
}
|
|
37573
38163
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldTemporalExtentsComponent, decorators: [{
|
|
37574
38164
|
type: Component,
|
|
@@ -37585,7 +38175,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37585
38175
|
provideNgIconsConfig({
|
|
37586
38176
|
size: '1.5rem',
|
|
37587
38177
|
}),
|
|
37588
|
-
], template: "<div class=\"flex gap-2
|
|
38178
|
+
], 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
38179
|
}], propDecorators: { value: [{
|
|
37590
38180
|
type: Input
|
|
37591
38181
|
}], valueChange: [{
|
|
@@ -37801,6 +38391,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
37801
38391
|
], 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
38392
|
}] });
|
|
37803
38393
|
|
|
38394
|
+
class FormFieldAssociatedRecordsComponent {
|
|
38395
|
+
constructor() {
|
|
38396
|
+
this.valueChange = new EventEmitter();
|
|
38397
|
+
}
|
|
38398
|
+
get list() {
|
|
38399
|
+
return this.value ?? [];
|
|
38400
|
+
}
|
|
38401
|
+
get first() {
|
|
38402
|
+
return this.list[0];
|
|
38403
|
+
}
|
|
38404
|
+
get rest() {
|
|
38405
|
+
return this.list.slice(1);
|
|
38406
|
+
}
|
|
38407
|
+
get hasParentLink() {
|
|
38408
|
+
return this.list.length > 0;
|
|
38409
|
+
}
|
|
38410
|
+
get uniqueIdentifier() {
|
|
38411
|
+
return this.first?.uniqueIdentifier ?? '';
|
|
38412
|
+
}
|
|
38413
|
+
get selectedType() {
|
|
38414
|
+
return this.first?.associationType;
|
|
38415
|
+
}
|
|
38416
|
+
get choices() {
|
|
38417
|
+
return associationTypeValues.map((value) => ({
|
|
38418
|
+
value,
|
|
38419
|
+
label: `domain.record.associationType.${value}`,
|
|
38420
|
+
}));
|
|
38421
|
+
}
|
|
38422
|
+
onToggle(checked) {
|
|
38423
|
+
this.valueChange.emit(checked
|
|
38424
|
+
? [
|
|
38425
|
+
{
|
|
38426
|
+
uniqueIdentifier: '',
|
|
38427
|
+
associationType: associationTypeValues[0],
|
|
38428
|
+
},
|
|
38429
|
+
...this.rest,
|
|
38430
|
+
]
|
|
38431
|
+
: this.rest);
|
|
38432
|
+
}
|
|
38433
|
+
onUniqueIdentifierChange(uniqueIdentifier) {
|
|
38434
|
+
this.valueChange.emit(uniqueIdentifier
|
|
38435
|
+
? [{ ...this.first, uniqueIdentifier }, ...this.rest]
|
|
38436
|
+
: this.rest);
|
|
38437
|
+
}
|
|
38438
|
+
onTypeChange(associationType) {
|
|
38439
|
+
this.valueChange.emit([
|
|
38440
|
+
{ ...this.first, associationType: associationType },
|
|
38441
|
+
...this.rest,
|
|
38442
|
+
]);
|
|
38443
|
+
}
|
|
38444
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
38445
|
+
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 }); }
|
|
38446
|
+
}
|
|
38447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldAssociatedRecordsComponent, decorators: [{
|
|
38448
|
+
type: Component,
|
|
38449
|
+
args: [{ selector: 'gn-ui-form-field-associated-records', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
38450
|
+
CheckToggleComponent,
|
|
38451
|
+
TextInputComponent,
|
|
38452
|
+
DropdownSelectorComponent,
|
|
38453
|
+
FormFieldWrapperComponent,
|
|
38454
|
+
TranslatePipe,
|
|
38455
|
+
], 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" }]
|
|
38456
|
+
}], propDecorators: { value: [{
|
|
38457
|
+
type: Input
|
|
38458
|
+
}], valueChange: [{
|
|
38459
|
+
type: Output
|
|
38460
|
+
}] } });
|
|
38461
|
+
|
|
37804
38462
|
class ContactCardComponent {
|
|
37805
38463
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ContactCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37806
38464
|
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 }); }
|
|
@@ -39186,6 +39844,9 @@ class FormFieldComponent {
|
|
|
39186
39844
|
get valueAsUpdateFrequency() {
|
|
39187
39845
|
return this.value;
|
|
39188
39846
|
}
|
|
39847
|
+
get valueAsAssociatedRecords() {
|
|
39848
|
+
return this.value;
|
|
39849
|
+
}
|
|
39189
39850
|
get valueAsTemporalExtents() {
|
|
39190
39851
|
return this.value;
|
|
39191
39852
|
}
|
|
@@ -39225,7 +39886,7 @@ class FormFieldComponent {
|
|
|
39225
39886
|
}
|
|
39226
39887
|
}
|
|
39227
39888
|
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 }); }
|
|
39889
|
+
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
39890
|
}
|
|
39230
39891
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
39231
39892
|
type: Component,
|
|
@@ -39237,6 +39898,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39237
39898
|
FormFieldLicenseComponent,
|
|
39238
39899
|
FormFieldDateComponent,
|
|
39239
39900
|
FormFieldUpdateFrequencyComponent,
|
|
39901
|
+
FormFieldAssociatedRecordsComponent,
|
|
39240
39902
|
FormFieldTemporalExtentsComponent,
|
|
39241
39903
|
FormFieldSimpleComponent,
|
|
39242
39904
|
FormFieldRichComponent,
|
|
@@ -39254,7 +39916,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
|
|
|
39254
39916
|
FormFieldTopicsComponent,
|
|
39255
39917
|
TextFieldModule,
|
|
39256
39918
|
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"] }]
|
|
39919
|
+
], 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
39920
|
}], propDecorators: { uniqueIdentifier: [{
|
|
39259
39921
|
type: Input
|
|
39260
39922
|
}], recordKind: [{
|
|
@@ -39839,7 +40501,7 @@ class RouterService {
|
|
|
39839
40501
|
return ROUTER_ROUTE_ORGANIZATION;
|
|
39840
40502
|
}
|
|
39841
40503
|
getDefaultSort() {
|
|
39842
|
-
return SortByEnum.
|
|
40504
|
+
return SortByEnum.RESOURCE_DATE;
|
|
39843
40505
|
}
|
|
39844
40506
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39845
40507
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RouterService, providedIn: 'root' }); }
|
|
@@ -39899,7 +40561,7 @@ function flattenQueryParams(params) {
|
|
|
39899
40561
|
const start = flattened[key].start;
|
|
39900
40562
|
const end = flattened[key].end;
|
|
39901
40563
|
flattened[key] = [
|
|
39902
|
-
`${start ? formatDate(start) : ''}..${formatDate(end)
|
|
40564
|
+
`${start ? formatDate(start) : ''}..${end ? formatDate(end) : ''}`,
|
|
39903
40565
|
];
|
|
39904
40566
|
}
|
|
39905
40567
|
}
|
|
@@ -40256,5 +40918,5 @@ const CHART_TYPE_VALUES = [
|
|
|
40256
40918
|
* Generated bundle index. Do not edit.
|
|
40257
40919
|
*/
|
|
40258
40920
|
|
|
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 };
|
|
40921
|
+
export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingComponent, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, defaultMapStyleFixture, defaultMapStyleHlFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
|
|
40260
40922
|
//# sourceMappingURL=geonetwork-ui.mjs.map
|