geonetwork-ui 2.4.0-dev.8118addf → 2.4.0-dev.825a487d

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.
Files changed (129) hide show
  1. package/esm2022/libs/api/metadata-converter/src/index.mjs +1 -2
  2. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +5 -3
  3. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +21 -4
  4. package/esm2022/libs/common/domain/src/lib/model/record/contact.model.mjs +28 -1
  5. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  6. package/esm2022/libs/feature/editor/src/lib/components/contact-card/contact-card.component.mjs +29 -0
  7. package/esm2022/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.mjs +131 -0
  8. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.mjs +170 -0
  9. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.mjs +3 -3
  10. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.mjs +21 -0
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.mjs +7 -6
  12. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +24 -9
  13. package/esm2022/libs/feature/editor/src/lib/components/record-form/record-form.component.mjs +3 -3
  14. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +19 -3
  15. package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +10 -4
  16. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
  17. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +40 -7
  18. package/esm2022/libs/feature/search/src/lib/state/search.facade.mjs +6 -2
  19. package/esm2022/libs/ui/elements/src/index.mjs +2 -1
  20. package/esm2022/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.mjs +27 -0
  21. package/esm2022/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.mjs +4 -3
  22. package/esm2022/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.mjs +2 -2
  23. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +3 -3
  24. package/esm2022/libs/ui/elements/src/lib/sortable-list/sortable-list.component.mjs +7 -3
  25. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +19 -5
  26. package/esm2022/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.mjs +3 -3
  27. package/esm2022/libs/ui/layout/src/lib/interactive-table/interactive-table.component.mjs +3 -3
  28. package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +49 -11
  29. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +18 -6
  30. package/esm2022/translations/de.json +40 -16
  31. package/esm2022/translations/en.json +33 -9
  32. package/esm2022/translations/es.json +33 -9
  33. package/esm2022/translations/fr.json +43 -19
  34. package/esm2022/translations/it.json +33 -9
  35. package/esm2022/translations/nl.json +33 -9
  36. package/esm2022/translations/pt.json +33 -9
  37. package/fesm2022/geonetwork-ui.mjs +984 -259
  38. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  39. package/libs/api/metadata-converter/src/index.d.ts +0 -1
  40. package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
  41. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +6 -1
  42. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  43. package/libs/common/domain/src/lib/model/record/contact.model.d.ts +1 -0
  44. package/libs/common/domain/src/lib/model/record/contact.model.d.ts.map +1 -1
  45. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +8 -0
  46. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  47. package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts +12 -0
  48. package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts.map +1 -0
  49. package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts +27 -0
  50. package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts.map +1 -0
  51. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.d.ts +47 -0
  52. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.d.ts.map +1 -0
  53. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts +11 -0
  54. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts.map +1 -0
  55. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.d.ts +3 -1
  56. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.d.ts.map +1 -1
  57. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +6 -1
  58. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  59. package/libs/feature/editor/src/lib/fields.config.d.ts +2 -0
  60. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  61. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
  62. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +11 -3
  63. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
  64. package/libs/feature/search/src/lib/state/search.facade.d.ts +1 -0
  65. package/libs/feature/search/src/lib/state/search.facade.d.ts.map +1 -1
  66. package/libs/ui/elements/src/index.d.ts +1 -0
  67. package/libs/ui/elements/src/index.d.ts.map +1 -1
  68. package/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.d.ts +18 -0
  69. package/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.d.ts.map +1 -0
  70. package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts +4 -4
  71. package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts.map +1 -1
  72. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +9 -1
  73. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  74. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +10 -1
  75. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
  76. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +6 -2
  77. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  78. package/package.json +1 -1
  79. package/src/libs/api/metadata-converter/src/index.ts +0 -1
  80. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +5 -5
  81. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +24 -4
  82. package/src/libs/common/domain/src/lib/model/record/contact.model.ts +28 -0
  83. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +10 -0
  84. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.css +0 -0
  85. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.html +25 -0
  86. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.ts +30 -0
  87. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.html +2 -1
  88. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.ts +110 -19
  89. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.css +0 -0
  90. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.html +76 -0
  91. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.ts +271 -0
  92. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +1 -1
  93. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.css +0 -0
  94. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.html +5 -0
  95. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +22 -0
  96. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.ts +8 -7
  97. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +11 -0
  98. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +18 -1
  99. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +1 -1
  100. package/src/libs/feature/editor/src/lib/fields.config.ts +20 -2
  101. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +8 -3
  102. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +1 -1
  103. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +2 -1
  104. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +52 -3
  105. package/src/libs/feature/search/src/lib/state/search.facade.ts +6 -0
  106. package/src/libs/ui/elements/src/index.ts +1 -0
  107. package/src/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.css +0 -0
  108. package/src/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.html +12 -0
  109. package/src/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.ts +37 -0
  110. package/src/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.html +4 -1
  111. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.css +2 -1
  112. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +12 -8
  113. package/src/libs/ui/elements/src/lib/sortable-list/sortable-list.component.html +3 -1
  114. package/src/libs/ui/elements/src/lib/sortable-list/sortable-list.component.ts +8 -4
  115. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +15 -3
  116. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +1 -1
  117. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -0
  118. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +10 -1
  119. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +55 -3
  120. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +7 -2
  121. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +9 -9
  122. package/translations/de.json +40 -16
  123. package/translations/en.json +33 -9
  124. package/translations/es.json +33 -9
  125. package/translations/fr.json +43 -19
  126. package/translations/it.json +33 -9
  127. package/translations/nl.json +33 -9
  128. package/translations/pt.json +33 -9
  129. package/translations/sk.json +33 -9
@@ -0,0 +1,271 @@
1
+ import { CommonModule } from '@angular/common'
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ ChangeDetectorRef,
5
+ Component,
6
+ Input,
7
+ OnDestroy,
8
+ OnInit,
9
+ } from '@angular/core'
10
+ import { FormControl } from '@angular/forms'
11
+ import {
12
+ AutocompleteComponent,
13
+ DropdownSelectorComponent,
14
+ UiInputsModule,
15
+ } from '../../../../../../../../../libs/ui/inputs/src'
16
+ import { UiWidgetsModule } from '../../../../../../../../../libs/ui/widgets/src'
17
+ import {
18
+ Individual,
19
+ Organization,
20
+ Role,
21
+ RoleLabels,
22
+ } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
23
+ import { TranslateModule } from '@ngx-translate/core'
24
+ import {
25
+ debounceTime,
26
+ distinctUntilChanged,
27
+ firstValueFrom,
28
+ Observable,
29
+ Subscription,
30
+ switchMap,
31
+ } from 'rxjs'
32
+ import { UserModel } from '../../../../../../../../../libs/common/domain/src/lib/model/user'
33
+ import { PlatformServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/platform.service.interface'
34
+ import { OrganizationsServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/organizations.service.interface'
35
+ import { ContactCardComponent } from '../../../contact-card/contact-card.component'
36
+ import {
37
+ DynamicElement,
38
+ SortableListComponent,
39
+ } from '../../../../../../../../../libs/ui/elements/src'
40
+ import { createFuzzyFilter } from '../../../../../../../../../libs/util/shared/src'
41
+ import { map } from 'rxjs/operators'
42
+
43
+ @Component({
44
+ selector: 'gn-ui-form-field-contacts-for-resource',
45
+ templateUrl: './form-field-contacts-for-resource.component.html',
46
+ styleUrls: ['./form-field-contacts-for-resource.component.css'],
47
+ changeDetection: ChangeDetectionStrategy.OnPush,
48
+ standalone: true,
49
+ imports: [
50
+ DropdownSelectorComponent,
51
+ UiInputsModule,
52
+ CommonModule,
53
+ UiWidgetsModule,
54
+ AutocompleteComponent,
55
+ TranslateModule,
56
+ ContactCardComponent,
57
+ SortableListComponent,
58
+ ],
59
+ })
60
+ export class FormFieldContactsForResourceComponent
61
+ implements OnInit, OnDestroy
62
+ {
63
+ @Input() control: FormControl<Individual[]>
64
+
65
+ subscription: Subscription = new Subscription()
66
+
67
+ allUsers$: Observable<UserModel[]>
68
+
69
+ contactsForRessourceByRole: Map<Role, Individual[]> = new Map()
70
+
71
+ contactsAsDynElemByRole: Map<Role, DynamicElement[]> = new Map()
72
+
73
+ rolesToPick: Role[] = [
74
+ 'resource_provider',
75
+ 'custodian',
76
+ 'owner',
77
+ 'point_of_contact',
78
+ 'author',
79
+ ]
80
+
81
+ roleSectionsToDisplay: Role[] = []
82
+
83
+ allOrganizations: Map<string, Organization> = new Map()
84
+
85
+ constructor(
86
+ private platformServiceInterface: PlatformServiceInterface,
87
+ private organizationsServiceInterface: OrganizationsServiceInterface,
88
+ private changeDetectorRef: ChangeDetectorRef
89
+ ) {
90
+ this.allUsers$ = this.platformServiceInterface.getUsers()
91
+ }
92
+
93
+ async ngOnInit(): Promise<void> {
94
+ this.allOrganizations = new Map<string, Organization>(
95
+ (
96
+ await firstValueFrom(this.organizationsServiceInterface.organisations$)
97
+ ).map((organization) => [organization.name, organization])
98
+ )
99
+ this.updateContactsForRessource()
100
+ this.manageRoleSectionsToDisplay(this.control.value)
101
+ this.filterRolesToPick()
102
+
103
+ this.changeDetectorRef.markForCheck()
104
+
105
+ this.subscription.add(
106
+ this.control.valueChanges.subscribe((contactsForResource) => {
107
+ this.updateContactsForRessource()
108
+ this.manageRoleSectionsToDisplay(contactsForResource)
109
+ this.filterRolesToPick()
110
+
111
+ this.changeDetectorRef.markForCheck()
112
+ })
113
+ )
114
+ }
115
+
116
+ addRoleToDisplay(roleToAdd: string) {
117
+ this.roleSectionsToDisplay.push(roleToAdd)
118
+ this.filterRolesToPick()
119
+ }
120
+
121
+ filterRolesToPick() {
122
+ this.rolesToPick = this.rolesToPick.filter(
123
+ (role) => !this.roleSectionsToDisplay.includes(role)
124
+ )
125
+ }
126
+
127
+ updateContactsForRessource() {
128
+ this.contactsForRessourceByRole = this.control.value.reduce(
129
+ (acc, contact) => {
130
+ const completeOrganization = this.allOrganizations.get(
131
+ contact.organization.name
132
+ )
133
+
134
+ const updatedContact = {
135
+ ...contact,
136
+ organization:
137
+ completeOrganization ??
138
+ ({ name: contact.organization.name } as Organization),
139
+ }
140
+
141
+ if (!acc.has(contact.role)) {
142
+ acc.set(contact.role, [])
143
+ }
144
+
145
+ acc.get(contact.role).push(updatedContact)
146
+
147
+ return acc
148
+ },
149
+ new Map<Role, Individual[]>()
150
+ )
151
+
152
+ this.contactsAsDynElemByRole = this.control.value.reduce((acc, contact) => {
153
+ const completeOrganization = this.allOrganizations.get(
154
+ contact.organization.name
155
+ )
156
+
157
+ const updatedContact = {
158
+ ...contact,
159
+ organization:
160
+ completeOrganization ??
161
+ ({ name: contact.organization.name } as Organization),
162
+ }
163
+
164
+ const contactAsDynElem = {
165
+ component: ContactCardComponent,
166
+ inputs: {
167
+ contact: updatedContact,
168
+ removable: false,
169
+ },
170
+ } as DynamicElement
171
+
172
+ if (!acc.has(contact.role)) {
173
+ acc.set(contact.role, [])
174
+ }
175
+
176
+ acc.get(contact.role).push(contactAsDynElem)
177
+
178
+ return acc
179
+ }, new Map<Role, DynamicElement[]>())
180
+
181
+ this.changeDetectorRef.markForCheck()
182
+ }
183
+
184
+ manageRoleSectionsToDisplay(contactsForResource: Individual[]) {
185
+ const roles = contactsForResource.map(
186
+ (contact: Individual) => contact.role
187
+ ) as Role[]
188
+
189
+ roles.forEach((role: Role) => {
190
+ if (!this.roleSectionsToDisplay.includes(role)) {
191
+ this.roleSectionsToDisplay.push(role)
192
+ }
193
+ })
194
+ }
195
+
196
+ removeContact(index: number) {
197
+ const newContactsforRessource = this.control.value.filter(
198
+ (_, i) => i !== index
199
+ )
200
+ this.control.setValue(newContactsforRessource)
201
+ }
202
+
203
+ handleContactsChanged(event: DynamicElement[]) {
204
+ const newContactsOrdered = event.map(
205
+ (contactAsDynElem) => contactAsDynElem.inputs['contact']
206
+ ) as Individual[]
207
+
208
+ const role = newContactsOrdered[0].role
209
+
210
+ this.contactsForRessourceByRole.set(role, newContactsOrdered)
211
+
212
+ const newControlValue = Array.from(
213
+ this.contactsForRessourceByRole.values()
214
+ ).flat()
215
+
216
+ this.control.setValue(newControlValue)
217
+ }
218
+
219
+ protected roleToLabel(role: string): string {
220
+ return RoleLabels.get(role)
221
+ }
222
+
223
+ /**
224
+ * gn-ui-autocomplete
225
+ */
226
+ displayWithFn: (user: UserModel) => string = (user) =>
227
+ `${user.name} ${user.surname} ${
228
+ user.organisation ? `(${user.organisation})` : ''
229
+ }`
230
+
231
+ /**
232
+ * gn-ui-autocomplete
233
+ */
234
+ autoCompleteAction = (query: string) => {
235
+ const fuzzyFilter = createFuzzyFilter(query)
236
+ return this.allUsers$.pipe(
237
+ switchMap((users) => [
238
+ users.filter((user) => fuzzyFilter(user.username)),
239
+ ]),
240
+ map((results) => results.slice(0, 10)),
241
+ debounceTime(300),
242
+ distinctUntilChanged()
243
+ )
244
+ }
245
+
246
+ /**
247
+ * gn-ui-autocomplete
248
+ */
249
+ addContact(contact: UserModel, role: string) {
250
+ const newContactsForRessource = {
251
+ firstName: contact.name ?? '',
252
+ lastName: contact.surname ?? '',
253
+ organization:
254
+ this.allOrganizations.get(contact.organisation) ??
255
+ ({ name: contact.organisation } as Organization),
256
+ email: contact.email ?? '',
257
+ role,
258
+ address: '',
259
+ phone: '',
260
+ position: '',
261
+ } as Individual
262
+
263
+ const newControlValue = [...this.control.value, newContactsForRessource]
264
+
265
+ this.control.setValue(newControlValue)
266
+ }
267
+
268
+ ngOnDestroy(): void {
269
+ this.subscription.unsubscribe()
270
+ }
271
+ }
@@ -4,7 +4,7 @@
4
4
  [displayWithFn]="displayWithFn"
5
5
  [action]="autoCompleteAction"
6
6
  (itemSelected)="handleItemSelection($event)"
7
- [clearOnSelection]="true"
7
+ [preventCompleteOnSelection]="true"
8
8
  [minCharacterCount]="0"
9
9
  [allowSubmit]="false"
10
10
  ></gn-ui-autocomplete>
@@ -0,0 +1,5 @@
1
+ <gn-ui-overview-upload
2
+ [metadataUuid]="metadataUuid"
3
+ [formControl]="control"
4
+ (overviewChange)="handleOverviewChange($event)"
5
+ ></gn-ui-overview-upload>
@@ -0,0 +1,22 @@
1
+ import { CommonModule } from '@angular/common'
2
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
3
+ import { OverviewUploadComponent } from '../../../overview-upload/overview-upload.component'
4
+ import { FormControl } from '@angular/forms'
5
+ import { GraphicOverview } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
6
+
7
+ @Component({
8
+ selector: 'gn-ui-form-field-overviews',
9
+ templateUrl: './form-field-overviews.component.html',
10
+ styleUrls: ['./form-field-overviews.component.css'],
11
+ changeDetection: ChangeDetectionStrategy.OnPush,
12
+ standalone: true,
13
+ imports: [CommonModule, OverviewUploadComponent],
14
+ })
15
+ export class FormFieldOverviewsComponent {
16
+ @Input() metadataUuid: string
17
+ @Input() control!: FormControl
18
+
19
+ handleOverviewChange(overView: GraphicOverview | null) {
20
+ this.control.setValue(overView ? [overView] : [])
21
+ }
22
+ }
@@ -62,9 +62,9 @@ export class FormFieldTemporalExtentsComponent implements OnInit, OnDestroy {
62
62
  )
63
63
  }
64
64
 
65
- onElementsChange(elements: any) {
65
+ onElementsChange(elements: { inputs: Record<string, unknown> }[]) {
66
66
  this.array.clear({ emitEvent: false })
67
- elements.forEach((e: any, i: number) =>
67
+ elements.forEach((e, i) =>
68
68
  this.array.push(e.inputs.control, {
69
69
  emitEvent: i === elements.length - 1,
70
70
  })
@@ -95,7 +95,7 @@ export class FormFieldTemporalExtentsComponent implements OnInit, OnDestroy {
95
95
 
96
96
  private resetValueFromInput(value) {
97
97
  this.array.clear({ emitEvent: false })
98
- this.elements = []
98
+ let newElements = []
99
99
  value.forEach((v: any) => {
100
100
  if ('start' in v && 'end' in v) {
101
101
  const rangeControl = new FormControl({
@@ -103,8 +103,8 @@ export class FormFieldTemporalExtentsComponent implements OnInit, OnDestroy {
103
103
  end: v.end,
104
104
  })
105
105
  this.array.push(rangeControl, { emitEvent: false })
106
- this.elements = [
107
- ...this.elements,
106
+ newElements = [
107
+ ...newElements,
108
108
  {
109
109
  component: FormFieldTemporalExtentsRangeComponent,
110
110
  inputs: {
@@ -115,8 +115,8 @@ export class FormFieldTemporalExtentsComponent implements OnInit, OnDestroy {
115
115
  } else {
116
116
  const dateControl = new FormControl({ start: v.start })
117
117
  this.array.push(dateControl, { emitEvent: false })
118
- this.elements = [
119
- ...this.elements,
118
+ newElements = [
119
+ ...newElements,
120
120
  {
121
121
  component: FormFieldTemporalExtentsDateComponent,
122
122
  inputs: {
@@ -126,5 +126,6 @@ export class FormFieldTemporalExtentsComponent implements OnInit, OnDestroy {
126
126
  ]
127
127
  }
128
128
  })
129
+ this.elements = newElements
129
130
  }
130
131
  }
@@ -76,9 +76,20 @@
76
76
  <ng-container *ngIf="isSpatialExtentField">
77
77
  <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>
78
78
  </ng-container>
79
+ <ng-container *ngIf="isGraphicOverview">
80
+ <gn-ui-form-field-overviews
81
+ [control]="formControl"
82
+ [metadataUuid]="metadataUuid$ | async"
83
+ ></gn-ui-form-field-overviews>
84
+ </ng-container>
79
85
  <ng-container *ngIf="isKeywords">
80
86
  <gn-ui-form-field-keywords
81
87
  [control]="formControl"
82
88
  ></gn-ui-form-field-keywords>
83
89
  </ng-container>
90
+ <ng-container *ngIf="isContactsForResource">
91
+ <gn-ui-form-field-contacts-for-resource
92
+ [control]="formControl"
93
+ ></gn-ui-form-field-contacts-for-resource>
94
+ </ng-container>
84
95
  </ng-template>
@@ -28,7 +28,11 @@ import { FormFieldSpatialExtentComponent } from './form-field-spatial-extent/for
28
28
  import { FormFieldUpdateFrequencyComponent } from './form-field-update-frequency/form-field-update-frequency.component'
29
29
  import { CatalogRecordKeys } from '../../../../../../../../libs/common/domain/src/lib/model/record'
30
30
  import { FormFieldKeywordsComponent } from './form-field-keywords/form-field-keywords.component'
31
+ import { FormFieldOverviewsComponent } from './form-field-overviews/form-field-overviews.component'
32
+ import { map, take } from 'rxjs/operators'
33
+ import { EditorFacade } from '../../../+state/editor.facade'
31
34
  import { FormFieldConfig } from '../../../models'
35
+ import { FormFieldContactsForResourceComponent } from './form-field-contacts-for-resource/form-field-contacts-for-resource.component'
32
36
 
33
37
  @Component({
34
38
  selector: 'gn-ui-form-field',
@@ -55,6 +59,8 @@ import { FormFieldConfig } from '../../../models'
55
59
  FormFieldArrayComponent,
56
60
  FormFieldKeywordsComponent,
57
61
  TranslateModule,
62
+ FormFieldOverviewsComponent,
63
+ FormFieldContactsForResourceComponent,
58
64
  ],
59
65
  })
60
66
  export class FormFieldComponent {
@@ -70,9 +76,14 @@ export class FormFieldComponent {
70
76
 
71
77
  @ViewChild('titleInput') titleInput: ElementRef
72
78
 
79
+ metadataUuid$ = this.facade.record$.pipe(
80
+ take(1),
81
+ map((record) => record.uniqueIdentifier)
82
+ )
83
+
73
84
  formControl = new FormControl()
74
85
 
75
- constructor() {
86
+ constructor(private facade: EditorFacade) {
76
87
  this.valueChange = this.formControl.valueChanges
77
88
  }
78
89
 
@@ -101,6 +112,9 @@ export class FormFieldComponent {
101
112
  get isSpatialExtentField() {
102
113
  return this.model === 'spatialExtents'
103
114
  }
115
+ get isGraphicOverview() {
116
+ return this.model === 'overviews'
117
+ }
104
118
  get isSimpleField() {
105
119
  return this.model === 'uniqueIdentifier' || this.model === 'recordUpdated'
106
120
  }
@@ -110,6 +124,9 @@ export class FormFieldComponent {
110
124
  get isKeywords() {
111
125
  return this.model === 'keywords'
112
126
  }
127
+ get isContactsForResource() {
128
+ return this.model === 'contactsForResource'
129
+ }
113
130
 
114
131
  get withoutWrapper() {
115
132
  return this.model === 'title' || this.model === 'abstract'
@@ -14,7 +14,7 @@
14
14
  >
15
15
  <div
16
16
  *ngIf="section.labelKey"
17
- class="text-2xl font-petrona text-secondary"
17
+ class="text-2xl font-title text-secondary"
18
18
  translate
19
19
  >
20
20
  {{ section.labelKey }}
@@ -83,6 +83,20 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
83
83
  },
84
84
  }
85
85
 
86
+ export const CONTACTS_FOR_RESOURCE_FIELD: EditorField = {
87
+ model: 'contactsForResource',
88
+ formFieldConfig: {
89
+ labelKey: '',
90
+ },
91
+ }
92
+
93
+ export const RECORD_GRAPHICAL_OVERVIEW_FIELD: EditorField = {
94
+ model: 'overviews',
95
+ formFieldConfig: {
96
+ labelKey: marker('editor.record.form.field.overviews'),
97
+ },
98
+ }
99
+
86
100
  /************************************************************
87
101
  *************** SECTIONS *****************
88
102
  ************************************************************
@@ -90,7 +104,11 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
90
104
 
91
105
  export const TITLE_SECTION: EditorSection = {
92
106
  hidden: false,
93
- fields: [RECORD_TITLE_FIELD, RECORD_ABSTRACT_FIELD],
107
+ fields: [
108
+ RECORD_TITLE_FIELD,
109
+ RECORD_ABSTRACT_FIELD,
110
+ RECORD_GRAPHICAL_OVERVIEW_FIELD,
111
+ ],
94
112
  }
95
113
 
96
114
  export const ABOUT_SECTION: EditorSection = {
@@ -146,7 +164,7 @@ export const DATA_MANAGERS_SECTION: EditorSection = {
146
164
  labelKey: marker('editor.record.form.section.dataManagers.label'),
147
165
  descriptionKey: marker('editor.record.form.section.dataManagers.description'),
148
166
  hidden: false,
149
- fields: [],
167
+ fields: [CONTACTS_FOR_RESOURCE_FIELD],
150
168
  }
151
169
 
152
170
  export const DATA_POINT_OF_CONTACT_SECTION: EditorSection = {
@@ -32,7 +32,7 @@ import { ProxyService } from '../../../../../../libs/util/shared/src'
32
32
  import { WmsEndpoint, WmtsEndpoint } from '@camptocamp/ogc-client'
33
33
  import { LONLAT_CRS_CODES } from '../constant/projections'
34
34
  import { fromEPSGCode, register } from 'ol/proj/proj4'
35
- import proj4 from 'proj4/dist/proj4'
35
+ import proj4 from 'proj4'
36
36
  import { defaults as defaultControls } from 'ol/control/defaults'
37
37
 
38
38
  const FEATURE_PROJECTION = 'EPSG:3857'
@@ -220,10 +220,15 @@ export class MapUtilsService {
220
220
  if (!('spatialExtents' in record) || record.spatialExtents.length === 0) {
221
221
  return null
222
222
  }
223
- // extend all the spatial extents bbox into an including bbox
223
+ // extend all the spatial extents into an including bbox
224
224
  const totalExtent = record.spatialExtents.reduce(
225
225
  (prev, curr) => {
226
- return extend(prev, curr.bbox)
226
+ if ('bbox' in curr) return extend(prev, curr.bbox)
227
+ else if ('geometry' in curr) {
228
+ const geom = GEOJSON.readGeometry(curr.geometry)
229
+ return extend(prev, geom.getExtent())
230
+ }
231
+ return prev
227
232
  },
228
233
  [Infinity, Infinity, -Infinity, -Infinity]
229
234
  )
@@ -6,6 +6,6 @@
6
6
  (inputSubmitted)="handleInputSubmission($event)"
7
7
  (inputCleared)="handleInputCleared()"
8
8
  [value]="searchInputValue$ | async"
9
- [clearOnSelection]="true"
9
+ [preventCompleteOnSelection]="true"
10
10
  [autoFocus]="autoFocus"
11
11
  ></gn-ui-autocomplete>
@@ -1,10 +1,11 @@
1
1
  <gn-ui-results-table
2
2
  [records]="records$ | async"
3
- [recordHasDraft]="hasDraft"
3
+ [hasDraft]="hasDraft"
4
4
  [selectedRecordsIdentifiers]="selectedRecords$ | async"
5
5
  [sortOrder]="sortBy$ | async"
6
6
  (recordClick)="handleRecordClick($event)"
7
7
  (duplicateRecord)="handleDuplicateRecord($event)"
8
+ (deleteRecord)="handleDeleteRecord($event)"
8
9
  (recordsSelectedChange)="handleRecordsSelectedChange($event[0], $event[1])"
9
10
  (sortByChange)="handleSortByChange($event[0], $event[1])"
10
11
  ></gn-ui-results-table>
@@ -1,4 +1,4 @@
1
- import { Component, EventEmitter, Output } from '@angular/core'
1
+ import { Component, EventEmitter, OnDestroy, Output } from '@angular/core'
2
2
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
3
3
  import { SearchFacade } from '../state/search.facade'
4
4
  import { SelectionService } from '../../../../../../libs/api/repository/src'
@@ -6,6 +6,9 @@ import { SearchService } from '../utils/service/search.service'
6
6
  import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
7
7
  import { ResultsTableComponent } from '../../../../../../libs/ui/search/src'
8
8
  import { CommonModule } from '@angular/common'
9
+ import { Subscription } from 'rxjs'
10
+ import { NotificationsService } from '../../../../../../libs/feature/notifications/src'
11
+ import { TranslateService } from '@ngx-translate/core'
9
12
 
10
13
  @Component({
11
14
  selector: 'gn-ui-results-table-container',
@@ -14,10 +17,12 @@ import { CommonModule } from '@angular/common'
14
17
  standalone: true,
15
18
  imports: [CommonModule, ResultsTableComponent],
16
19
  })
17
- export class ResultsTableContainerComponent {
20
+ export class ResultsTableContainerComponent implements OnDestroy {
18
21
  @Output() recordClick = new EventEmitter<CatalogRecord>()
19
22
  @Output() duplicateRecord = new EventEmitter<CatalogRecord>()
20
23
 
24
+ subscription = new Subscription()
25
+
21
26
  records$ = this.searchFacade.results$
22
27
  selectedRecords$ = this.selectionService.selectedRecordsIdentifiers$
23
28
  sortBy$ = this.searchFacade.sortBy$
@@ -29,7 +34,9 @@ export class ResultsTableContainerComponent {
29
34
  private searchFacade: SearchFacade,
30
35
  private searchService: SearchService,
31
36
  private selectionService: SelectionService,
32
- private recordsRepository: RecordsRepositoryInterface
37
+ private recordsRepository: RecordsRepositoryInterface,
38
+ private notificationsService: NotificationsService,
39
+ private translateService: TranslateService
33
40
  ) {}
34
41
 
35
42
  handleRecordClick(item: unknown) {
@@ -40,6 +47,44 @@ export class ResultsTableContainerComponent {
40
47
  this.duplicateRecord.emit(item as CatalogRecord)
41
48
  }
42
49
 
50
+ async handleDeleteRecord(item: unknown) {
51
+ const uniqueIdentifier = (item as CatalogRecord).uniqueIdentifier
52
+ this.subscription.add(
53
+ this.recordsRepository.deleteRecord(uniqueIdentifier).subscribe({
54
+ next: () => {
55
+ this.recordsRepository.clearRecordDraft(uniqueIdentifier)
56
+ this.searchFacade.requestNewResults()
57
+ this.notificationsService.showNotification(
58
+ {
59
+ type: 'success',
60
+ title: this.translateService.instant(
61
+ 'editor.record.deleteSuccess.title'
62
+ ),
63
+ text: `${this.translateService.instant(
64
+ 'editor.record.deleteSuccess.body'
65
+ )}`,
66
+ },
67
+ 2500
68
+ )
69
+ },
70
+ error: (error) => {
71
+ this.notificationsService.showNotification({
72
+ type: 'error',
73
+ title: this.translateService.instant(
74
+ 'editor.record.deleteError.title'
75
+ ),
76
+ text: `${this.translateService.instant(
77
+ 'editor.record.deleteError.body'
78
+ )} ${error}`,
79
+ closeMessage: this.translateService.instant(
80
+ 'editor.record.deleteError.closeMessage'
81
+ ),
82
+ })
83
+ },
84
+ })
85
+ )
86
+ }
87
+
43
88
  handleSortByChange(col: string, order: 'asc' | 'desc') {
44
89
  this.searchService.setSortBy([order, col])
45
90
  }
@@ -51,4 +96,8 @@ export class ResultsTableContainerComponent {
51
96
  this.selectionService.selectRecords(records)
52
97
  }
53
98
  }
99
+
100
+ ngOnDestroy() {
101
+ this.subscription.unsubscribe()
102
+ }
54
103
  }
@@ -8,6 +8,7 @@ import {
8
8
  Paginate,
9
9
  RequestMoreOnAggregation,
10
10
  RequestMoreResults,
11
+ RequestNewResults,
11
12
  SetConfigAggregations,
12
13
  SetConfigFilters,
13
14
  SetConfigRequestFields,
@@ -151,6 +152,11 @@ export class SearchFacade {
151
152
  return this
152
153
  }
153
154
 
155
+ requestNewResults(): SearchFacade {
156
+ this.store.dispatch(new RequestNewResults(this.searchId))
157
+ return this
158
+ }
159
+
154
160
  requestMoreOnAggregation(key: string, increment: number): SearchFacade {
155
161
  this.store.dispatch(
156
162
  new RequestMoreOnAggregation(key, increment, this.searchId)
@@ -1,5 +1,6 @@
1
1
  export * from './lib/api-card/api-card.component'
2
2
  export * from './lib/avatar/avatar.component'
3
+ export * from './lib/confirmation-dialog/confirmation-dialog.component'
3
4
  export * from './lib/content-ghost/content-ghost.component'
4
5
  export * from './lib/download-item/download-item.component'
5
6
  export * from './lib/downloads-list/downloads-list.component'
@@ -0,0 +1,12 @@
1
+ <h1 mat-dialog-title>{{ data.title }}</h1>
2
+ <div mat-dialog-content>{{ data.message }}</div>
3
+ <div mat-dialog-actions>
4
+ <gn-ui-button (buttonClick)="onCancel()">{{ data.cancelText }}</gn-ui-button>
5
+ <gn-ui-button
6
+ (buttonClick)="onConfirm()"
7
+ cdkFocusInitial
8
+ class="ml-2"
9
+ data-cy="confirm-button"
10
+ >{{ data.confirmText }}</gn-ui-button
11
+ >
12
+ </div>