geonetwork-ui 2.10.0-dev.25c2dd4c0 → 2.10.0-dev.2be368c45
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 +1368 -6214
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +199 -171
- package/index.d.ts.map +1 -1
- 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 +22 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +1 -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 +22 -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 +1 -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 +6 -5
- 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 +4 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +13 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +45 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +13 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +40 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +47 -1
- package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +4 -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 +56 -38
- 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 +37 -2
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +12 -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/domain/src/lib/repository/records-repository.interface.ts +2 -1
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +57 -0
- package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
- package/src/libs/feature/editor/src/index.ts +1 -0
- 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.html +7 -6
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +10 -8
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
- 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 +4 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +7 -7
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
- 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-update-frequency/form-field-update-frequency.component.html +6 -2
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +0 -34
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +27 -16
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -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 +18 -5
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +76 -19
- package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
- package/src/libs/feature/editor/src/lib/fields.config.ts +354 -337
- package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +6 -3
- package/src/libs/feature/editor/src/lib/services/editor.service.ts +8 -12
- 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/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
- package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
- package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -1
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +211 -8
- package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
- 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 +48 -56
- package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +7 -3
- package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
- package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
- 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/keyword-badge/keyword-badge.component.html +14 -0
- package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
- package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +5 -8
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
- 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/badge/badge.component.html +33 -26
- package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -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/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
- 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/interactive-table/interactive-table.component.html +1 -1
- package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
- 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/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
- package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
- package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
- package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
- package/src/libs/util/app-config/src/lib/app-config.ts +21 -9
- 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 +22 -0
- 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/style.css +0 -1
- package/tailwind.base.css +15 -0
- package/translations/de.json +102 -49
- package/translations/en.json +112 -59
- package/translations/es.json +76 -23
- package/translations/fr.json +109 -56
- package/translations/it.json +103 -50
- package/translations/nl.json +75 -22
- package/translations/pt.json +76 -23
- package/translations/sk.json +76 -23
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
HttpErrorResponse,
|
|
4
4
|
HttpHeaders,
|
|
5
5
|
} from '@angular/common/http'
|
|
6
|
-
import { Injectable, InjectionToken
|
|
6
|
+
import { inject, Injectable, InjectionToken } from '@angular/core'
|
|
7
7
|
import {
|
|
8
8
|
assertValidXml,
|
|
9
9
|
BaseConverter,
|
|
@@ -327,8 +327,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
327
327
|
return this.settingsService.allowEditHarvested$.pipe(
|
|
328
328
|
map((allowEditHarvested) => {
|
|
329
329
|
return (
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
(this.platformService.supportsAuthentication() &&
|
|
331
|
+
record.extras?.['edit'] &&
|
|
332
|
+
(!record.extras?.['isHarvested'] || allowEditHarvested)) ??
|
|
333
|
+
false
|
|
332
334
|
)
|
|
333
335
|
})
|
|
334
336
|
)
|
|
@@ -336,10 +338,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
336
338
|
|
|
337
339
|
private canEdit(record: CatalogRecord, allowEditHarvested: boolean): boolean {
|
|
338
340
|
return (
|
|
339
|
-
this.platformService.supportsAuthentication() &&
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
(this.platformService.supportsAuthentication() &&
|
|
342
|
+
record.extras?.['edit'] &&
|
|
343
|
+
(!record.extras?.['isHarvested'] || allowEditHarvested)) ??
|
|
344
|
+
false
|
|
343
345
|
)
|
|
344
346
|
}
|
|
345
347
|
|
|
@@ -361,8 +363,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
openRecordForEdition(
|
|
364
|
-
uniqueIdentifier: string
|
|
366
|
+
uniqueIdentifier: string,
|
|
367
|
+
disableDraft?: boolean
|
|
365
368
|
): Observable<[CatalogRecord, string, boolean] | null> {
|
|
369
|
+
this.disableDraft = disableDraft ?? this.disableDraft
|
|
366
370
|
const draft$ = this.disableDraft
|
|
367
371
|
? of(null)
|
|
368
372
|
: of(this.getRecordFromLocalStorage(uniqueIdentifier))
|
|
@@ -385,38 +389,52 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
385
389
|
openRecordForDuplication(
|
|
386
390
|
uniqueIdentifier: string
|
|
387
391
|
): Observable<[CatalogRecord, string, true] | null> {
|
|
388
|
-
return this.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
392
|
+
return this.platformService.getUserPermissionsByGroup().pipe(
|
|
393
|
+
map((permissions) => {
|
|
394
|
+
const groupId =
|
|
395
|
+
permissions.find((p) => p.canApprove)?.groupId?.toString() ??
|
|
396
|
+
permissions.find((p) => p.canEdit)?.groupId?.toString()
|
|
397
|
+
if (!groupId)
|
|
398
|
+
throw new Error(
|
|
399
|
+
'Current user has no writable group to duplicate into'
|
|
400
|
+
)
|
|
401
|
+
return groupId
|
|
402
|
+
}),
|
|
403
|
+
switchMap((groupId) =>
|
|
404
|
+
this.gn4RecordsApi
|
|
405
|
+
.create(
|
|
406
|
+
uniqueIdentifier,
|
|
407
|
+
groupId,
|
|
408
|
+
'METADATA',
|
|
409
|
+
'',
|
|
410
|
+
false,
|
|
411
|
+
undefined,
|
|
412
|
+
true,
|
|
413
|
+
false,
|
|
414
|
+
undefined,
|
|
415
|
+
'body',
|
|
416
|
+
false,
|
|
417
|
+
{
|
|
418
|
+
httpHeaderAccept: 'application/json',
|
|
419
|
+
httpContentTypeSelected: 'application/json;charset=UTF-8',
|
|
420
|
+
}
|
|
421
|
+
)
|
|
422
|
+
.pipe(
|
|
423
|
+
switchMap((uniqueIdentifier) => {
|
|
424
|
+
return this.getRecordAsXml(uniqueIdentifier)
|
|
425
|
+
}),
|
|
426
|
+
switchMap((xml) => {
|
|
427
|
+
return from(
|
|
428
|
+
findConverterForDocument(xml)
|
|
429
|
+
.readRecord(xml)
|
|
430
|
+
.then((record) => {
|
|
431
|
+
return [record, xml, true] as [CatalogRecord, string, true]
|
|
432
|
+
})
|
|
433
|
+
)
|
|
434
|
+
})
|
|
417
435
|
)
|
|
418
|
-
})
|
|
419
436
|
)
|
|
437
|
+
)
|
|
420
438
|
}
|
|
421
439
|
|
|
422
440
|
saveRecord(
|
package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts
CHANGED
|
@@ -52,7 +52,7 @@ export class OrganizationsFromGroupsService
|
|
|
52
52
|
organisationsCount$ = this.organisations$.pipe(map((orgs) => orgs.length))
|
|
53
53
|
|
|
54
54
|
private get lang3() {
|
|
55
|
-
return toLang3(this.translateService.
|
|
55
|
+
return toLang3(this.translateService.getCurrentLang())
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
constructor(
|
package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts
CHANGED
|
@@ -128,7 +128,7 @@ export class OrganizationsFromMetadataService
|
|
|
128
128
|
) {}
|
|
129
129
|
|
|
130
130
|
private get langIndex() {
|
|
131
|
-
return `lang${toLang3(this.translateService.
|
|
131
|
+
return `lang${toLang3(this.translateService.getCurrentLang())}`
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
equalsNormalizedStrings(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HttpClient, HttpEventType } from '@angular/common/http'
|
|
2
|
-
import { Injectable, InjectionToken
|
|
2
|
+
import { inject, Injectable, InjectionToken } from '@angular/core'
|
|
3
3
|
import {
|
|
4
4
|
KeywordApiResponse,
|
|
5
5
|
ThesaurusApiResponse,
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
} from '../../../../../../../libs/common/domain/src/lib/model/record'
|
|
13
13
|
import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
|
|
14
14
|
import { UserModel } from '../../../../../../../libs/common/domain/src/lib/model/user/user.model'
|
|
15
|
+
import { GroupModel } from '../../../../../../../libs/common/domain/src/lib/model/user/group.model'
|
|
15
16
|
import {
|
|
16
17
|
PlatformServiceInterface,
|
|
17
18
|
UploadEvent,
|
|
18
19
|
} from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
|
|
19
20
|
import {
|
|
21
|
+
GroupsApiService,
|
|
20
22
|
MeApiService,
|
|
21
23
|
RecordsApiService,
|
|
22
24
|
RegistriesApiService,
|
|
@@ -57,6 +59,7 @@ export const DISABLE_AUTH = new InjectionToken<boolean>('gnDisableAuth', {
|
|
|
57
59
|
export class Gn4PlatformService implements PlatformServiceInterface {
|
|
58
60
|
private meApi = inject(MeApiService)
|
|
59
61
|
private usersApi = inject(UsersApiService)
|
|
62
|
+
private groupsApi = inject(GroupsApiService)
|
|
60
63
|
private mapper = inject(Gn4PlatformMapper)
|
|
61
64
|
private toolsApiService = inject(ToolsApiService)
|
|
62
65
|
private registriesApiService = inject(RegistriesApiService)
|
|
@@ -97,7 +100,7 @@ export class Gn4PlatformService implements PlatformServiceInterface {
|
|
|
97
100
|
private keywordsByThesauri: Record<string, Observable<Keyword[]>> = {}
|
|
98
101
|
|
|
99
102
|
private get lang3() {
|
|
100
|
-
return toLang3(this.translateService.
|
|
103
|
+
return toLang3(this.translateService.getCurrentLang())
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
constructor() {
|
|
@@ -155,6 +158,38 @@ export class Gn4PlatformService implements PlatformServiceInterface {
|
|
|
155
158
|
return this.users$
|
|
156
159
|
}
|
|
157
160
|
|
|
161
|
+
getUserPermissionsByGroup(): Observable<GroupModel[]> {
|
|
162
|
+
if (this.disableAuth) return of([])
|
|
163
|
+
return combineLatest([this.meApi.getMe(), this.groupsApi.getGroups()]).pipe(
|
|
164
|
+
map(([meResponse, groups]) => {
|
|
165
|
+
if (!meResponse) return []
|
|
166
|
+
if (meResponse.admin) {
|
|
167
|
+
return groups.map((group) => ({
|
|
168
|
+
groupId: group.id,
|
|
169
|
+
groupName: group.name,
|
|
170
|
+
isMember: true,
|
|
171
|
+
canEdit: true,
|
|
172
|
+
canApprove: true,
|
|
173
|
+
canAdministrate: true,
|
|
174
|
+
}))
|
|
175
|
+
}
|
|
176
|
+
const reviewerIds = meResponse.groupsWithReviewer ?? []
|
|
177
|
+
const editorIds = meResponse.groupsWithEditor ?? []
|
|
178
|
+
const memberIds = meResponse.groupsWithRegisteredUser ?? []
|
|
179
|
+
const adminIds = meResponse.groupsWithUserAdmin ?? []
|
|
180
|
+
|
|
181
|
+
return groups.map((group) => ({
|
|
182
|
+
groupId: group.id,
|
|
183
|
+
groupName: group.name,
|
|
184
|
+
isMember: memberIds.includes(group.id),
|
|
185
|
+
canEdit: editorIds.includes(group.id),
|
|
186
|
+
canApprove: reviewerIds.includes(group.id),
|
|
187
|
+
canAdministrate: adminIds.includes(group.id),
|
|
188
|
+
}))
|
|
189
|
+
})
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
158
193
|
translateKey(key: string): Observable<string> {
|
|
159
194
|
// if the key is a URI, use the registries API to look for the translation
|
|
160
195
|
if (key.match(/^https?:\/\//)) {
|
|
@@ -104,15 +104,12 @@ export interface Keyword {
|
|
|
104
104
|
type: KeywordType
|
|
105
105
|
thesaurus?: ThesaurusModel
|
|
106
106
|
bbox?: [number, number, number, number]
|
|
107
|
+
// thesaurus hierarchy path incl. the keyword as last element; unset for root-level keywords
|
|
108
|
+
hierarchyPath?: string[]
|
|
107
109
|
|
|
108
110
|
translations?: KeywordTranslations
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
export interface INSPIRE_topic {
|
|
112
|
-
value: string
|
|
113
|
-
label: string
|
|
114
|
-
}
|
|
115
|
-
|
|
116
113
|
export interface ResourceIdentifier {
|
|
117
114
|
code: string
|
|
118
115
|
codeSpace?: string
|
|
@@ -263,11 +260,20 @@ export interface SourceRecord {
|
|
|
263
260
|
href?: string
|
|
264
261
|
}
|
|
265
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Represents another record associated with this one (e.g. a parent/sibling dataset).
|
|
265
|
+
*/
|
|
266
|
+
export interface AssociatedRecord {
|
|
267
|
+
uuid: string
|
|
268
|
+
associationType: string
|
|
269
|
+
}
|
|
270
|
+
|
|
266
271
|
export interface DatasetRecord extends BaseRecord {
|
|
267
272
|
kind: 'dataset'
|
|
268
273
|
status: RecordStatus
|
|
269
274
|
lineage: string // Explanation of the origin of this record (e.g: how, why)"
|
|
270
275
|
sourceRecords: Array<SourceRecord>
|
|
276
|
+
associatedRecords: Array<AssociatedRecord>
|
|
271
277
|
onlineResources: Array<DatasetOnlineResource>
|
|
272
278
|
spatialExtents: Array<DatasetSpatialExtent>
|
|
273
279
|
temporalExtents: Array<DatasetTemporalExtent>
|
|
@@ -296,6 +302,7 @@ export interface ReuseRecord extends BaseRecord {
|
|
|
296
302
|
kind: 'reuse'
|
|
297
303
|
lineage: string // Explanation of the origin of this record (e.g: how, why)"
|
|
298
304
|
sourceRecords: Array<SourceRecord>
|
|
305
|
+
associatedRecords: Array<AssociatedRecord>
|
|
299
306
|
onlineResources: Array<DatasetOnlineResource>
|
|
300
307
|
reuseType: ReuseType
|
|
301
308
|
spatialExtents: Array<DatasetSpatialExtent>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Observable } from 'rxjs'
|
|
2
2
|
import type { UserModel } from './model/user/user.model'
|
|
3
|
+
import type { GroupModel } from './model/user/group.model'
|
|
3
4
|
import type { Organization } from './model/record/organization.model'
|
|
4
5
|
import { CatalogRecord, Keyword, UserFeedback } from './model/record'
|
|
5
6
|
import { KeywordType } from './model/thesaurus'
|
|
@@ -28,6 +29,7 @@ export abstract class PlatformServiceInterface {
|
|
|
28
29
|
abstract getMe(): Observable<UserModel>
|
|
29
30
|
abstract isAnonymous(): Observable<boolean>
|
|
30
31
|
abstract getUsers(): Observable<UserModel[]>
|
|
32
|
+
abstract getUserPermissionsByGroup(): Observable<GroupModel[]>
|
|
31
33
|
abstract getUsersByOrganization(
|
|
32
34
|
organisation: Organization
|
|
33
35
|
): Observable<UserModel[]>
|
|
@@ -39,7 +39,8 @@ export abstract class RecordsRepositoryInterface {
|
|
|
39
39
|
* @returns Observable<[CatalogRecord, string, boolean] | null>
|
|
40
40
|
*/
|
|
41
41
|
abstract openRecordForEdition(
|
|
42
|
-
uniqueIdentifier: string
|
|
42
|
+
uniqueIdentifier: string,
|
|
43
|
+
disableDraft?: boolean
|
|
43
44
|
): Observable<[CatalogRecord, string, boolean] | null>
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DatasetRecord,
|
|
4
4
|
DatasetSpatialExtent,
|
|
5
5
|
Keyword,
|
|
6
|
+
ReuseRecord,
|
|
6
7
|
ServiceRecord,
|
|
7
8
|
} from '../../../../../libs/common/domain/src/lib/model/record'
|
|
8
9
|
|
|
@@ -135,6 +136,7 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
|
|
|
135
136
|
|
|
136
137
|
As such, **it is not very interesting at all.**`,
|
|
137
138
|
sourceRecords: [],
|
|
139
|
+
associatedRecords: [],
|
|
138
140
|
licenses: [
|
|
139
141
|
{
|
|
140
142
|
text: 'Licence ODbL mai 2013 (basée sur ODbL 1.0)',
|
|
@@ -312,6 +314,7 @@ Malgré l'attention portée à la création de ces données, il est rappelé que
|
|
|
312
314
|
lineage: `Document d’urbanisme numérisé conformément aux prescriptions nationales du CNIG par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.
|
|
313
315
|
Ce lot de données produit en 2019, a été numérisé à partir du PCI Vecteur de 2019 et contrôlé par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.`,
|
|
314
316
|
sourceRecords: [],
|
|
317
|
+
associatedRecords: [],
|
|
315
318
|
legalConstraints: [],
|
|
316
319
|
securityConstraints: [],
|
|
317
320
|
otherConstraints: [],
|
|
@@ -364,6 +367,7 @@ export const simpleDatasetRecordFixture = (): DatasetRecord => ({
|
|
|
364
367
|
spatialExtents: [],
|
|
365
368
|
temporalExtents: [],
|
|
366
369
|
sourceRecords: [],
|
|
370
|
+
associatedRecords: [],
|
|
367
371
|
onlineResources: [
|
|
368
372
|
{
|
|
369
373
|
type: 'download',
|
|
@@ -417,6 +421,7 @@ export const simpleDatasetRecordWithFcatsFixture = (): DatasetRecord => ({
|
|
|
417
421
|
spatialExtents: [],
|
|
418
422
|
temporalExtents: [],
|
|
419
423
|
sourceRecords: [],
|
|
424
|
+
associatedRecords: [],
|
|
420
425
|
onlineResources: [],
|
|
421
426
|
updateFrequency: { per: 'month', updatedTimes: 3 },
|
|
422
427
|
translations: {},
|
|
@@ -983,6 +988,7 @@ export const multilingualDatasetFixture: () => DatasetRecord = () => ({
|
|
|
983
988
|
abstract: 'English Abstract',
|
|
984
989
|
lineage: 'English Lineage',
|
|
985
990
|
sourceRecords: [],
|
|
991
|
+
associatedRecords: [],
|
|
986
992
|
translations: {
|
|
987
993
|
title: { fr: 'Titre Français', de: 'Titel DE' },
|
|
988
994
|
abstract: { fr: 'Résumé Français', de: 'Beschreibung DE' },
|
|
@@ -1027,3 +1033,54 @@ export const multilingualDatasetFixture: () => DatasetRecord = () => ({
|
|
|
1027
1033
|
topics: [],
|
|
1028
1034
|
recordUpdated: null,
|
|
1029
1035
|
})
|
|
1036
|
+
|
|
1037
|
+
export const simpleReuseRecordFixture = (): ReuseRecord => ({
|
|
1038
|
+
abstract: `Sample reuse record`,
|
|
1039
|
+
kind: 'reuse',
|
|
1040
|
+
reuseType: 'application',
|
|
1041
|
+
recordUpdated: new Date('2023-03-17T07:38:08.875Z'),
|
|
1042
|
+
recordPublished: null,
|
|
1043
|
+
ownerOrganization: null,
|
|
1044
|
+
licenses: [],
|
|
1045
|
+
legalConstraints: [],
|
|
1046
|
+
securityConstraints: [],
|
|
1047
|
+
otherConstraints: [],
|
|
1048
|
+
contacts: [],
|
|
1049
|
+
contactsForResource: [],
|
|
1050
|
+
keywords: [],
|
|
1051
|
+
topics: [],
|
|
1052
|
+
spatialExtents: [],
|
|
1053
|
+
temporalExtents: [],
|
|
1054
|
+
lineage: 'bla',
|
|
1055
|
+
sourceRecords: [],
|
|
1056
|
+
associatedRecords: [],
|
|
1057
|
+
overviews: [],
|
|
1058
|
+
defaultLanguage: null,
|
|
1059
|
+
otherLanguages: [],
|
|
1060
|
+
title: 'Sites de gestion des déchets miniers - Service de visualisation WMS',
|
|
1061
|
+
onlineResources: [
|
|
1062
|
+
{
|
|
1063
|
+
name: 'Rapport de disponibilité du service WMS',
|
|
1064
|
+
description:
|
|
1065
|
+
'Ce service de visualisation WMS permet de consulter la série de couches de données "Sites de gestion des déchets miniers - Série".',
|
|
1066
|
+
mimeType: 'text/html',
|
|
1067
|
+
type: 'link',
|
|
1068
|
+
url: new URL(
|
|
1069
|
+
'https://geoservices.wallonie.be/rapportDisponibilite/wms/sites_de_gestion_des_dechets_miniers_srie.html'
|
|
1070
|
+
),
|
|
1071
|
+
accessRestricted: false,
|
|
1072
|
+
},
|
|
1073
|
+
],
|
|
1074
|
+
uniqueIdentifier: '00b22798-ec8e-4500-89e8-90eeeda45919',
|
|
1075
|
+
landingPage: new URL(
|
|
1076
|
+
'http://localhost:4200/geonetwork/srv/fre/catalog.search#/metadata/00b22798-ec8e-4500-89e8-90eeeda45919'
|
|
1077
|
+
),
|
|
1078
|
+
extras: {
|
|
1079
|
+
isPublishedToAll: true,
|
|
1080
|
+
id: '723',
|
|
1081
|
+
isHarvested: true,
|
|
1082
|
+
ownerInfo: 'admin|admin|admin|Administrator',
|
|
1083
|
+
edit: true,
|
|
1084
|
+
},
|
|
1085
|
+
recordCreated: new Date('2023-03-17T07:38:08.875Z'),
|
|
1086
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { inject, Injectable } from '@angular/core'
|
|
2
2
|
import { SourcesApiService } from '../../../../../../libs/data-access/gn4/src'
|
|
3
3
|
import { Observable } from 'rxjs'
|
|
4
4
|
import { filter, map, shareReplay } from 'rxjs/operators'
|
|
@@ -21,7 +21,10 @@ export class SourcesService {
|
|
|
21
21
|
return this.sources$.pipe(
|
|
22
22
|
map((sources) => sources.filter((source) => source.uuid === uuid)[0]),
|
|
23
23
|
filter((source) => !!source),
|
|
24
|
-
map(
|
|
24
|
+
map(
|
|
25
|
+
(source) =>
|
|
26
|
+
source.label[toLang3(this.translateService.getCurrentLang())]
|
|
27
|
+
)
|
|
25
28
|
)
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -3,6 +3,7 @@ export * from './lib/+state/editor.facade'
|
|
|
3
3
|
export * from './lib/+state/editor.models'
|
|
4
4
|
export * from './lib/+state/editor.reducer'
|
|
5
5
|
export * from './lib/+state/editor.selectors'
|
|
6
|
+
export * from './lib/components/contact-details/contact-details-form.component'
|
|
6
7
|
export * from './lib/components/import-record/import-record.component'
|
|
7
8
|
export * from './lib/components/metadata-quality-panel/metadata-quality-panel.component'
|
|
8
9
|
export * from './lib/components/multilingual-panel/multilingual-panel.component'
|
|
@@ -29,7 +29,10 @@ export const markRecordAsChanged = createAction(
|
|
|
29
29
|
'[Editor] Mark record as changed'
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
export const saveRecord = createAction(
|
|
32
|
+
export const saveRecord = createAction(
|
|
33
|
+
'[Editor] Save record',
|
|
34
|
+
props<{ publish: boolean }>()
|
|
35
|
+
)
|
|
33
36
|
export const saveRecordSuccess = createAction('[Editor] Save record success')
|
|
34
37
|
export const saveRecordFailure = createAction(
|
|
35
38
|
'[Editor] Save record failure',
|
|
@@ -28,30 +28,37 @@ export class EditorEffects {
|
|
|
28
28
|
this.store.select(selectRecordSource),
|
|
29
29
|
this.store.select(selectEditorConfig)
|
|
30
30
|
),
|
|
31
|
-
switchMap(([, record, recordSource, fieldsConfig]) =>
|
|
32
|
-
this.editorService
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
switchMap(([{ publish }, record, recordSource, fieldsConfig]) =>
|
|
32
|
+
this.editorService
|
|
33
|
+
.saveRecord(record, recordSource, fieldsConfig, publish)
|
|
34
|
+
.pipe(
|
|
35
|
+
switchMap(([savedRecord, savedRecordSource]) => {
|
|
36
|
+
const actions: Action[] = [EditorActions.saveRecordSuccess()]
|
|
37
|
+
|
|
38
|
+
if (publish) {
|
|
39
|
+
// saving without publishing doesn't unpublish
|
|
40
|
+
actions.push(EditorActions.isPublished({ isPublished: true }))
|
|
41
|
+
}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
if (!record?.uniqueIdentifier) {
|
|
44
|
+
actions.push(
|
|
45
|
+
EditorActions.openRecord({
|
|
46
|
+
record: savedRecord,
|
|
47
|
+
recordSource: savedRecordSource,
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return of(...actions)
|
|
53
|
+
}),
|
|
54
|
+
catchError((error) =>
|
|
55
|
+
of(
|
|
56
|
+
EditorActions.saveRecordFailure({
|
|
57
|
+
error,
|
|
41
58
|
})
|
|
42
59
|
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return of(...actions)
|
|
46
|
-
}),
|
|
47
|
-
catchError((error) =>
|
|
48
|
-
of(
|
|
49
|
-
EditorActions.saveRecordFailure({
|
|
50
|
-
error,
|
|
51
|
-
})
|
|
52
60
|
)
|
|
53
61
|
)
|
|
54
|
-
)
|
|
55
62
|
)
|
|
56
63
|
)
|
|
57
64
|
)
|
|
@@ -54,7 +54,11 @@ export class EditorFacade {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
saveRecord() {
|
|
57
|
-
this.store.dispatch(EditorActions.saveRecord())
|
|
57
|
+
this.store.dispatch(EditorActions.saveRecord({ publish: false }))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
saveAndPublishRecord() {
|
|
61
|
+
this.store.dispatch(EditorActions.saveRecord({ publish: true }))
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
undoRecordDraft() {
|
package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
|
|
9
9
|
import { FormFieldRichComponent } from '../record-form/form-field/form-field-rich/form-field-rich.component'
|
|
10
10
|
import { ButtonComponent, UrlInputComponent } from '../../../../../../../libs/ui/inputs/src'
|
|
11
|
-
import { MatIconModule } from '@angular/material/icon'
|
|
12
11
|
import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
|
|
13
12
|
import { Constraint } from '../../../../../../../libs/common/domain/src/lib/model/record'
|
|
14
13
|
import {
|
|
@@ -26,7 +25,6 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
|
|
|
26
25
|
FormFieldRichComponent,
|
|
27
26
|
UrlInputComponent,
|
|
28
27
|
ButtonComponent,
|
|
29
|
-
MatIconModule,
|
|
30
28
|
TranslateDirective,
|
|
31
29
|
TranslatePipe,
|
|
32
30
|
NgIconComponent,
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<gn-ui-text-input
|
|
8
8
|
class="block w-full"
|
|
9
9
|
extraClass="w-full"
|
|
10
|
-
[
|
|
11
|
-
(valueChange)="
|
|
10
|
+
[value]="contact.lastName ?? ''"
|
|
11
|
+
(valueChange)="handleChange({ lastName: $event })"
|
|
12
12
|
[placeholder]="
|
|
13
13
|
'editor.record.form.field.contactDetails.lastName.placeholder'
|
|
14
14
|
| translate
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
<gn-ui-text-input
|
|
24
24
|
class="block w-full"
|
|
25
25
|
extraClass="w-full"
|
|
26
|
-
[
|
|
27
|
-
(valueChange)="
|
|
26
|
+
[value]="contact.firstName ?? ''"
|
|
27
|
+
(valueChange)="handleChange({ firstName: $event })"
|
|
28
28
|
[placeholder]="
|
|
29
29
|
'editor.record.form.field.contactDetails.firstName.placeholder'
|
|
30
30
|
| translate
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
<gn-ui-text-input
|
|
41
41
|
class="block w-full"
|
|
42
42
|
extraClass="w-full"
|
|
43
|
-
[
|
|
44
|
-
|
|
43
|
+
[type]="'email'"
|
|
44
|
+
[value]="contact.email ?? ''"
|
|
45
|
+
(valueChange)="handleChange({ email: $event })"
|
|
45
46
|
[placeholder]="
|
|
46
47
|
'editor.record.form.field.contactDetails.email.placeholder' | translate
|
|
47
48
|
"
|
package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts
CHANGED
|
@@ -24,16 +24,18 @@ export class ContactDetailsFormComponent {
|
|
|
24
24
|
@Input() contact: Individual
|
|
25
25
|
@Output() contactChange = new EventEmitter<Individual>()
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// emit a fresh contact on each change; never mutate the @Input
|
|
28
|
+
handleChange(change: Partial<Individual>) {
|
|
29
|
+
this.contactChange.emit({ ...this.contact, ...change })
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
handleOrganizationChange(change: Partial<Organization>) {
|
|
32
|
-
this.
|
|
33
|
-
...
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
this.contactChange.emit({
|
|
34
|
+
...this.contact,
|
|
35
|
+
organization: {
|
|
36
|
+
...(this.contact.organization ?? ({} as Organization)),
|
|
37
|
+
...change,
|
|
38
|
+
} as Organization,
|
|
39
|
+
})
|
|
38
40
|
}
|
|
39
41
|
}
|
package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html
CHANGED
|
@@ -11,20 +11,11 @@
|
|
|
11
11
|
></gn-ui-autocomplete>
|
|
12
12
|
<div class="flex gap-2 flex-wrap">
|
|
13
13
|
@for (keyword of keywords; track keyword) {
|
|
14
|
-
<gn-ui-badge
|
|
15
|
-
[
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<ng-icon
|
|
20
|
-
[title]="
|
|
21
|
-
'editor.record.form.keywords.place.withoutExtent' | translate
|
|
22
|
-
"
|
|
23
|
-
class="badge-warning"
|
|
24
|
-
name="matWarningAmberOutline"
|
|
25
|
-
></ng-icon>
|
|
26
|
-
}
|
|
27
|
-
</gn-ui-badge>
|
|
14
|
+
<gn-ui-keyword-badge
|
|
15
|
+
[keyword]="keyword"
|
|
16
|
+
[editable]="true"
|
|
17
|
+
(keywordRemove)="removeKeyword($event)"
|
|
18
|
+
></gn-ui-keyword-badge>
|
|
28
19
|
}
|
|
29
20
|
</div>
|
|
30
21
|
</div>
|