geonetwork-ui 2.4.0-dev.d5b28b1e → 2.4.0-dev.dd042cec

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 (65) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +5 -3
  2. package/esm2022/libs/common/domain/src/lib/model/record/contact.model.mjs +28 -1
  3. package/esm2022/libs/feature/editor/src/lib/components/contact-card/contact-card.component.mjs +29 -0
  4. 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
  5. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.mjs +3 -3
  6. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.mjs +47 -0
  7. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +17 -3
  8. package/esm2022/libs/feature/editor/src/lib/components/record-form/record-form.component.mjs +3 -3
  9. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +19 -2
  10. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
  11. package/esm2022/libs/ui/elements/src/lib/sortable-list/sortable-list.component.mjs +2 -1
  12. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +19 -5
  13. package/esm2022/translations/de.json +23 -0
  14. package/esm2022/translations/en.json +23 -0
  15. package/esm2022/translations/es.json +23 -0
  16. package/esm2022/translations/fr.json +24 -1
  17. package/esm2022/translations/it.json +23 -0
  18. package/esm2022/translations/nl.json +23 -0
  19. package/esm2022/translations/pt.json +23 -0
  20. package/fesm2022/geonetwork-ui.mjs +507 -16
  21. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  22. package/libs/common/domain/src/lib/model/record/contact.model.d.ts +1 -0
  23. package/libs/common/domain/src/lib/model/record/contact.model.d.ts.map +1 -1
  24. package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts +12 -0
  25. package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts.map +1 -0
  26. 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
  27. 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
  28. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.d.ts +17 -0
  29. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.d.ts.map +1 -0
  30. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +4 -0
  31. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  32. package/libs/feature/editor/src/lib/fields.config.d.ts +6 -0
  33. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  34. package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts +1 -2
  35. package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts.map +1 -1
  36. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +9 -1
  37. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +5 -5
  40. package/src/libs/common/domain/src/lib/model/record/contact.model.ts +28 -0
  41. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.css +0 -0
  42. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.html +25 -0
  43. package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.ts +30 -0
  44. 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
  45. 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
  46. 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
  47. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +1 -1
  48. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.css +0 -0
  49. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.html +6 -0
  50. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.ts +59 -0
  51. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +12 -1
  52. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +17 -0
  53. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +1 -1
  54. package/src/libs/feature/editor/src/lib/fields.config.ts +20 -1
  55. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +1 -1
  56. package/src/libs/ui/elements/src/lib/sortable-list/sortable-list.component.ts +2 -2
  57. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +15 -3
  58. package/translations/de.json +23 -0
  59. package/translations/en.json +23 -0
  60. package/translations/es.json +23 -0
  61. package/translations/fr.json +24 -1
  62. package/translations/it.json +23 -0
  63. package/translations/nl.json +23 -0
  64. package/translations/pt.json +23 -0
  65. package/translations/sk.json +23 -0
@@ -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,6 @@
1
+ <gn-ui-check-toggle
2
+ [label]="'editor.record.form.classification.opendata' | translate"
3
+ [value]="value"
4
+ (toggled)="onOpenDataToggled($event)"
5
+ data-cy="openDataToggle"
6
+ ></gn-ui-check-toggle>
@@ -0,0 +1,59 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ EventEmitter,
5
+ Input,
6
+ OnChanges,
7
+ OnInit,
8
+ Output,
9
+ SimpleChanges,
10
+ } from '@angular/core'
11
+ import { FormControl } from '@angular/forms'
12
+ import { CheckToggleComponent } from '../../../../../../../../../libs/ui/inputs/src'
13
+ import { TranslateModule } from '@ngx-translate/core'
14
+ import { OPEN_DATA_LICENSES } from './../../../../fields.config'
15
+ import { Subscription } from 'rxjs'
16
+
17
+ @Component({
18
+ selector: 'gn-ui-form-field-open-data',
19
+ templateUrl: './form-field-open-data.component.html',
20
+ styleUrls: ['./form-field-open-data.component.css'],
21
+ standalone: true,
22
+ imports: [CheckToggleComponent, TranslateModule],
23
+ changeDetection: ChangeDetectionStrategy.OnPush,
24
+ })
25
+ export class FormFieldOpenDataComponent implements OnInit {
26
+ @Input() control: FormControl
27
+ value = false
28
+ @Output() visibilityChange = new EventEmitter<boolean>()
29
+ subscription: Subscription
30
+
31
+ get config() {
32
+ return OPEN_DATA_LICENSES
33
+ }
34
+
35
+ ngOnInit() {
36
+ this.initToggle()
37
+ this.subscription = new Subscription()
38
+
39
+ this.subscription.add(
40
+ this.control.valueChanges.subscribe((value) => {
41
+ this.value = this.config.includes(value[0].text)
42
+ this.visibilityChange.emit(this.value)
43
+ })
44
+ )
45
+ }
46
+
47
+ initToggle() {
48
+ this.value = this.config.includes(this.control.value[0].text)
49
+ this.visibilityChange.emit(this.value)
50
+ }
51
+
52
+ onOpenDataToggled(boolean) {
53
+ if (boolean) {
54
+ this.control.setValue([{ text: this.config[0] }])
55
+ }
56
+ this.value = !this.value
57
+ this.visibilityChange.emit(boolean)
58
+ }
59
+ }
@@ -1,4 +1,10 @@
1
- <div class="flex flex-col h-full">
1
+ <ng-container *ngIf="isOpenData">
2
+ <gn-ui-form-field-open-data
3
+ [control]="formControl"
4
+ (visibilityChange)="onVisibilityChange($event)"
5
+ ></gn-ui-form-field-open-data>
6
+ </ng-container>
7
+ <div class="flex flex-col h-full" *ngIf="!isHidden">
2
8
  <ng-container *ngIf="withoutWrapper; else withGenericWrapper">
3
9
  <ng-container *ngTemplateOutlet="fieldContent"></ng-container>
4
10
  </ng-container>
@@ -87,4 +93,9 @@
87
93
  [control]="formControl"
88
94
  ></gn-ui-form-field-keywords>
89
95
  </ng-container>
96
+ <ng-container *ngIf="isContactsForResource">
97
+ <gn-ui-form-field-contacts-for-resource
98
+ [control]="formControl"
99
+ ></gn-ui-form-field-contacts-for-resource>
100
+ </ng-container>
90
101
  </ng-template>
@@ -3,6 +3,7 @@ import {
3
3
  ChangeDetectionStrategy,
4
4
  Component,
5
5
  ElementRef,
6
+ EventEmitter,
6
7
  Input,
7
8
  Output,
8
9
  ViewChild,
@@ -32,6 +33,8 @@ import { FormFieldOverviewsComponent } from './form-field-overviews/form-field-o
32
33
  import { map, take } from 'rxjs/operators'
33
34
  import { EditorFacade } from '../../../+state/editor.facade'
34
35
  import { FormFieldConfig } from '../../../models'
36
+ import { FormFieldContactsForResourceComponent } from './form-field-contacts-for-resource/form-field-contacts-for-resource.component'
37
+ import { FormFieldOpenDataComponent } from './form-field-open-data/form-field-open-data.component'
35
38
 
36
39
  @Component({
37
40
  selector: 'gn-ui-form-field',
@@ -59,6 +62,8 @@ import { FormFieldConfig } from '../../../models'
59
62
  FormFieldKeywordsComponent,
60
63
  TranslateModule,
61
64
  FormFieldOverviewsComponent,
65
+ FormFieldContactsForResourceComponent,
66
+ FormFieldOpenDataComponent,
62
67
  ],
63
68
  })
64
69
  export class FormFieldComponent {
@@ -71,6 +76,7 @@ export class FormFieldComponent {
71
76
  }
72
77
 
73
78
  @Output() valueChange: Observable<unknown>
79
+ isHidden = false
74
80
 
75
81
  @ViewChild('titleInput') titleInput: ElementRef
76
82
 
@@ -89,6 +95,10 @@ export class FormFieldComponent {
89
95
  this.titleInput.nativeElement.children[0].focus()
90
96
  }
91
97
 
98
+ onVisibilityChange(visibility: boolean) {
99
+ this.isHidden = visibility
100
+ }
101
+
92
102
  get isTitle() {
93
103
  return this.model === 'title'
94
104
  }
@@ -122,8 +132,15 @@ export class FormFieldComponent {
122
132
  get isKeywords() {
123
133
  return this.model === 'keywords'
124
134
  }
135
+ get isContactsForResource() {
136
+ return this.model === 'contactsForResource'
137
+ }
125
138
 
126
139
  get withoutWrapper() {
127
140
  return this.model === 'title' || this.model === 'abstract'
128
141
  }
142
+
143
+ get isOpenData() {
144
+ return this.model === 'licenses'
145
+ }
129
146
  }
@@ -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,13 @@ 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
+
86
93
  export const RECORD_GRAPHICAL_OVERVIEW_FIELD: EditorField = {
87
94
  model: 'overviews',
88
95
  formFieldConfig: {
@@ -157,7 +164,7 @@ export const DATA_MANAGERS_SECTION: EditorSection = {
157
164
  labelKey: marker('editor.record.form.section.dataManagers.label'),
158
165
  descriptionKey: marker('editor.record.form.section.dataManagers.description'),
159
166
  hidden: false,
160
- fields: [],
167
+ fields: [CONTACTS_FOR_RESOURCE_FIELD],
161
168
  }
162
169
 
163
170
  export const DATA_POINT_OF_CONTACT_SECTION: EditorSection = {
@@ -194,3 +201,15 @@ export const DEFAULT_CONFIGURATION: EditorConfig = {
194
201
  },
195
202
  ],
196
203
  }
204
+
205
+ /************************************************************
206
+ *************** LICENSES *****************
207
+ ************************************************************
208
+ */
209
+ export const OPEN_DATA_LICENSES: string[] = [
210
+ 'etalab',
211
+ 'etalab-v2',
212
+ 'odbl',
213
+ 'odc-by',
214
+ 'pddl',
215
+ ]
@@ -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>
@@ -17,7 +17,7 @@ import {
17
17
  import { MatIconModule } from '@angular/material/icon'
18
18
  import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
19
19
 
20
- type DynamicElement = {
20
+ export type DynamicElement = {
21
21
  component: Type<unknown>
22
22
  inputs: Record<string, unknown>
23
23
  }
@@ -40,7 +40,7 @@ type DynamicElement = {
40
40
  })
41
41
  export class SortableListComponent {
42
42
  @Input() elements: Array<DynamicElement>
43
- @Input() addOptions: Array<{ buttonLabel: string; eventName: string }>
43
+ @Input() addOptions: Array<{ buttonLabel: string; eventName: string }> = []
44
44
  @Output() elementsChange = new EventEmitter<Array<DynamicElement>>()
45
45
  @Output() add = new EventEmitter<string>()
46
46
 
@@ -61,6 +61,7 @@ export class AutocompleteComponent
61
61
  @Input() action: (value: string) => Observable<AutocompleteItem[]>
62
62
  @Input() value?: AutocompleteItem
63
63
  @Input() clearOnSelection = false
64
+ @Input() preventCompleteOnSelection = false
64
65
  @Input() autoFocus = false
65
66
  @Input() minCharacterCount? = 3
66
67
  @Input() allowSubmit = true
@@ -206,13 +207,24 @@ export class AutocompleteComponent
206
207
  this.inputSubmitted.emit(this.inputRef.nativeElement.value)
207
208
  }
208
209
 
210
+ /**
211
+ * This function is triggered when an item is selected in the list of displayed items.
212
+ * If preventCompleteOnSelection is true then the input will be left as entered by the user.
213
+ * If preventCompleteOnSelection is false (by default) then the input will be completed with the item selected by the user.
214
+ * If clearOnSelection is true then the input will be cleared upon selection.
215
+ * @param event
216
+ */
209
217
  handleSelection(event: MatAutocompleteSelectedEvent) {
210
218
  this.cancelEnter = true
211
219
  this.itemSelected.emit(event.option.value)
212
- if (this.clearOnSelection) {
213
- this.lastInputValue$.pipe(first()).subscribe((any) => {
214
- this.inputRef.nativeElement.value = any
220
+ if (this.preventCompleteOnSelection) {
221
+ this.lastInputValue$.pipe(first()).subscribe((lastInputValue) => {
222
+ this.inputRef.nativeElement.value = lastInputValue
215
223
  })
224
+ return
225
+ }
226
+ if (this.clearOnSelection) {
227
+ this.inputRef.nativeElement.value = ''
216
228
  }
217
229
  }
218
230
  }
@@ -147,6 +147,27 @@
147
147
  "dataset.error.parse": "Die Daten wurden geladen, konnten aber nicht gelesen werden: \"{ info }\"",
148
148
  "dataset.error.unknown": "Die Daten können nicht angezeigt werden: \"{ info }\"",
149
149
  "dataset.error.unsupportedType": "Der folgende Inhaltstyp wird nicht unterstützt: \"{ info }\"",
150
+ "domain.contact.role.author": "",
151
+ "domain.contact.role.collaborator": "",
152
+ "domain.contact.role.contributor": "",
153
+ "domain.contact.role.custodian": "",
154
+ "domain.contact.role.distributor": "",
155
+ "domain.contact.role.editor": "",
156
+ "domain.contact.role.funder": "",
157
+ "domain.contact.role.mediator": "",
158
+ "domain.contact.role.originator": "",
159
+ "domain.contact.role.other": "",
160
+ "domain.contact.role.owner": "",
161
+ "domain.contact.role.point_of_contact": "",
162
+ "domain.contact.role.principal_investigator": "",
163
+ "domain.contact.role.processor": "",
164
+ "domain.contact.role.publisher": "",
165
+ "domain.contact.role.resource_provider": "",
166
+ "domain.contact.role.rights_holder": "",
167
+ "domain.contact.role.sponsor": "",
168
+ "domain.contact.role.stakeholder": "",
169
+ "domain.contact.role.unspecified": "",
170
+ "domain.contact.role.user": "",
150
171
  "domain.record.status.completed": "Abgeschlossen",
151
172
  "domain.record.status.deprecated": "Veraltet",
152
173
  "domain.record.status.ongoing": "Kontinuierliche Aktualisierung",
@@ -178,6 +199,7 @@
178
199
  "editor.record.form.bottomButtons.next": "",
179
200
  "editor.record.form.bottomButtons.previous": "",
180
201
  "editor.record.form.field.abstract": "Kurzbeschreibung",
202
+ "editor.record.form.field.contactsForResource.noContact": "",
181
203
  "editor.record.form.field.keywords": "Schlagwörter",
182
204
  "editor.record.form.field.license": "Lizenz",
183
205
  "editor.record.form.field.overviews": "",
@@ -187,6 +209,7 @@
187
209
  "editor.record.form.field.title": "Metadaten-Titel",
188
210
  "editor.record.form.field.uniqueIdentifier": "Eindeutige Kennung (ID)",
189
211
  "editor.record.form.field.updateFrequency": "Aktualisierungshäufigkeit",
212
+ "editor.record.form.classification.opendata": "",
190
213
  "editor.record.form.license.cc-by": "Creative Commons CC-BY",
191
214
  "editor.record.form.license.cc-by-sa": "Creative Commons CC-BY-SA",
192
215
  "editor.record.form.license.cc-zero": "Creative Commons CC-0",
@@ -147,6 +147,27 @@
147
147
  "dataset.error.parse": "The data was loaded but could not be parsed: \"{ info }\"",
148
148
  "dataset.error.unknown": "The data cannot be displayed: \"{ info }\"",
149
149
  "dataset.error.unsupportedType": "The following content type is unsupported: \"{ info }\"",
150
+ "domain.contact.role.author": "Author",
151
+ "domain.contact.role.collaborator": "Collaborator",
152
+ "domain.contact.role.contributor": "Contributor",
153
+ "domain.contact.role.custodian": "Custodian",
154
+ "domain.contact.role.distributor": "Distributor",
155
+ "domain.contact.role.editor": "Editor",
156
+ "domain.contact.role.funder": "Funder",
157
+ "domain.contact.role.mediator": "Mediator",
158
+ "domain.contact.role.originator": "Originator",
159
+ "domain.contact.role.other": "Other",
160
+ "domain.contact.role.owner": "Owner",
161
+ "domain.contact.role.point_of_contact": "Point of contact",
162
+ "domain.contact.role.principal_investigator": "Principal investigator",
163
+ "domain.contact.role.processor": "Processor",
164
+ "domain.contact.role.publisher": "Publisher",
165
+ "domain.contact.role.resource_provider": "Resource provider",
166
+ "domain.contact.role.rights_holder": "Rights holder",
167
+ "domain.contact.role.sponsor": "Sponsor",
168
+ "domain.contact.role.stakeholder": "Stakeholder",
169
+ "domain.contact.role.unspecified": "Unspecified",
170
+ "domain.contact.role.user": "User",
150
171
  "domain.record.status.completed": "Completed",
151
172
  "domain.record.status.deprecated": "Deprecated",
152
173
  "domain.record.status.ongoing": "On going",
@@ -177,7 +198,9 @@
177
198
  "editor.record.form.bottomButtons.comeBackLater": "Come back later",
178
199
  "editor.record.form.bottomButtons.next": "Next",
179
200
  "editor.record.form.bottomButtons.previous": "Previous",
201
+ "editor.record.form.classification.opendata": "Open Data",
180
202
  "editor.record.form.field.abstract": "Abstract",
203
+ "editor.record.form.field.contactsForResource.noContact": "Please provide at least one point of contact responsible for the data.",
181
204
  "editor.record.form.field.keywords": "Keywords",
182
205
  "editor.record.form.field.license": "License",
183
206
  "editor.record.form.field.overviews": "Overviews",
@@ -147,6 +147,27 @@
147
147
  "dataset.error.parse": "",
148
148
  "dataset.error.unknown": "",
149
149
  "dataset.error.unsupportedType": "",
150
+ "domain.contact.role.author": "",
151
+ "domain.contact.role.collaborator": "",
152
+ "domain.contact.role.contributor": "",
153
+ "domain.contact.role.custodian": "",
154
+ "domain.contact.role.distributor": "",
155
+ "domain.contact.role.editor": "",
156
+ "domain.contact.role.funder": "",
157
+ "domain.contact.role.mediator": "",
158
+ "domain.contact.role.originator": "",
159
+ "domain.contact.role.other": "",
160
+ "domain.contact.role.owner": "",
161
+ "domain.contact.role.point_of_contact": "",
162
+ "domain.contact.role.principal_investigator": "",
163
+ "domain.contact.role.processor": "",
164
+ "domain.contact.role.publisher": "",
165
+ "domain.contact.role.resource_provider": "",
166
+ "domain.contact.role.rights_holder": "",
167
+ "domain.contact.role.sponsor": "",
168
+ "domain.contact.role.stakeholder": "",
169
+ "domain.contact.role.unspecified": "",
170
+ "domain.contact.role.user": "",
150
171
  "domain.record.status.completed": "",
151
172
  "domain.record.status.deprecated": "",
152
173
  "domain.record.status.ongoing": "",
@@ -177,7 +198,9 @@
177
198
  "editor.record.form.bottomButtons.comeBackLater": "",
178
199
  "editor.record.form.bottomButtons.next": "",
179
200
  "editor.record.form.bottomButtons.previous": "",
201
+ "editor.record.form.classification.opendata": "",
180
202
  "editor.record.form.field.abstract": "",
203
+ "editor.record.form.field.contactsForResource.noContact": "",
181
204
  "editor.record.form.field.keywords": "",
182
205
  "editor.record.form.field.license": "",
183
206
  "editor.record.form.field.overviews": "",