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.
- package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +5 -3
- package/esm2022/libs/common/domain/src/lib/model/record/contact.model.mjs +28 -1
- package/esm2022/libs/feature/editor/src/lib/components/contact-card/contact-card.component.mjs +29 -0
- 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
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.mjs +3 -3
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.mjs +47 -0
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +17 -3
- package/esm2022/libs/feature/editor/src/lib/components/record-form/record-form.component.mjs +3 -3
- package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +19 -2
- package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/sortable-list/sortable-list.component.mjs +2 -1
- package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +19 -5
- package/esm2022/translations/de.json +23 -0
- package/esm2022/translations/en.json +23 -0
- package/esm2022/translations/es.json +23 -0
- package/esm2022/translations/fr.json +24 -1
- package/esm2022/translations/it.json +23 -0
- package/esm2022/translations/nl.json +23 -0
- package/esm2022/translations/pt.json +23 -0
- package/fesm2022/geonetwork-ui.mjs +507 -16
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/common/domain/src/lib/model/record/contact.model.d.ts +1 -0
- package/libs/common/domain/src/lib/model/record/contact.model.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts +12 -0
- package/libs/feature/editor/src/lib/components/contact-card/contact-card.component.d.ts.map +1 -0
- 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
- 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
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.d.ts +17 -0
- 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
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +4 -0
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/fields.config.d.ts +6 -0
- package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts +1 -2
- package/libs/ui/elements/src/lib/sortable-list/sortable-list.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +9 -1
- package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +5 -5
- package/src/libs/common/domain/src/lib/model/record/contact.model.ts +28 -0
- package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.html +25 -0
- package/src/libs/feature/editor/src/lib/components/contact-card/contact-card.component.ts +30 -0
- 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
- 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
- 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
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +1 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.html +6 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-open-data/form-field-open-data.component.ts +59 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +12 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +17 -0
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +1 -1
- package/src/libs/feature/editor/src/lib/fields.config.ts +20 -1
- package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +1 -1
- package/src/libs/ui/elements/src/lib/sortable-list/sortable-list.component.ts +2 -2
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +15 -3
- package/translations/de.json +23 -0
- package/translations/en.json +23 -0
- package/translations/es.json +23 -0
- package/translations/fr.json +24 -1
- package/translations/it.json +23 -0
- package/translations/nl.json +23 -0
- package/translations/pt.json +23 -0
- 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
|
+
}
|
|
File without changes
|
|
@@ -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
|
+
}
|
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
<
|
|
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>
|
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts
CHANGED
|
@@ -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
|
}
|
|
@@ -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
|
+
]
|
|
@@ -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.
|
|
213
|
-
this.lastInputValue$.pipe(first()).subscribe((
|
|
214
|
-
this.inputRef.nativeElement.value =
|
|
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
|
}
|
package/translations/de.json
CHANGED
|
@@ -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",
|
package/translations/en.json
CHANGED
|
@@ -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",
|
package/translations/es.json
CHANGED
|
@@ -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": "",
|