geonetwork-ui 2.10.0-dev.5f1c6f718 → 2.10.0-dev.6183d942b
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 +737 -5773
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +171 -79
- package/index.d.ts.map +1 -1
- package/material-styles.css +483 -0
- package/package.json +25 -35
- package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +9 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/eu.dcat-ap.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +7 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+roilaye.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/metadata-for-i18n.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/opendataswiss.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/sextant.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/vlaanderen.dcat-ap.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +8 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.converter.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +5 -4
- package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
- package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +7 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +8 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +8 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +11 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +33 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +33 -0
- package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +8 -4
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +54 -32
- package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
- package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
- package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +48 -2
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +13 -5
- package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
- package/src/libs/common/domain/src/lib/model/user/group.model.ts +8 -0
- package/src/libs/common/domain/src/lib/model/user/index.ts +1 -0
- package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +5 -0
- package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
- package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
- package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
- package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
- package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +67 -0
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +39 -0
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +41 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +6 -8
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +9 -2
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +12 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.html +5 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.ts +89 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +3 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +11 -9
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +12 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -0
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +34 -2
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +5 -2
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +51 -33
- package/src/libs/feature/editor/src/lib/fields.config.ts +60 -47
- package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +4 -0
- package/src/libs/feature/editor/src/lib/services/editor.service.ts +4 -9
- package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
- package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
- package/src/libs/ui/dataviz/src/index.ts +0 -1
- package/src/libs/ui/elements/src/index.ts +1 -0
- package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +88 -0
- package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.ts +45 -0
- package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +29 -4
- package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.ts +51 -7
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
- package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
- package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.ts +2 -5
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +20 -10
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +29 -1
- package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
- package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
- package/src/libs/ui/inputs/src/lib/button/button.component.ts +4 -0
- package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
- package/src/libs/ui/inputs/src/lib/url-input/url-input.component.html +2 -2
- package/src/libs/ui/inputs/src/lib/url-input/url-input.component.ts +2 -1
- package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
- package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
- package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
- package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
- package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +4 -54
- package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
- package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
- package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
- package/src/libs/util/app-config/src/lib/app-config.ts +70 -9
- package/src/libs/util/app-config/src/lib/model.ts +7 -0
- package/src/libs/util/app-config/src/lib/parse-utils.ts +50 -1
- package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
- package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
- package/src/libs/util/i18n/src/index.ts +0 -1
- package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
- package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
- package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
- package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
- package/src/libs/util/shared/src/lib/links/link-utils.ts +1 -1
- package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
- package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
- package/src/libs/util/shared/src/lib/utils/user-display.ts +9 -0
- package/style.css +0 -1
- package/tailwind.base.css +8 -0
- package/translations/de.json +32 -20
- package/translations/en.json +32 -20
- package/translations/es.json +32 -20
- package/translations/fr.json +32 -20
- package/translations/it.json +32 -20
- package/translations/nl.json +32 -20
- package/translations/pt.json +32 -20
- package/translations/sk.json +32 -20
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
type="url"
|
|
7
7
|
[value]="inputValue"
|
|
8
8
|
(input)="handleInput($event)"
|
|
9
|
-
(keydown.enter)="handleUpload(input)"
|
|
9
|
+
(keydown.enter)="handleUpload(input, $event)"
|
|
10
10
|
[placeholder]="placeholder"
|
|
11
11
|
[attr.aria-label]="placeholder"
|
|
12
12
|
[disabled]="disabled"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
extraClass="absolute inset-y-[var(--side-padding)] right-[var(--side-padding)]"
|
|
26
26
|
type="primary"
|
|
27
27
|
[disabled]="disabled || input.value === '' || !isValidUrl(input.value)"
|
|
28
|
-
(buttonClick)="handleUpload(input)"
|
|
28
|
+
(buttonClick)="handleUpload(input, $event)"
|
|
29
29
|
>
|
|
30
30
|
<ng-content>
|
|
31
31
|
<ng-icon name="iconoirArrowUp"></ng-icon>
|
|
@@ -81,7 +81,8 @@ export class UrlInputComponent implements OnChanges {
|
|
|
81
81
|
this.valueChange.next(value)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
handleUpload(element: HTMLInputElement) {
|
|
84
|
+
handleUpload(element: HTMLInputElement, event: Event) {
|
|
85
|
+
event.stopPropagation()
|
|
85
86
|
const value = element.value
|
|
86
87
|
if (!value || !this.isValidUrl(value)) return
|
|
87
88
|
this.uploadClick.next(value)
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
<span class="flex-none font-bold" translate="">{{ label }}</span>
|
|
4
4
|
<div class="flex-1 flex justify-end items-center">
|
|
5
5
|
<ng-content select="[form-field-interaction]"></ng-content>
|
|
6
|
-
<
|
|
6
|
+
<ng-icon
|
|
7
7
|
*ngIf="hint"
|
|
8
|
-
|
|
8
|
+
name="matHelpOutline"
|
|
9
|
+
size="16"
|
|
10
|
+
class="m-2"
|
|
9
11
|
[matTooltip]="hint"
|
|
10
12
|
matTooltipPosition="above"
|
|
11
|
-
>
|
|
12
|
-
help
|
|
13
|
-
</span>
|
|
13
|
+
></ng-icon>
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
16
16
|
<div class="flex-1 mt-2">
|
|
@@ -2,6 +2,8 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
|
|
2
2
|
import { MatTooltipModule } from '@angular/material/tooltip'
|
|
3
3
|
import { CommonModule } from '@angular/common'
|
|
4
4
|
import { TranslateDirective } from '@ngx-translate/core'
|
|
5
|
+
import { NgIconComponent, provideIcons } from '@ng-icons/core'
|
|
6
|
+
import { matHelpOutline } from '@ng-icons/material-icons/outline'
|
|
5
7
|
|
|
6
8
|
@Component({
|
|
7
9
|
selector: 'gn-ui-form-field-wrapper',
|
|
@@ -9,7 +11,13 @@ import { TranslateDirective } from '@ngx-translate/core'
|
|
|
9
11
|
styleUrls: ['./form-field-wrapper.component.css'],
|
|
10
12
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
11
13
|
standalone: true,
|
|
12
|
-
imports: [
|
|
14
|
+
imports: [
|
|
15
|
+
MatTooltipModule,
|
|
16
|
+
CommonModule,
|
|
17
|
+
TranslateDirective,
|
|
18
|
+
NgIconComponent,
|
|
19
|
+
],
|
|
20
|
+
providers: [provideIcons({ matHelpOutline })],
|
|
13
21
|
})
|
|
14
22
|
export class FormFieldWrapperComponent {
|
|
15
23
|
@Input() label?: string
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
>
|
|
6
6
|
@for (item of items; track trackByFn(index); let index = $index) {
|
|
7
7
|
<div class="sortable-box bg-white flex items-center" cdkDrag>
|
|
8
|
-
<
|
|
8
|
+
<ng-icon
|
|
9
9
|
cdkDragHandle
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
name="matDragHandleOutline"
|
|
11
|
+
size="20"
|
|
12
|
+
class="mx-[10px] cursor-grab flex-none"
|
|
13
|
+
></ng-icon>
|
|
14
14
|
<div class="flex-1">
|
|
15
15
|
<ng-container
|
|
16
16
|
*ngTemplateOutlet="
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
class="ml-[8px] mr-[10px]"
|
|
30
30
|
(buttonClick)="removeItem(index)"
|
|
31
31
|
data-test="remove-item"
|
|
32
|
-
><
|
|
33
|
-
|
|
32
|
+
><ng-icon name="matCloseOutline" size="20"></ng-icon
|
|
33
|
+
></gn-ui-button>
|
|
34
34
|
</div>
|
|
35
35
|
}
|
|
36
36
|
</div>
|
|
@@ -15,6 +15,11 @@ import {
|
|
|
15
15
|
TemplateRef,
|
|
16
16
|
} from '@angular/core'
|
|
17
17
|
import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
|
|
18
|
+
import { NgIconComponent, provideIcons } from '@ng-icons/core'
|
|
19
|
+
import {
|
|
20
|
+
matCloseOutline,
|
|
21
|
+
matDragHandleOutline,
|
|
22
|
+
} from '@ng-icons/material-icons/outline'
|
|
18
23
|
|
|
19
24
|
@Component({
|
|
20
25
|
selector: 'gn-ui-sortable-list',
|
|
@@ -22,7 +27,15 @@ import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
|
|
|
22
27
|
styleUrls: ['sortable-list.component.css'],
|
|
23
28
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
24
29
|
standalone: true,
|
|
25
|
-
imports: [
|
|
30
|
+
imports: [
|
|
31
|
+
CommonModule,
|
|
32
|
+
CdkDropList,
|
|
33
|
+
CdkDrag,
|
|
34
|
+
CdkDragHandle,
|
|
35
|
+
ButtonComponent,
|
|
36
|
+
NgIconComponent,
|
|
37
|
+
],
|
|
38
|
+
providers: [provideIcons({ matDragHandleOutline, matCloseOutline })],
|
|
26
39
|
})
|
|
27
40
|
export class SortableListComponent {
|
|
28
41
|
@Input() elementTemplate: TemplateRef<unknown>
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { ChangeDetectorRef, Component, inject, Input } from '@angular/core'
|
|
2
2
|
import { CommonModule } from '@angular/common'
|
|
3
|
-
import {
|
|
4
|
-
import { GeoJSONFeatureCollection } from 'ol/format/GeoJSON.js'
|
|
5
|
-
import GeoJSON from 'ol/format/GeoJSON.js'
|
|
6
|
-
import { Polygon } from 'ol/geom.js'
|
|
7
|
-
import {
|
|
8
|
-
createViewFromLayer,
|
|
9
|
-
MapContext,
|
|
10
|
-
MapContextLayer,
|
|
11
|
-
} from '@geospatial-sdk/core'
|
|
3
|
+
import { createViewFromLayer, MapContext } from '@geospatial-sdk/core'
|
|
12
4
|
import { MapContainerComponent } from '../map-container/map-container.component'
|
|
13
5
|
import { BehaviorSubject, from, Observable, of } from 'rxjs'
|
|
14
6
|
import { map, switchMap, tap } from 'rxjs/operators'
|
|
15
7
|
import { DatasetSpatialExtent } from '../../../../../../../libs/common/domain/src/lib/model/record'
|
|
8
|
+
import { createSpatialExtentLayer } from '../../map-utils'
|
|
16
9
|
|
|
17
10
|
@Component({
|
|
18
11
|
selector: 'gn-ui-spatial-extent',
|
|
@@ -30,39 +23,10 @@ export class SpatialExtentComponent {
|
|
|
30
23
|
spatialExtents$ = new BehaviorSubject<DatasetSpatialExtent[]>([])
|
|
31
24
|
mapContext$: Observable<MapContext> = this.spatialExtents$.pipe(
|
|
32
25
|
switchMap((extents) => {
|
|
33
|
-
|
|
26
|
+
const layer = createSpatialExtentLayer(extents)
|
|
27
|
+
if (!layer) {
|
|
34
28
|
return of(null)
|
|
35
29
|
}
|
|
36
|
-
const featureCollection: GeoJSONFeatureCollection = {
|
|
37
|
-
type: 'FeatureCollection',
|
|
38
|
-
features: [],
|
|
39
|
-
}
|
|
40
|
-
extents.forEach((extent) => {
|
|
41
|
-
if (extent.geometry) {
|
|
42
|
-
featureCollection.features.push({
|
|
43
|
-
type: 'Feature',
|
|
44
|
-
properties: {},
|
|
45
|
-
geometry: extent.geometry,
|
|
46
|
-
})
|
|
47
|
-
} else if (extent.bbox?.length >= 0) {
|
|
48
|
-
featureCollection.features.push({
|
|
49
|
-
type: 'Feature',
|
|
50
|
-
properties: {},
|
|
51
|
-
geometry: this.bboxCoordsToGeometry(extent.bbox),
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const layer: MapContextLayer = {
|
|
57
|
-
type: 'geojson',
|
|
58
|
-
data: featureCollection,
|
|
59
|
-
label: 'Spatial extents',
|
|
60
|
-
style: {
|
|
61
|
-
'stroke-color': 'black',
|
|
62
|
-
'stroke-width': 2,
|
|
63
|
-
'fill-color': 'rgba(153, 153, 153, 0.3)',
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
30
|
return from(createViewFromLayer(layer)).pipe(
|
|
67
31
|
map((view) => ({ view, layers: [layer] }) as MapContext),
|
|
68
32
|
tap(() => this._cdr.markForCheck())
|
|
@@ -71,18 +35,4 @@ export class SpatialExtentComponent {
|
|
|
71
35
|
)
|
|
72
36
|
|
|
73
37
|
error = ''
|
|
74
|
-
|
|
75
|
-
bboxCoordsToGeometry(bbox: [number, number, number, number]): Geometry {
|
|
76
|
-
const geometry = new Polygon([
|
|
77
|
-
[
|
|
78
|
-
[bbox[0], bbox[1]],
|
|
79
|
-
[bbox[0], bbox[3]],
|
|
80
|
-
[bbox[2], bbox[3]],
|
|
81
|
-
[bbox[2], bbox[1]],
|
|
82
|
-
[bbox[0], bbox[1]],
|
|
83
|
-
],
|
|
84
|
-
])
|
|
85
|
-
|
|
86
|
-
return new GeoJSON().writeGeometryObject(geometry)
|
|
87
|
-
}
|
|
88
38
|
}
|
|
@@ -12,6 +12,54 @@ import {
|
|
|
12
12
|
MouseWheelZoom,
|
|
13
13
|
} from 'ol/interaction.js'
|
|
14
14
|
import MapBrowserEvent from 'ol/MapBrowserEvent.js'
|
|
15
|
+
import type { DatasetSpatialExtent } from '../../../../../libs/common/domain/src/lib/model/record'
|
|
16
|
+
import type {
|
|
17
|
+
MapContextLayer,
|
|
18
|
+
MapContextLayerGeojson,
|
|
19
|
+
} from '@geospatial-sdk/core'
|
|
20
|
+
import { spatialExtentsToFeatureCollection } from '../../../../../libs/util/shared/src'
|
|
21
|
+
|
|
22
|
+
export type SpatialExtentLayerStyle = NonNullable<
|
|
23
|
+
MapContextLayerGeojson['style']
|
|
24
|
+
>
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Default style for a spatial-extent layer: a solid black outline over a
|
|
28
|
+
* translucent grey fill.
|
|
29
|
+
*/
|
|
30
|
+
export const DEFAULT_SPATIAL_EXTENT_STYLE: SpatialExtentLayerStyle = {
|
|
31
|
+
'stroke-color': 'black',
|
|
32
|
+
'stroke-width': 2,
|
|
33
|
+
'fill-color': 'rgba(153, 153, 153, 0.3)',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Builds a GeoJSON map layer drawing the given spatial extents: each extent is
|
|
38
|
+
* rendered from its own geometry or, when only a bounding box is available,
|
|
39
|
+
* from a polygon derived from that box.
|
|
40
|
+
*
|
|
41
|
+
* @returns the layer, or `null` when none of the extents can be represented.
|
|
42
|
+
*/
|
|
43
|
+
export function createSpatialExtentLayer(
|
|
44
|
+
extents: DatasetSpatialExtent[],
|
|
45
|
+
overrides?: {
|
|
46
|
+
label?: string
|
|
47
|
+
clickable?: boolean
|
|
48
|
+
style?: SpatialExtentLayerStyle
|
|
49
|
+
}
|
|
50
|
+
): MapContextLayer | null {
|
|
51
|
+
const data = spatialExtentsToFeatureCollection(extents)
|
|
52
|
+
if (data.features.length === 0) {
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
type: 'geojson',
|
|
57
|
+
data,
|
|
58
|
+
label: 'Spatial extents',
|
|
59
|
+
style: DEFAULT_SPATIAL_EXTENT_STYLE,
|
|
60
|
+
...overrides,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
15
63
|
|
|
16
64
|
export function prioritizePageScroll(interactions: Collection<Interaction>) {
|
|
17
65
|
interactions.clear()
|
|
@@ -52,7 +52,7 @@ export class RecordPreviewFeedComponent extends RecordPreviewComponent {
|
|
|
52
52
|
protected elementRef: ElementRef
|
|
53
53
|
private translate = inject(TranslateService)
|
|
54
54
|
|
|
55
|
-
timeFormat = new Duration(this.translate.
|
|
55
|
+
timeFormat = new Duration(this.translate.getCurrentLang(), {})
|
|
56
56
|
|
|
57
57
|
constructor() {
|
|
58
58
|
const elementRef = inject(ElementRef)
|
|
@@ -28,7 +28,13 @@ export class PopoverComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|
|
28
28
|
|
|
29
29
|
@ViewChild('popoverContent', { static: false }) popoverContent: ElementRef
|
|
30
30
|
@Input() content: string | TemplateRef<any>
|
|
31
|
-
@Input() theme:
|
|
31
|
+
@Input() theme:
|
|
32
|
+
| 'light'
|
|
33
|
+
| 'light-border'
|
|
34
|
+
| 'translucent'
|
|
35
|
+
| 'material'
|
|
36
|
+
| 'dark'
|
|
37
|
+
| ''
|
|
32
38
|
|
|
33
39
|
private tippyInstance: Instance
|
|
34
40
|
private view: EmbeddedViewRef<any>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as TOML from '@ltd/j-toml'
|
|
2
2
|
import {
|
|
3
3
|
checkMetadataLanguage,
|
|
4
|
+
checkNewRecordDefaultLanguage,
|
|
5
|
+
checkNewRecordStandard,
|
|
4
6
|
parseConfigSection,
|
|
5
7
|
parseMultiConfigSection,
|
|
6
8
|
parseTranslationsConfigSection,
|
|
@@ -8,6 +10,7 @@ import {
|
|
|
8
10
|
import {
|
|
9
11
|
CustomTranslations,
|
|
10
12
|
CustomTranslationsAllLanguages,
|
|
13
|
+
EditorConfig,
|
|
11
14
|
GlobalConfig,
|
|
12
15
|
LayerConfig,
|
|
13
16
|
MapConfig,
|
|
@@ -15,10 +18,15 @@ import {
|
|
|
15
18
|
SearchConfig,
|
|
16
19
|
ThemeConfig,
|
|
17
20
|
} from './model'
|
|
18
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
TranslateCompiler,
|
|
23
|
+
TranslateLoader,
|
|
24
|
+
TranslateModuleConfig,
|
|
25
|
+
} from '@ngx-translate/core'
|
|
19
26
|
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler'
|
|
20
|
-
import { HttpClient } from '@angular/common/http'
|
|
21
27
|
import { FileWithOverridesTranslateLoader } from './i18n/file-with-overrides.translate.loader'
|
|
28
|
+
import { TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader'
|
|
29
|
+
import { HttpClient } from '@angular/common/http'
|
|
22
30
|
|
|
23
31
|
const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
|
|
24
32
|
This error might show up in case of an invalid/malformed configuration file.
|
|
@@ -51,6 +59,12 @@ export function getOptionalSearchConfig(): SearchConfig | null {
|
|
|
51
59
|
return searchConfig
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
let editorConfig: EditorConfig = null
|
|
63
|
+
|
|
64
|
+
export function getOptionalEditorConfig(): EditorConfig | null {
|
|
65
|
+
return editorConfig
|
|
66
|
+
}
|
|
67
|
+
|
|
54
68
|
let metadataQualityConfig: MetadataQualityConfig = null
|
|
55
69
|
export function getMetadataQualityConfig(): MetadataQualityConfig {
|
|
56
70
|
return (
|
|
@@ -285,6 +299,45 @@ export function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
|
|
|
285
299
|
SORTABLE: parsedMetadataQualitySection.sortable,
|
|
286
300
|
} as MetadataQualityConfig)
|
|
287
301
|
|
|
302
|
+
let parsedEditingSection = parseConfigSection(
|
|
303
|
+
parsed,
|
|
304
|
+
'editing',
|
|
305
|
+
[],
|
|
306
|
+
['new_record_default_language', 'new_record_standard'],
|
|
307
|
+
warnings,
|
|
308
|
+
errors
|
|
309
|
+
)
|
|
310
|
+
if (
|
|
311
|
+
parsedEditingSection !== null &&
|
|
312
|
+
parsedEditingSection.new_record_default_language !== undefined
|
|
313
|
+
) {
|
|
314
|
+
parsedEditingSection = checkNewRecordDefaultLanguage(
|
|
315
|
+
parsedEditingSection,
|
|
316
|
+
warnings
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
if (
|
|
320
|
+
parsedEditingSection !== null &&
|
|
321
|
+
parsedEditingSection.new_record_standard !== undefined
|
|
322
|
+
) {
|
|
323
|
+
parsedEditingSection = checkNewRecordStandard(
|
|
324
|
+
parsedEditingSection,
|
|
325
|
+
warnings
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
editorConfig =
|
|
329
|
+
parsedEditingSection === null
|
|
330
|
+
? null
|
|
331
|
+
: ({
|
|
332
|
+
NEW_RECORD_DEFAULT_LANGUAGE:
|
|
333
|
+
parsedEditingSection.new_record_default_language as
|
|
334
|
+
| string
|
|
335
|
+
| undefined,
|
|
336
|
+
NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard as
|
|
337
|
+
| EditorConfig['NEW_RECORD_STANDARD']
|
|
338
|
+
| undefined,
|
|
339
|
+
} as EditorConfig)
|
|
340
|
+
|
|
288
341
|
customTranslations = parseTranslationsConfigSection(
|
|
289
342
|
parsed,
|
|
290
343
|
'translations'
|
|
@@ -309,19 +362,27 @@ export function isConfigLoaded() {
|
|
|
309
362
|
export function _reset() {
|
|
310
363
|
globalConfig = null
|
|
311
364
|
themeConfig = null
|
|
365
|
+
editorConfig = null
|
|
312
366
|
customTranslations = null
|
|
313
367
|
}
|
|
314
368
|
|
|
315
|
-
export const TRANSLATE_WITH_OVERRIDES_CONFIG = {
|
|
369
|
+
export const TRANSLATE_WITH_OVERRIDES_CONFIG: TranslateModuleConfig = {
|
|
316
370
|
compiler: {
|
|
317
371
|
provide: TranslateCompiler,
|
|
318
372
|
useClass: TranslateMessageFormatCompiler,
|
|
319
373
|
},
|
|
320
|
-
loader:
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
374
|
+
loader: [
|
|
375
|
+
{
|
|
376
|
+
provide: TRANSLATE_HTTP_LOADER_CONFIG,
|
|
377
|
+
useValue: {
|
|
378
|
+
prefix: './assets/i18n/',
|
|
379
|
+
suffix: '.json',
|
|
380
|
+
},
|
|
324
381
|
},
|
|
325
|
-
|
|
326
|
-
|
|
382
|
+
{
|
|
383
|
+
provide: TranslateLoader,
|
|
384
|
+
useClass: FileWithOverridesTranslateLoader,
|
|
385
|
+
deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
|
|
386
|
+
},
|
|
387
|
+
],
|
|
327
388
|
}
|
|
@@ -69,6 +69,13 @@ export interface MetadataQualityConfig {
|
|
|
69
69
|
ENABLED: boolean
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export type NewRecordStandard = 'iso19139' | 'iso19115-3'
|
|
73
|
+
|
|
74
|
+
export interface EditorConfig {
|
|
75
|
+
NEW_RECORD_DEFAULT_LANGUAGE?: string
|
|
76
|
+
NEW_RECORD_STANDARD?: NewRecordStandard
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
export type CustomTranslations = { [translationKey: string]: string }
|
|
73
80
|
export type CustomTranslationsAllLanguages = {
|
|
74
81
|
[lang: string]: CustomTranslations
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toLang2 } from '../../../../../libs/util/i18n/src'
|
|
1
|
+
import { LANG_2_TO_3_MAPPER, toLang2 } from '../../../../../libs/util/i18n/src'
|
|
2
2
|
|
|
3
3
|
const flatten = (
|
|
4
4
|
base: string,
|
|
@@ -137,3 +137,52 @@ export function checkMetadataLanguage(
|
|
|
137
137
|
}
|
|
138
138
|
return parsedConfigSection
|
|
139
139
|
}
|
|
140
|
+
|
|
141
|
+
export function checkNewRecordDefaultLanguage(
|
|
142
|
+
parsedConfigSection: any,
|
|
143
|
+
outWarnings: string[]
|
|
144
|
+
) {
|
|
145
|
+
const lang2 = toLang2(
|
|
146
|
+
parsedConfigSection.new_record_default_language.toLowerCase()
|
|
147
|
+
)
|
|
148
|
+
if (!(lang2 in LANG_2_TO_3_MAPPER)) {
|
|
149
|
+
outWarnings.push(
|
|
150
|
+
`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`
|
|
151
|
+
)
|
|
152
|
+
return {
|
|
153
|
+
...parsedConfigSection,
|
|
154
|
+
new_record_default_language: undefined,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...parsedConfigSection,
|
|
159
|
+
new_record_default_language: lang2,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function checkNewRecordStandard(
|
|
164
|
+
parsedConfigSection: any,
|
|
165
|
+
outWarnings: string[]
|
|
166
|
+
) {
|
|
167
|
+
const standard = parsedConfigSection.new_record_standard
|
|
168
|
+
const normalizedStandard =
|
|
169
|
+
typeof standard === 'string' ? standard.trim().toLowerCase() : null
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
normalizedStandard === 'iso19139' ||
|
|
173
|
+
normalizedStandard === 'iso19115-3'
|
|
174
|
+
) {
|
|
175
|
+
return {
|
|
176
|
+
...parsedConfigSection,
|
|
177
|
+
new_record_standard: normalizedStandard,
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
outWarnings.push(
|
|
182
|
+
`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`
|
|
183
|
+
)
|
|
184
|
+
return {
|
|
185
|
+
...parsedConfigSection,
|
|
186
|
+
new_record_standard: undefined,
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BaseReader } from './base'
|
|
2
1
|
import { DataItem, DatasetInfo, PropertyInfo } from '../model'
|
|
3
2
|
import { getJsonDataItemsProxy, jsonToGeojsonFeature } from '../utils'
|
|
4
3
|
import { generateSqlQuery } from '../sql-utils'
|
|
@@ -58,7 +57,7 @@ export class BaseFileReader extends BaseCacheReader {
|
|
|
58
57
|
this.groupedBy,
|
|
59
58
|
this.aggregations
|
|
60
59
|
)
|
|
61
|
-
const result = await import('alasql').then((module) =>
|
|
60
|
+
const result: any[] = await import('alasql').then((module) =>
|
|
62
61
|
module.default(query, [jsonItems])
|
|
63
62
|
)
|
|
64
63
|
return result.map(jsonToGeojsonFeature)
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { EndpointError, WfsEndpoint, WfsVersion } from '@camptocamp/ogc-client'
|
|
2
2
|
import { DataItem, DatasetInfo, FetchError, PropertyInfo } from '../model'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
fetchDataAsText,
|
|
5
|
+
getJsonDataItemsProxy,
|
|
6
|
+
jsonToGeojsonFeature,
|
|
7
|
+
} from '../utils'
|
|
4
8
|
import { GmlReader, parseGml } from './gml'
|
|
5
9
|
import { GeojsonReader, parseGeojson } from './geojson'
|
|
6
10
|
import { BaseCacheReader } from './base-cache'
|
|
7
|
-
import { getJsonDataItemsProxy, jsonToGeojsonFeature } from '../utils'
|
|
8
11
|
import { generateSqlQuery } from '../sql-utils'
|
|
9
12
|
|
|
10
13
|
export async function getWfsEndpoint(wfsUrl: string): Promise<WfsEndpoint> {
|
|
@@ -167,7 +170,7 @@ export class WfsReader extends BaseCacheReader {
|
|
|
167
170
|
this.groupedBy,
|
|
168
171
|
this.aggregations
|
|
169
172
|
)
|
|
170
|
-
const result = await import('alasql').then((module) =>
|
|
173
|
+
const result: any[] = await import('alasql').then((module) =>
|
|
171
174
|
module.default(query, [jsonItems])
|
|
172
175
|
)
|
|
173
176
|
return result.map(jsonToGeojsonFeature)
|
|
@@ -2,6 +2,5 @@ export * from './lib/i18n.providers'
|
|
|
2
2
|
export * from './lib/i18n.constants'
|
|
3
3
|
export * from './lib/i18n.interceptor'
|
|
4
4
|
export * from './lib/file.translate.loader'
|
|
5
|
-
export * from './lib/embedded.translate.loader'
|
|
6
5
|
export * from './lib/translate.loader.utils'
|
|
7
6
|
export * from './lib/language-codes'
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { HttpClient } from '@angular/common/http'
|
|
2
1
|
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler'
|
|
3
|
-
import { FileTranslateLoader } from './file.translate.loader'
|
|
4
2
|
import {
|
|
5
3
|
TranslateCompiler,
|
|
6
4
|
TranslateDefaultParser,
|
|
@@ -9,26 +7,34 @@ import {
|
|
|
9
7
|
TranslateParser,
|
|
10
8
|
} from '@ngx-translate/core'
|
|
11
9
|
import { Injectable } from '@angular/core'
|
|
10
|
+
import { TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader'
|
|
11
|
+
import { HttpClient } from '@angular/common/http'
|
|
12
|
+
import { FileTranslateLoader } from './file.translate.loader'
|
|
12
13
|
|
|
13
14
|
export const DEFAULT_LANG = 'en'
|
|
14
15
|
|
|
15
16
|
// Caution: changing this can break language selection from third parties!
|
|
16
17
|
export const LANGUAGE_STORAGE_KEY = 'geonetwork-ui-language'
|
|
17
18
|
|
|
18
|
-
export function HttpLoaderFactory(http: HttpClient) {
|
|
19
|
-
return new FileTranslateLoader(http, './assets/i18n/')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
19
|
export const TRANSLATE_DEFAULT_CONFIG: TranslateModuleConfig = {
|
|
23
20
|
compiler: {
|
|
24
21
|
provide: TranslateCompiler,
|
|
25
22
|
useClass: TranslateMessageFormatCompiler,
|
|
26
23
|
},
|
|
27
|
-
loader:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
loader: [
|
|
25
|
+
{
|
|
26
|
+
provide: TRANSLATE_HTTP_LOADER_CONFIG,
|
|
27
|
+
useValue: {
|
|
28
|
+
prefix: './assets/i18n/',
|
|
29
|
+
suffix: '.json',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
provide: TranslateLoader,
|
|
34
|
+
useClass: FileTranslateLoader,
|
|
35
|
+
deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
@Injectable()
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from '@angular/common/http'
|
|
7
7
|
import { DEFAULT_LANG } from './i18n.constants'
|
|
8
8
|
import { Observable } from 'rxjs'
|
|
9
|
-
import { Injectable, Injector
|
|
9
|
+
import { inject, Injectable, Injector } from '@angular/core'
|
|
10
10
|
import { TranslateService } from '@ngx-translate/core'
|
|
11
11
|
|
|
12
12
|
@Injectable()
|
|
@@ -21,7 +21,7 @@ export class I18nInterceptor implements HttpInterceptor {
|
|
|
21
21
|
const translate = this.injector.get(TranslateService)
|
|
22
22
|
request = request.clone({
|
|
23
23
|
setHeaders: {
|
|
24
|
-
'Accept-Language': translate.
|
|
24
|
+
'Accept-Language': translate.getCurrentLang() || DEFAULT_LANG,
|
|
25
25
|
},
|
|
26
26
|
})
|
|
27
27
|
return next.handle(request)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
APP_INITIALIZER,
|
|
3
2
|
EnvironmentProviders,
|
|
3
|
+
inject,
|
|
4
4
|
makeEnvironmentProviders,
|
|
5
|
+
provideAppInitializer,
|
|
5
6
|
Provider,
|
|
6
7
|
} from '@angular/core'
|
|
7
8
|
import {
|
|
@@ -22,17 +23,16 @@ import {
|
|
|
22
23
|
} from '@angular/common/http'
|
|
23
24
|
import { I18nInterceptor } from './i18n.interceptor'
|
|
24
25
|
|
|
25
|
-
function i18nInitializerFromLocalStorageFactory(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
translate.use(storageLang || translate.getBrowserLang() || DEFAULT_LANG)
|
|
26
|
+
function i18nInitializerFromLocalStorageFactory() {
|
|
27
|
+
const translate = inject(TranslateService)
|
|
28
|
+
translate.setFallbackLang(DEFAULT_LANG)
|
|
29
|
+
let storageLang = null
|
|
30
|
+
try {
|
|
31
|
+
storageLang = localStorage.getItem(LANGUAGE_STORAGE_KEY)
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.warn(error)
|
|
35
34
|
}
|
|
35
|
+
translate.use(storageLang || translate.getBrowserLang() || DEFAULT_LANG)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export function provideI18n(
|
|
@@ -56,12 +56,9 @@ export function provideI18n(
|
|
|
56
56
|
provideTranslateService(usedConfig),
|
|
57
57
|
]
|
|
58
58
|
if (useLocalStorage) {
|
|
59
|
-
providers.push(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
deps: [TranslateService],
|
|
63
|
-
multi: true,
|
|
64
|
-
})
|
|
59
|
+
providers.push(
|
|
60
|
+
provideAppInitializer(i18nInitializerFromLocalStorageFactory)
|
|
61
|
+
)
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
return makeEnvironmentProviders(providers)
|