geonetwork-ui 2.11.0-dev.80a8b0bfa → 2.11.0-dev.840dcc932

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 (105) hide show
  1. package/fesm2022/geonetwork-ui.mjs +2273 -1474
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +342 -136
  4. package/index.d.ts.map +1 -1
  5. package/package.json +7 -5
  6. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +2 -0
  7. package/src/libs/api/metadata-converter/src/lib/fixtures/mel.records.dataset+featurecatalog.ts +395 -0
  8. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +35 -8
  9. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +19 -0
  10. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +17 -6
  11. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +110 -0
  12. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +131 -0
  13. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +9 -0
  14. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +2 -1
  15. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +134 -35
  16. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +83 -35
  17. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
  18. package/src/libs/common/domain/src/lib/model/record/flags.model.ts +1 -0
  19. package/src/libs/common/domain/src/lib/model/record/index.ts +1 -0
  20. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +14 -18
  21. package/src/libs/common/domain/src/lib/model/search/aggregation.model.ts +2 -0
  22. package/src/libs/common/domain/src/lib/model/search/filter.model.ts +24 -2
  23. package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -0
  24. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +20 -1
  25. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +42 -62
  26. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +32 -19
  27. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints/form-field-constraints.component.ts +3 -5
  28. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +2 -2
  29. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.html +18 -0
  30. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.ts +86 -0
  31. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +100 -88
  32. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -4
  33. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +18 -4
  34. package/src/libs/feature/editor/src/lib/expressions.ts +67 -0
  35. package/src/libs/feature/editor/src/lib/fields.config.ts +13 -0
  36. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -4
  37. package/src/libs/feature/map/src/index.ts +0 -2
  38. package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +1 -0
  39. package/src/libs/feature/map/src/lib/feature-map.module.ts +1 -8
  40. package/src/libs/feature/notifications/src/lib/notifications.service.ts +6 -4
  41. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +8 -3
  42. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +3 -1
  43. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -1
  44. package/src/libs/feature/router/src/lib/default/state/query-params.utils.ts +1 -1
  45. package/src/libs/feature/search/src/index.ts +2 -0
  46. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +18 -4
  47. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +80 -19
  48. package/src/libs/feature/search/src/lib/geocoding/geocoding.service.ts +105 -0
  49. package/src/libs/feature/search/src/lib/location-search/location-search.component.html +18 -0
  50. package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +114 -0
  51. package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +19 -8
  52. package/src/libs/feature/search/src/lib/state/reducer.ts +1 -4
  53. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +64 -4
  54. package/src/libs/feature/search/src/lib/utils/service/fields.ts +92 -9
  55. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +3 -3
  56. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.ts +2 -2
  57. package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.ts +2 -1
  58. package/src/libs/ui/inputs/src/index.ts +2 -0
  59. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -4
  60. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +12 -3
  61. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +11 -3
  62. package/src/libs/ui/inputs/src/lib/date-adapter.providers.ts +30 -0
  63. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +3 -24
  64. package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.css +37 -3
  65. package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.html +135 -16
  66. package/src/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.ts +166 -29
  67. package/src/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.ts +3 -7
  68. package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.css +1 -0
  69. package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.html +20 -7
  70. package/src/libs/ui/inputs/src/lib/drag-and-drop-file-input/drag-and-drop-file-input.component.ts +46 -5
  71. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +7 -4
  72. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +12 -9
  73. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.model.ts +2 -2
  74. package/src/libs/ui/inputs/src/lib/search-feature-catalog/search-feature-catalog.component.ts +2 -1
  75. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.css +0 -0
  76. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +117 -0
  77. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +244 -0
  78. package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +1 -0
  79. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +6 -5
  80. package/src/libs/util/app-config/src/lib/app-config.ts +37 -0
  81. package/src/libs/util/app-config/src/lib/fixtures.ts +37 -1
  82. package/src/libs/util/app-config/src/lib/model.ts +25 -1
  83. package/src/libs/util/shared/src/index.ts +1 -0
  84. package/src/libs/util/shared/src/lib/autofocus.directive.ts +26 -0
  85. package/src/libs/util/shared/src/lib/links/link-utils.ts +19 -10
  86. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  87. package/src/libs/util/shared/src/lib/utils/file.ts +15 -0
  88. package/src/libs/util/shared/src/lib/utils/geojson.ts +24 -0
  89. package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
  90. package/tailwind.base.css +5 -0
  91. package/translations/de.json +28 -4
  92. package/translations/en.json +27 -3
  93. package/translations/es.json +26 -2
  94. package/translations/fr.json +32 -8
  95. package/translations/it.json +26 -2
  96. package/translations/nl.json +26 -2
  97. package/translations/pt.json +26 -2
  98. package/translations/sk.json +26 -2
  99. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +0 -41
  100. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +0 -112
  101. package/src/libs/feature/map/src/lib/geocoding.service.ts +0 -57
  102. package/src/libs/feature/map/src/lib/style/index.ts +0 -2
  103. package/src/libs/feature/map/src/lib/style/map-style.fixtures.ts +0 -47
  104. package/src/libs/feature/map/src/lib/style/map-style.service.ts +0 -108
  105. /package/src/libs/feature/{map/src/lib/geocoding/geocoding.component.css → editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.css} +0 -0
@@ -316,6 +316,7 @@ export interface DatasetRecord extends BaseRecord {
316
316
  spatialExtents: Array<DatasetSpatialExtent>
317
317
  temporalExtents: Array<DatasetTemporalExtent>
318
318
  spatialRepresentation?: SpatialRepresentationType
319
+ featureTypeDescriptions?: Array<DatasetFeatureType>
319
320
  }
320
321
 
321
322
  export interface ServiceEndpoint {
@@ -347,33 +348,28 @@ export interface ReuseRecord extends BaseRecord {
347
348
  temporalExtents: Array<DatasetTemporalExtent>
348
349
  }
349
350
 
351
+ export interface DatasetFeatureType {
352
+ name: string
353
+ label?: string
354
+ description?: string
355
+ attributes: DatasetFeatureAttribute[]
356
+ }
350
357
  export type DatasetFeatureCatalog = {
351
- featureTypes: Array<{
352
- name: string
353
- definition: string
354
- attributes: DatasetFeatureAttribute[]
355
- }>
358
+ featureTypes: Array<DatasetFeatureType>
356
359
  }
357
360
  export interface DatasetFeatureAttributeValue {
358
- code?: string
359
- definition?: string
361
+ value: string // empty string when the value has no code
360
362
  label?: string
363
+ description?: string
361
364
  }
362
365
  export interface DatasetFeatureAttribute {
363
366
  name: string
364
- definition: string
365
- type: string
366
- code: string
367
+ label?: string
368
+ description?: string
369
+ type?: string
370
+ code?: string
367
371
  values?: Array<DatasetFeatureAttributeValue>
368
372
  }
369
- export interface DatasetFeatureType {
370
- aliases: string
371
- code: string
372
- isAbstract: string
373
- typeName: string
374
- definition: string
375
- attributeTable: Array<DatasetFeatureAttribute>
376
- }
377
373
 
378
374
  export type ReuseType = 'application' | 'map' | 'other'
379
375
 
@@ -7,6 +7,8 @@ export interface TermsAggregationParams {
7
7
  limit: number
8
8
  sort: AggregationSort
9
9
  filter?: string
10
+ includeValues?: string[]
11
+ excludeValues?: string[]
10
12
  }
11
13
  export interface HistogramAggregationParams {
12
14
  type: 'histogram'
@@ -6,17 +6,39 @@ export type FieldFilterByRange = {
6
6
  start?: Date
7
7
  end?: Date
8
8
  }
9
+ // matches util/shared's BoundingBox; duplicated here to avoid a circular
10
+ // dependency (util/shared already depends on common/domain)
11
+ export type FieldFilterByBoundingBox = [number, number, number, number]
9
12
 
10
13
  export type FieldFilter =
11
14
  | FieldFilterByExpression
12
15
  | FieldFilterByValues
13
16
  | FieldFilterByRange
17
+ | FieldFilterByBoundingBox
14
18
  export type FieldFilters = Record<FieldName, FieldFilter>
15
19
 
16
20
  export type QueryString = {
17
21
  query_string: string
18
22
  }
19
23
  export type QueryRange = {
20
- range: Record<string, { format: string; gte: string; lte: string }>
24
+ range: Record<
25
+ string,
26
+ { format: string; gte?: string; lte?: string; relation?: string }
27
+ >
21
28
  }
22
- export type FilterQuery = Array<QueryString | QueryRange>
29
+ export type QueryGeoShape = {
30
+ geo_shape: {
31
+ geom: {
32
+ shape: { type: string; coordinates: number[][] }
33
+ relation: string
34
+ }
35
+ }
36
+ }
37
+ export type QueryBool = {
38
+ bool: {
39
+ filter: QueryRange[]
40
+ }
41
+ }
42
+ export type FilterQuery = Array<
43
+ QueryString | QueryRange | QueryGeoShape | QueryBool
44
+ >
@@ -28,6 +28,7 @@ export abstract class PlatformServiceInterface {
28
28
  abstract supportsAuthentication(): boolean
29
29
  abstract getMe(): Observable<UserModel>
30
30
  abstract isAnonymous(): Observable<boolean>
31
+ abstract isAdministrator(): Observable<boolean>
31
32
  abstract getUsers(): Observable<UserModel[]>
32
33
  abstract getUserPermissionsByGroup(): Observable<GroupModel[]>
33
34
  abstract getUsersByOrganization(
@@ -11,13 +11,14 @@ import {
11
11
  DatasetFeatureCatalog,
12
12
  LanguageCode,
13
13
  LinkedRecord,
14
+ RecordFlag,
14
15
  } from '../model/record'
15
16
 
16
17
  export abstract class RecordsRepositoryInterface {
17
18
  abstract search(params: SearchParams): Observable<SearchResults>
18
19
  abstract getMatchesCount(filters: FieldFilters): Observable<number>
19
20
  abstract getRecord(uniqueIdentifier: string): Observable<CatalogRecord | null>
20
- abstract getFeatureCatalog(
21
+ abstract queryLinkedFeatureCatalog(
21
22
  record: CatalogRecord
22
23
  ): Observable<DatasetFeatureCatalog | null>
23
24
  abstract aggregate(params: AggregationsParams): Observable<Aggregations>
@@ -106,4 +107,22 @@ export abstract class RecordsRepositoryInterface {
106
107
  ): Observable<{ user: string; date: Date }>
107
108
  abstract getRecordPublicationStatus(uuid: string): Observable<boolean>
108
109
  abstract getApplicationLanguages(): Observable<LanguageCode[]>
110
+
111
+ /**
112
+ * Sets a given flag on a record. Flags are not part of the metadata document, which is why they are
113
+ * not part of the Record model.
114
+ */
115
+ abstract setRecordFlag(
116
+ uniqueIdentifier: string,
117
+ flagName: RecordFlag,
118
+ value: boolean
119
+ ): Observable<void>
120
+
121
+ /**
122
+ * Checks whether a given flag is enabled for a record.
123
+ */
124
+ abstract getRecordFlag(
125
+ uniqueIdentifier: string,
126
+ flagName: RecordFlag
127
+ ): Observable<boolean>
109
128
  }
@@ -164,69 +164,49 @@ As such, **it is not very interesting at all.**`,
164
164
  extras: {
165
165
  isPublishedToAll: true,
166
166
  edit: true,
167
- featureTypes: [
168
- {
169
- attributeTable: [
170
- {
171
- code: 'OBJECTID',
172
- name: 'OBJECTID',
173
- link: '',
174
- definition: 'Object identifier',
175
- type: 'OID',
176
- },
177
- {
178
- code: 'NOM',
179
- name: 'Nom',
180
- link: '',
181
- definition: 'Nom de la rue',
182
- type: 'String (48)',
183
- values: [
184
- {
185
- code: 'Pomme',
186
- label: 'Les Pommiers',
187
- description: 'Sous les pommiers',
188
- },
189
- {
190
- code: 'Cotton',
191
- label: 'Rue Cotton',
192
- description: 'Rue Cotton',
193
- },
194
- { code: "Passage de l'échiquier" },
195
- { description: 'Rue du Charlieu' },
196
- ],
197
- },
198
- {
199
- code: 'RUE',
200
- name: 'Rue',
201
- link: '',
202
- definition: '',
203
- type: 'String (50)',
204
- },
205
- ],
206
- code: '',
207
- aliases: '',
208
- typeName: "Catalogue d'attributs N°1",
209
- definition: 'Définition du catalogue d attributs N°1',
210
- isAbstract: 'false',
211
- },
212
- {
213
- attributeTable: [
214
- {
215
- code: 'UniqueObject',
216
- name: 'unique object ',
217
- link: '',
218
- definition: 'this is the only object of this catalog',
219
- type: 'String (50)',
220
- },
221
- ],
222
- code: '',
223
- aliases: '',
224
- typeName: "Catalogue d'attributs N°2",
225
- definition: 'Définition du catalogue d attributs N°2',
226
- isAbstract: 'false',
227
- },
228
- ],
229
167
  },
168
+ featureTypeDescriptions: [
169
+ {
170
+ name: "Catalogue d'attributs N°1",
171
+ description: 'Définition du catalogue d attributs N°1',
172
+ attributes: [
173
+ {
174
+ name: 'OBJECTID',
175
+ description: 'Object identifier',
176
+ code: 'OBJECTID',
177
+ type: 'OID',
178
+ },
179
+ {
180
+ name: 'Nom',
181
+ description: 'Nom de la rue',
182
+ code: 'NOM',
183
+ type: 'String (48)',
184
+ values: [
185
+ { value: 'Pomme', label: 'Les Pommiers' },
186
+ { value: 'Cotton', label: 'Rue Cotton' },
187
+ { value: "Passage de l'échiquier" },
188
+ ],
189
+ },
190
+ {
191
+ name: 'Rue',
192
+ code: 'RUE',
193
+ type: 'String (50)',
194
+ },
195
+ ],
196
+ },
197
+ {
198
+ name: "Catalogue d'attributs N°2",
199
+ description: 'Définition du catalogue d attributs N°2',
200
+ attributes: [
201
+ {
202
+ name: 'unique object ',
203
+ description: 'this is the only object of this catalog',
204
+ code: 'UniqueObject',
205
+ type: 'String (50)',
206
+ },
207
+ ],
208
+ },
209
+ ],
230
210
  },
231
211
  {
232
212
  uniqueIdentifier: '7d002c4c-92ef-4b9f-a568-d732f740b99e',
@@ -209,7 +209,8 @@ export class DataService {
209
209
  ogcApiLink: DatasetServiceDistribution
210
210
  ): Promise<DatasetOnlineResource[]> {
211
211
  const collectionInfo = await this.getDownloadUrlsFromOgcApi(
212
- ogcApiLink.url.href
212
+ ogcApiLink.url.href,
213
+ ogcApiLink.name
213
214
  )
214
215
 
215
216
  return Object.keys(collectionInfo.bulkDownloadLinks).map((mimeType) => {
@@ -229,31 +230,41 @@ export class DataService {
229
230
  })
230
231
  }
231
232
 
232
- async getDownloadUrlsFromOgcApi(url: string): Promise<OgcApiCollectionInfo> {
233
+ private async getTargetCollectionId(
234
+ endpoint: OgcApiEndpoint,
235
+ collectionId?: string
236
+ ): Promise<string | undefined> {
237
+ const collections = await endpoint.featureCollections
238
+ return collections.length === 1 && !collectionId
239
+ ? collections[0]
240
+ : collectionId
241
+ }
242
+
243
+ async getDownloadUrlsFromOgcApi(
244
+ url: string,
245
+ collectionId?: string
246
+ ): Promise<OgcApiCollectionInfo> {
233
247
  const endpoint = new OgcApiEndpoint(url)
234
- return await endpoint.featureCollections
235
- .then((collections) => {
236
- return endpoint.getCollectionInfo(collections[0])
237
- })
238
- .catch((error) => {
239
- throw new Error(`ogc.unreachable.unknown`)
240
- })
248
+ try {
249
+ const id = await this.getTargetCollectionId(endpoint, collectionId)
250
+ return await endpoint.getCollectionInfo(id)
251
+ } catch {
252
+ throw new Error('ogc.unreachable.unknown')
253
+ }
241
254
  }
242
255
 
243
256
  async getItemsFromOgcApi(
244
257
  url: string,
258
+ collectionId?: string,
245
259
  limit?: number
246
260
  ): Promise<OgcApiRecord[]> {
247
261
  const endpoint = new OgcApiEndpoint(url)
248
- return await endpoint.featureCollections
249
- .then((collections) => {
250
- return collections.length
251
- ? endpoint.getCollectionItems(collections[0], limit)
252
- : null
253
- })
254
- .catch(() => {
255
- throw new Error(`ogc.unreachable.unknown`)
256
- })
262
+ try {
263
+ const id = await this.getTargetCollectionId(endpoint, collectionId)
264
+ return await endpoint.getCollectionItems(id, limit)
265
+ } catch {
266
+ throw new Error('ogc.unreachable.unknown')
267
+ }
257
268
  }
258
269
 
259
270
  async getItemsFromStacApi(
@@ -381,7 +392,9 @@ export class DataService {
381
392
  link.type === 'service' &&
382
393
  link.accessServiceProtocol === 'ogcFeatures'
383
394
  ) {
384
- return from(this.getDownloadUrlsFromOgcApi(link.url.href)).pipe(
395
+ return from(
396
+ this.getDownloadUrlsFromOgcApi(link.url.href, link.name)
397
+ ).pipe(
385
398
  switchMap((collectionInfo) => {
386
399
  const isMimeTypeJson = (mimeType: string): boolean => {
387
400
  return mimeType.toLowerCase().indexOf('json') > -1
@@ -9,10 +9,7 @@ import {
9
9
 
10
10
  import { SortableListComponent } from '../../../../../../../../../libs/ui/layout/src'
11
11
  import { ConstraintCardComponent } from '../../../constraint-card/constraint-card.component'
12
- import {
13
- CatalogRecordKeys,
14
- Constraint,
15
- } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
12
+ import { Constraint } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
16
13
  import { ButtonComponent } from '../../../../../../../../../libs/ui/inputs/src'
17
14
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
18
15
  import { TranslatePipe } from '@ngx-translate/core'
@@ -22,6 +19,7 @@ import {
22
19
  provideNgIconsConfig,
23
20
  } from '@ng-icons/core'
24
21
  import { iconoirPlus } from '@ng-icons/iconoir'
22
+ import { FormFieldModel } from '../../../../models'
25
23
 
26
24
  marker('editor.record.form.constraint.add.legalConstraints')
27
25
  marker('editor.record.form.constraint.add.securityConstraints')
@@ -53,7 +51,7 @@ marker('editor.record.form.constraint.header.otherConstraints')
53
51
  export class FormFieldConstraintsComponent implements OnInit {
54
52
  @Input() label: string
55
53
  @Input() value: Constraint[]
56
- @Input() constraintType: CatalogRecordKeys
54
+ @Input() constraintType: FormFieldModel
57
55
  @Output() valueChange = new EventEmitter<Constraint[]>()
58
56
 
59
57
  constraintsHeader = ''
@@ -36,7 +36,7 @@ import {
36
36
  } from '../../../../../../../../../libs/util/shared/src'
37
37
  import { map } from 'rxjs/operators'
38
38
  import { SortableListComponent } from '../../../../../../../../../libs/ui/layout/src'
39
- import { FieldModelSpecifier } from '../../../../models/editor-config.model'
39
+ import { FormFieldModelSpecifier } from '../../../../models/editor-config.model'
40
40
 
41
41
  @Component({
42
42
  selector: 'gn-ui-form-field-contacts',
@@ -59,7 +59,7 @@ export class FormFieldContactsComponent implements OnDestroy, OnChanges {
59
59
  private changeDetectorRef = inject(ChangeDetectorRef)
60
60
 
61
61
  @Input() value: Individual[]
62
- @Input() modelSpecifier: FieldModelSpecifier
62
+ @Input() modelSpecifier: FormFieldModelSpecifier
63
63
  @Output() valueChange: EventEmitter<Individual[]> = new EventEmitter()
64
64
 
65
65
  contacts: Individual[] = []
@@ -0,0 +1,18 @@
1
+ <div class="flex-1 flex justify-between items-center">
2
+ <gn-ui-check-toggle
3
+ [label]="labelKey() | translate"
4
+ [value]="initialValue$ | async"
5
+ (toggled)="onToggle($event)"
6
+ [attr.data-cy]="'record-flag-toggle-' + flagName()"
7
+ ></gn-ui-check-toggle>
8
+
9
+ @if (hintKey()) {
10
+ <ng-icon
11
+ name="matHelpOutline"
12
+ size="16"
13
+ class="m-2"
14
+ [matTooltip]="hintKey() | translate"
15
+ matTooltipPosition="above"
16
+ ></ng-icon>
17
+ }
18
+ </div>
@@ -0,0 +1,86 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ inject,
5
+ input,
6
+ } from '@angular/core'
7
+ import { AsyncPipe } from '@angular/common'
8
+ import { CheckToggleComponent } from '../../../../../../../../../libs/ui/inputs/src'
9
+ import { EditorFacade } from '../../../../+state/editor.facade'
10
+ import { TranslatePipe, TranslateService } from '@ngx-translate/core'
11
+ import { RecordFlag } from '../../../../../../../../../libs/common/domain/src/lib/model'
12
+ import { RecordsRepositoryInterface } from '../../../../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
13
+ import { toSignal } from '@angular/core/rxjs-interop'
14
+ import { filter } from 'rxjs'
15
+ import { NgIcon, provideIcons } from '@ng-icons/core'
16
+ import { MatTooltip } from '@angular/material/tooltip'
17
+ import { map, switchMap } from 'rxjs/operators'
18
+ import { matHelpOutline } from '@ng-icons/material-icons/outline'
19
+ import { NotificationsService } from '../../../../../../../../../libs/feature/notifications/src'
20
+
21
+ @Component({
22
+ selector: 'gn-ui-form-field-record-flag',
23
+ standalone: true,
24
+ imports: [AsyncPipe, CheckToggleComponent, TranslatePipe, NgIcon, MatTooltip],
25
+ viewProviders: [
26
+ provideIcons({
27
+ matHelpOutline,
28
+ }),
29
+ ],
30
+ templateUrl: './form-field-record-flag-component.html',
31
+ styleUrls: ['./form-field-record-flag-component.css'],
32
+ changeDetection: ChangeDetectionStrategy.OnPush,
33
+ })
34
+ export class FormFieldRecordFlagComponent {
35
+ flagName = input<RecordFlag>()
36
+ labelKey = input<string>()
37
+ hintKey = input<string>()
38
+
39
+ private editorFacade = inject(EditorFacade)
40
+ private repository = inject(RecordsRepositoryInterface)
41
+ private notificationsService = inject(NotificationsService)
42
+ private translateService = inject(TranslateService)
43
+
44
+ private record = toSignal(this.editorFacade.record$)
45
+
46
+ recordKind = toSignal(
47
+ this.editorFacade.record$.pipe(map((record) => record.kind))
48
+ )
49
+ initialValue$ = this.editorFacade.record$.pipe(
50
+ filter((record) => !!record),
51
+ switchMap((record) =>
52
+ this.repository.getRecordFlag(record.uniqueIdentifier, this.flagName())
53
+ )
54
+ )
55
+
56
+ onToggle(enabled: boolean) {
57
+ if (this.record() === null) {
58
+ return
59
+ }
60
+ this.repository
61
+ .setRecordFlag(this.record().uniqueIdentifier, this.flagName(), enabled)
62
+ .subscribe({
63
+ next: () => {
64
+ // do nothing
65
+ },
66
+ error: (error) => {
67
+ this.notificationsService.showNotification(
68
+ {
69
+ type: 'error',
70
+ title: this.translateService.instant(
71
+ 'editor.record.flag.saveError.title'
72
+ ),
73
+ text: `${this.translateService.instant(
74
+ 'editor.record.flag.saveError.body',
75
+ {
76
+ recordKind: this.recordKind(),
77
+ }
78
+ )} ${error.message}`,
79
+ },
80
+ undefined,
81
+ error
82
+ )
83
+ },
84
+ })
85
+ }
86
+ }