geonetwork-ui 2.10.0-dev.e97ea6950 → 2.10.0-dev.fb2893f44
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 +1622 -6598
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +196 -87
- 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/gn4.converter.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -2
- package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
- 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 +68 -34
- package/src/libs/api/repository/src/lib/gn4/gn4.provider.ts +6 -1
- 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 +11 -5
- 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 +6 -0
- package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +0 -1
- package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +10 -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/metadata-quality-panel/metadata-quality-panel.component.html +18 -3
- package/src/libs/feature/editor/src/lib/components/metadata-quality-panel/metadata-quality-panel.component.ts +33 -40
- 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 +32 -34
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +13 -13
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +18 -4
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.html +8 -7
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.ts +6 -6
- 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-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 +1 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +5 -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 +35 -0
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +5 -1
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +77 -5
- 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 +1 -1
- package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
- package/src/libs/feature/notify-reuse/src/index.ts +1 -0
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.css +0 -0
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +1 -0
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +21 -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 +2 -0
- package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +96 -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 +41 -0
- package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.ts +70 -0
- 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/internal-link-card/internal-link-card.component.html +1 -1
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +0 -1
- 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.css +0 -4
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +28 -67
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +30 -10
- package/src/libs/ui/inputs/src/lib/button/button.component.ts +8 -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/map/src/lib/components/map-container/map-container.component.ts +2 -1
- package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +15 -64
- 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/search/src/lib/record-preview-row/record-preview-row.component.html +0 -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/record/quality-score.util.ts +33 -18
- 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/index.ts +1 -0
- package/src/libs/util/shared/src/lib/utils/user-display.ts +32 -0
- package/style.css +0 -1
- package/tailwind.base.css +19 -2
- package/translations/de.json +29 -20
- package/translations/en.json +29 -20
- package/translations/es.json +29 -20
- package/translations/fr.json +29 -20
- package/translations/it.json +29 -20
- package/translations/nl.json +29 -20
- package/translations/pt.json +29 -20
- package/translations/sk.json +29 -20
|
@@ -58,7 +58,6 @@ export class InternalLinkCardComponent implements OnInit {
|
|
|
58
58
|
protected elementRef = inject(ElementRef)
|
|
59
59
|
|
|
60
60
|
@Input() record: CatalogRecord
|
|
61
|
-
@Input() linkTarget = '_blank'
|
|
62
61
|
@Input() linkHref: string = null
|
|
63
62
|
@Input() metadataQualityDisplay: boolean
|
|
64
63
|
@Input() favoriteTemplate: TemplateRef<{ $implicit: CatalogRecord }>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
|
2
|
-
import {
|
|
2
|
+
import { parse } from 'marked'
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
5
5
|
selector: 'gn-ui-markdown-parser',
|
|
@@ -14,6 +14,6 @@ export class MarkdownParserComponent {
|
|
|
14
14
|
@Input() whitoutStyles?: boolean
|
|
15
15
|
|
|
16
16
|
get parsedMarkdown() {
|
|
17
|
-
return
|
|
17
|
+
return parse(this.textContent ?? '')
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
matCallOutline,
|
|
22
22
|
matLocationOnOutline,
|
|
23
23
|
} from '@ng-icons/material-icons/outline'
|
|
24
|
-
|
|
24
|
+
import { getAddressLines } from '../../../../../../libs/util/shared/src'
|
|
25
25
|
import { TranslateDirective } from '@ngx-translate/core'
|
|
26
26
|
|
|
27
27
|
@Component({
|
|
@@ -59,10 +59,7 @@ export class MetadataContactComponent {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
get address() {
|
|
62
|
-
|
|
63
|
-
.split(',')
|
|
64
|
-
.map((part) => part.trim())
|
|
65
|
-
return addressParts
|
|
62
|
+
return getAddressLines(this.contacts[0]?.address)
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
onOrganizationClick() {
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
<gn-ui-max-lines [maxLines]="7">
|
|
29
29
|
<div class="metadata-info-keywords sm:pb-4 flex flex-wrap gap-2">
|
|
30
30
|
@for (keyword of metadata.keywords; track keyword) {
|
|
31
|
-
<gn-ui-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
<gn-ui-button
|
|
32
|
+
type="primary-light"
|
|
33
|
+
class="inline-block opacity-70"
|
|
34
|
+
extraClass="lowercase text-sm py-1 px-2"
|
|
35
|
+
(buttonClick)="onKeywordClick(keyword)"
|
|
36
|
+
>{{ keyword.label }}</gn-ui-button
|
|
36
37
|
>
|
|
37
38
|
}
|
|
38
39
|
</div>
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
data-test="usage-panel"
|
|
53
54
|
>
|
|
54
55
|
<div class="flex flex-col gap-[10px] mr-4 py-[12px] rounded text-gray-900">
|
|
55
|
-
@for (license of licenses; track
|
|
56
|
+
@for (license of licenses; track $index) {
|
|
56
57
|
@if (license.url) {
|
|
57
58
|
<div class="text-primary">
|
|
58
59
|
<a
|
|
@@ -105,9 +106,29 @@
|
|
|
105
106
|
</div>
|
|
106
107
|
</gn-ui-expandable-panel>
|
|
107
108
|
}
|
|
109
|
+
@if (metadata.contactsForResource?.length) {
|
|
110
|
+
<gn-ui-expandable-panel
|
|
111
|
+
[title]="'record.metadata.resource.contacts' | translate"
|
|
112
|
+
data-test="contacts-panel"
|
|
113
|
+
>
|
|
114
|
+
<div class="flex flex-col gap-1 pt-3 pb-4">
|
|
115
|
+
@for (group of contactGroups; track group.role) {
|
|
116
|
+
<div class="flex flex-col gap-1 rounded py-4 px-2">
|
|
117
|
+
<p class="text-xs font-normal text-black">
|
|
118
|
+
{{ group.roleLabel | translate }}
|
|
119
|
+
</p>
|
|
120
|
+
<div class="grid gap-1 grid-cols-1 md:grid-cols-2">
|
|
121
|
+
@for (contact of group.contacts; track contact.email) {
|
|
122
|
+
<gn-ui-contact-pill [contact]="contact"></gn-ui-contact-pill>
|
|
123
|
+
}
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
}
|
|
127
|
+
</div>
|
|
128
|
+
</gn-ui-expandable-panel>
|
|
129
|
+
}
|
|
108
130
|
@if (
|
|
109
131
|
(metadata.kind === 'dataset' && metadata.lineage) ||
|
|
110
|
-
resourceContact ||
|
|
111
132
|
metadata.resourceCreated ||
|
|
112
133
|
metadata.resourcePublished ||
|
|
113
134
|
metadata.resourceUpdated ||
|
|
@@ -129,66 +150,6 @@
|
|
|
129
150
|
</p>
|
|
130
151
|
</div>
|
|
131
152
|
}
|
|
132
|
-
@if (resourceContact) {
|
|
133
|
-
<div
|
|
134
|
-
class="flex flex-row gap-6 mt-5 mb-8 resource-contact"
|
|
135
|
-
data-test="details-panel-resource-contact"
|
|
136
|
-
>
|
|
137
|
-
@if (resourceContact.organization?.logoUrl?.href) {
|
|
138
|
-
<div
|
|
139
|
-
class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
|
|
140
|
-
>
|
|
141
|
-
<gn-ui-thumbnail
|
|
142
|
-
class="relative h-full w-full"
|
|
143
|
-
[thumbnailUrl]="resourceContact.organization.logoUrl.href"
|
|
144
|
-
fit="contain"
|
|
145
|
-
></gn-ui-thumbnail>
|
|
146
|
-
</div>
|
|
147
|
-
}
|
|
148
|
-
<div class="flex flex-col gap-1">
|
|
149
|
-
<p class="text-sm font-medium" translate>record.metadata.producer</p>
|
|
150
|
-
<div
|
|
151
|
-
class="text-primary font-title text-21 mr-2 cursor-pointer hover:underline"
|
|
152
|
-
data-cy="organization-name"
|
|
153
|
-
>
|
|
154
|
-
{{ resourceContact.organization?.name }}
|
|
155
|
-
</div>
|
|
156
|
-
@if (resourceContact.organization?.website) {
|
|
157
|
-
<div>
|
|
158
|
-
<a
|
|
159
|
-
[href]="resourceContact.organization.website"
|
|
160
|
-
target="_blank"
|
|
161
|
-
class="contact-website text-primary text-sm cursor-pointer hover:underline transition-all"
|
|
162
|
-
>{{ resourceContact.organization.website }}
|
|
163
|
-
<ng-icon
|
|
164
|
-
class="!w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
|
|
165
|
-
name="matOpenInNew"
|
|
166
|
-
></ng-icon>
|
|
167
|
-
</a>
|
|
168
|
-
</div>
|
|
169
|
-
}
|
|
170
|
-
@if (resourceContact.email) {
|
|
171
|
-
<div class="mt-4">
|
|
172
|
-
<div class="flex">
|
|
173
|
-
<ng-icon
|
|
174
|
-
class="!w-5 !h-5 !text-[20px] opacity-75 shrink-0"
|
|
175
|
-
name="matMailOutline"
|
|
176
|
-
></ng-icon>
|
|
177
|
-
@if (resourceContact.email) {
|
|
178
|
-
<a
|
|
179
|
-
[href]="'mailto:' + resourceContact.email"
|
|
180
|
-
class="text-sm hover:underline ml-2"
|
|
181
|
-
target="_blank"
|
|
182
|
-
data-cy="contact-email"
|
|
183
|
-
>{{ resourceContact?.email }}</a
|
|
184
|
-
>
|
|
185
|
-
}
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
}
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
|
-
}
|
|
192
153
|
<div
|
|
193
154
|
class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
|
|
194
155
|
>
|
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
} from '@angular/core'
|
|
9
9
|
import {
|
|
10
10
|
CatalogRecord,
|
|
11
|
+
Individual,
|
|
11
12
|
Keyword,
|
|
13
|
+
Role,
|
|
14
|
+
RoleLabels,
|
|
12
15
|
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
13
16
|
import { DateService, getTemporalRangeUnion } from '../../../../../../libs/util/shared/src'
|
|
14
17
|
import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
|
|
@@ -19,17 +22,18 @@ import {
|
|
|
19
22
|
import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
|
|
20
23
|
import {
|
|
21
24
|
BadgeComponent,
|
|
25
|
+
ButtonComponent,
|
|
22
26
|
CopyTextButtonComponent,
|
|
23
27
|
} from '../../../../../../libs/ui/inputs/src'
|
|
24
28
|
import { ContentGhostComponent } from '../content-ghost/content-ghost.component'
|
|
25
29
|
import { NgIcon, provideIcons } from '@ng-icons/core'
|
|
26
30
|
import { matOpenInNew } from '@ng-icons/material-icons/baseline'
|
|
27
31
|
import { matMailOutline } from '@ng-icons/material-icons/outline'
|
|
28
|
-
import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
|
|
29
32
|
import { GnUiLinkifyDirective } from './linkify.directive'
|
|
30
33
|
import { GnUiHumanizeDateDirective } from '../../../../../../libs/util/shared/src'
|
|
31
34
|
|
|
32
35
|
import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
|
|
36
|
+
import { ContactPillComponent } from '../contact-pill/contact-pill.component'
|
|
33
37
|
|
|
34
38
|
@Component({
|
|
35
39
|
selector: 'gn-ui-metadata-info',
|
|
@@ -42,15 +46,16 @@ import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
|
|
|
42
46
|
TranslatePipe,
|
|
43
47
|
MarkdownParserComponent,
|
|
44
48
|
ExpandablePanelComponent,
|
|
49
|
+
ButtonComponent,
|
|
45
50
|
BadgeComponent,
|
|
46
51
|
ContentGhostComponent,
|
|
47
|
-
ThumbnailComponent,
|
|
48
52
|
MaxLinesComponent,
|
|
49
53
|
CopyTextButtonComponent,
|
|
50
54
|
NgIcon,
|
|
51
55
|
GnUiLinkifyDirective,
|
|
52
56
|
GnUiHumanizeDateDirective,
|
|
53
57
|
SpatialExtentComponent,
|
|
58
|
+
ContactPillComponent,
|
|
54
59
|
],
|
|
55
60
|
viewProviders: [
|
|
56
61
|
provideIcons({
|
|
@@ -132,18 +137,33 @@ export class MetadataInfoComponent {
|
|
|
132
137
|
return getTemporalRangeUnion(temporalExtents, this.dateService)
|
|
133
138
|
}
|
|
134
139
|
|
|
135
|
-
get shownOrganization() {
|
|
136
|
-
return this.metadata.ownerOrganization
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
get resourceContact() {
|
|
140
|
-
return this.metadata.contactsForResource?.[0]
|
|
141
|
-
}
|
|
142
|
-
|
|
143
140
|
fieldReady(propName: string) {
|
|
144
141
|
return !this.incomplete || propName in this.metadata
|
|
145
142
|
}
|
|
146
143
|
|
|
144
|
+
get contactGroups(): {
|
|
145
|
+
role: Role
|
|
146
|
+
roleLabel: string
|
|
147
|
+
contacts: Individual[]
|
|
148
|
+
}[] {
|
|
149
|
+
const groups: { role: Role; roleLabel: string; contacts: Individual[] }[] =
|
|
150
|
+
[]
|
|
151
|
+
const indexByRole = new Map<Role, number>()
|
|
152
|
+
for (const contact of this.metadata.contactsForResource ?? []) {
|
|
153
|
+
if (indexByRole.has(contact.role)) {
|
|
154
|
+
groups[indexByRole.get(contact.role)].contacts.push(contact)
|
|
155
|
+
} else {
|
|
156
|
+
indexByRole.set(contact.role, groups.length)
|
|
157
|
+
groups.push({
|
|
158
|
+
role: contact.role,
|
|
159
|
+
roleLabel: RoleLabels.get(contact.role),
|
|
160
|
+
contacts: [contact],
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return groups
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
onKeywordClick(keyword: Keyword) {
|
|
148
168
|
this.keyword.emit(keyword)
|
|
149
169
|
}
|
|
@@ -25,7 +25,9 @@ export class ButtonComponent {
|
|
|
25
25
|
| 'outline'
|
|
26
26
|
| 'light'
|
|
27
27
|
| 'gray'
|
|
28
|
+
| 'gray-light'
|
|
28
29
|
| 'black'
|
|
30
|
+
| 'primary-light'
|
|
29
31
|
) {
|
|
30
32
|
// btn-classes are written in full to be picked up by tailwind
|
|
31
33
|
switch (value) {
|
|
@@ -44,9 +46,15 @@ export class ButtonComponent {
|
|
|
44
46
|
case 'gray':
|
|
45
47
|
this.btnClass = 'gn-ui-btn-gray'
|
|
46
48
|
break
|
|
49
|
+
case 'gray-light':
|
|
50
|
+
this.btnClass = 'gn-ui-btn-gray-light'
|
|
51
|
+
break
|
|
47
52
|
case 'black':
|
|
48
53
|
this.btnClass = 'gn-ui-btn-black'
|
|
49
54
|
break
|
|
55
|
+
case 'primary-light':
|
|
56
|
+
this.btnClass = 'gn-ui-btn-primary-light'
|
|
57
|
+
break
|
|
50
58
|
case 'default':
|
|
51
59
|
default:
|
|
52
60
|
this.btnClass = 'gn-ui-btn-default'
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
ChangeDetectionStrategy,
|
|
3
3
|
Component,
|
|
4
4
|
EventEmitter,
|
|
5
|
+
inject,
|
|
5
6
|
Input,
|
|
6
7
|
Output,
|
|
7
|
-
inject,
|
|
8
8
|
} from '@angular/core'
|
|
9
9
|
import {
|
|
10
10
|
DateAdapter,
|
|
@@ -52,6 +52,6 @@ export class DatePickerComponent {
|
|
|
52
52
|
@Output() dateChange = new EventEmitter<Date>()
|
|
53
53
|
|
|
54
54
|
constructor() {
|
|
55
|
-
this.dateAdapter.setLocale(this.translate.
|
|
55
|
+
this.dateAdapter.setLocale(this.translate.getCurrentLang())
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -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)
|
|
@@ -204,11 +204,12 @@ export class MapContainerComponent implements AfterViewInit, OnChanges {
|
|
|
204
204
|
|
|
205
205
|
async ngOnChanges(changes: SimpleChanges) {
|
|
206
206
|
if ('context' in changes && !changes['context'].isFirstChange()) {
|
|
207
|
+
const olMap = await this.openlayersMap
|
|
207
208
|
const diff = computeMapContextDiff(
|
|
208
209
|
this.processContext(changes['context'].currentValue),
|
|
209
210
|
this.processContext(changes['context'].previousValue)
|
|
210
211
|
)
|
|
211
|
-
await applyContextDiffToMap(
|
|
212
|
+
await applyContextDiffToMap(olMap, diff)
|
|
212
213
|
|
|
213
214
|
if (this._resolvedExtentChange && diff.viewChanges) {
|
|
214
215
|
this._resolvedExtentChange.emit(this.calculateCurrentMapExtent())
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import { Component, Input } from '@angular/core'
|
|
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
|
-
import { BehaviorSubject, Observable } from 'rxjs'
|
|
14
|
-
import { switchMap } from 'rxjs/operators'
|
|
5
|
+
import { BehaviorSubject, from, Observable, of } from 'rxjs'
|
|
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',
|
|
@@ -22,66 +15,24 @@ import { DatasetSpatialExtent } from '../../../../../../../libs/common/domain/sr
|
|
|
22
15
|
styleUrl: './spatial-extent.component.css',
|
|
23
16
|
})
|
|
24
17
|
export class SpatialExtentComponent {
|
|
18
|
+
private _cdr = inject(ChangeDetectorRef)
|
|
19
|
+
|
|
25
20
|
@Input() set spatialExtents(value: DatasetSpatialExtent[]) {
|
|
26
21
|
this.spatialExtents$.next(value)
|
|
27
22
|
}
|
|
28
23
|
spatialExtents$ = new BehaviorSubject<DatasetSpatialExtent[]>([])
|
|
29
24
|
mapContext$: Observable<MapContext> = this.spatialExtents$.pipe(
|
|
30
|
-
switchMap(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const featureCollection: GeoJSONFeatureCollection = {
|
|
35
|
-
type: 'FeatureCollection',
|
|
36
|
-
features: [],
|
|
37
|
-
}
|
|
38
|
-
extents.forEach((extent) => {
|
|
39
|
-
if (extent.geometry) {
|
|
40
|
-
featureCollection.features.push({
|
|
41
|
-
type: 'Feature',
|
|
42
|
-
properties: {},
|
|
43
|
-
geometry: extent.geometry,
|
|
44
|
-
})
|
|
45
|
-
} else if (extent.bbox?.length >= 0) {
|
|
46
|
-
featureCollection.features.push({
|
|
47
|
-
type: 'Feature',
|
|
48
|
-
properties: {},
|
|
49
|
-
geometry: this.bboxCoordsToGeometry(extent.bbox),
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const layer: MapContextLayer = {
|
|
55
|
-
type: 'geojson',
|
|
56
|
-
data: featureCollection,
|
|
57
|
-
label: 'Spatial extents',
|
|
58
|
-
style: {
|
|
59
|
-
'stroke-color': 'black',
|
|
60
|
-
'stroke-width': 2,
|
|
61
|
-
'fill-color': 'rgba(153, 153, 153, 0.3)',
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
const view = await createViewFromLayer(layer)
|
|
65
|
-
return {
|
|
66
|
-
view,
|
|
67
|
-
layers: [layer],
|
|
25
|
+
switchMap((extents) => {
|
|
26
|
+
const layer = createSpatialExtentLayer(extents)
|
|
27
|
+
if (!layer) {
|
|
28
|
+
return of(null)
|
|
68
29
|
}
|
|
30
|
+
return from(createViewFromLayer(layer)).pipe(
|
|
31
|
+
map((view) => ({ view, layers: [layer] }) as MapContext),
|
|
32
|
+
tap(() => this._cdr.markForCheck())
|
|
33
|
+
)
|
|
69
34
|
})
|
|
70
35
|
)
|
|
71
36
|
|
|
72
37
|
error = ''
|
|
73
|
-
|
|
74
|
-
bboxCoordsToGeometry(bbox: [number, number, number, number]): Geometry {
|
|
75
|
-
const geometry = new Polygon([
|
|
76
|
-
[
|
|
77
|
-
[bbox[0], bbox[1]],
|
|
78
|
-
[bbox[0], bbox[3]],
|
|
79
|
-
[bbox[2], bbox[3]],
|
|
80
|
-
[bbox[2], bbox[1]],
|
|
81
|
-
[bbox[0], bbox[1]],
|
|
82
|
-
],
|
|
83
|
-
])
|
|
84
|
-
|
|
85
|
-
return new GeoJSON().writeGeometryObject(geometry)
|
|
86
|
-
}
|
|
87
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)
|
|
@@ -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
|
}
|