geonetwork-ui 2.4.0-dev.a1bcfe22 → 2.4.0-dev.a9a61288

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 (128) hide show
  1. package/esm2022/libs/api/metadata-converter/src/index.mjs +1 -2
  2. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +5 -5
  3. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +30 -2
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.mjs +31 -0
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +23 -1
  6. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +6 -1
  7. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +21 -4
  8. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  9. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  10. package/esm2022/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.mjs +138 -0
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.mjs +21 -0
  12. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +19 -9
  13. package/esm2022/libs/feature/editor/src/lib/components/record-form/record-form.component.mjs +2 -1
  14. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +12 -2
  15. package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +10 -5
  16. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +35 -7
  17. package/esm2022/libs/feature/search/src/lib/state/search.facade.mjs +6 -2
  18. package/esm2022/libs/ui/elements/src/index.mjs +2 -1
  19. package/esm2022/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.mjs +27 -0
  20. package/esm2022/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.mjs +4 -3
  21. package/esm2022/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.mjs +2 -2
  22. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +3 -3
  23. package/esm2022/libs/ui/inputs/src/lib/image-input/image-input.component.mjs +11 -5
  24. package/esm2022/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.mjs +3 -3
  25. package/esm2022/libs/ui/layout/src/lib/interactive-table/interactive-table.component.mjs +3 -3
  26. package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +49 -11
  27. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +18 -6
  28. package/esm2022/translations/de.json +17 -17
  29. package/esm2022/translations/en.json +10 -10
  30. package/esm2022/translations/es.json +9 -9
  31. package/esm2022/translations/fr.json +19 -19
  32. package/esm2022/translations/it.json +10 -10
  33. package/esm2022/translations/nl.json +9 -9
  34. package/esm2022/translations/pt.json +9 -9
  35. package/fesm2022/geonetwork-ui.mjs +620 -250
  36. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  37. package/libs/api/metadata-converter/src/index.d.ts +0 -1
  38. package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
  39. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -1
  40. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +8 -1
  41. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  42. package/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.d.ts +5 -0
  43. package/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.d.ts.map +1 -0
  44. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +3 -1
  45. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  46. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts +1 -0
  47. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts.map +1 -1
  48. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +6 -1
  49. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  50. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +2 -1
  51. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  52. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +8 -0
  53. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  54. package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts +27 -0
  55. package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts.map +1 -0
  56. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts +11 -0
  57. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts.map +1 -0
  58. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +5 -1
  59. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  60. package/libs/feature/editor/src/lib/components/record-form/record-form.component.d.ts.map +1 -1
  61. package/libs/feature/editor/src/lib/fields.config.d.ts +1 -0
  62. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  63. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
  64. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +11 -3
  65. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
  66. package/libs/feature/search/src/lib/state/search.facade.d.ts +1 -0
  67. package/libs/feature/search/src/lib/state/search.facade.d.ts.map +1 -1
  68. package/libs/ui/elements/src/index.d.ts +1 -0
  69. package/libs/ui/elements/src/index.d.ts.map +1 -1
  70. package/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.d.ts +18 -0
  71. package/libs/ui/elements/src/lib/confirmation-dialog/confirmation-dialog.component.d.ts.map +1 -0
  72. package/libs/ui/elements/src/lib/downloads-list/downloads-list.component.d.ts +1 -1
  73. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts +1 -1
  74. package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts +4 -2
  75. package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts.map +1 -1
  76. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +10 -1
  77. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
  78. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +6 -2
  79. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  80. package/package.json +1 -1
  81. package/src/libs/api/metadata-converter/src/index.ts +0 -1
  82. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +5 -1
  83. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +37 -12
  84. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +5 -1
  85. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +4 -2
  86. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +72 -2
  87. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.ts +39 -0
  88. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +70 -1
  89. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +8 -0
  90. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +24 -4
  91. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +2 -1
  92. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +10 -0
  93. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.html +3 -1
  94. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.ts +117 -21
  95. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.css +0 -0
  96. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.html +5 -0
  97. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +22 -0
  98. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +6 -0
  99. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +13 -1
  100. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +1 -0
  101. package/src/libs/feature/editor/src/lib/fields.config.ts +12 -1
  102. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +8 -4
  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 +40 -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/inputs/src/lib/image-input/image-input.component.html +1 -1
  114. package/src/libs/ui/inputs/src/lib/image-input/image-input.component.ts +7 -2
  115. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +1 -1
  116. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -0
  117. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +10 -1
  118. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +55 -3
  119. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +7 -2
  120. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +9 -9
  121. package/translations/de.json +17 -17
  122. package/translations/en.json +10 -10
  123. package/translations/es.json +9 -9
  124. package/translations/fr.json +19 -19
  125. package/translations/it.json +10 -10
  126. package/translations/nl.json +9 -9
  127. package/translations/pt.json +9 -9
  128. package/translations/sk.json +10 -10
@@ -1,8 +1,10 @@
1
1
  <gn-ui-image-input
2
2
  [maxSizeMB]="5"
3
3
  [previewUrl]="resourceUrl"
4
- [altText]="resourceFileName"
4
+ [altText]="resourceAltText"
5
+ [formControl]="formControl"
5
6
  (fileChange)="handleFileChange($event)"
6
7
  (urlChange)="handleUrlChange($event)"
8
+ (altTextChange)="handleAltTextChange($event)"
7
9
  (delete)="handleDelete()"
8
10
  ></gn-ui-image-input>
@@ -2,12 +2,24 @@ import {
2
2
  ChangeDetectionStrategy,
3
3
  ChangeDetectorRef,
4
4
  Component,
5
+ EventEmitter,
5
6
  Input,
7
+ OnChanges,
6
8
  OnInit,
9
+ Output,
10
+ SimpleChanges,
7
11
  } from '@angular/core'
8
12
  import { CommonModule } from '@angular/common'
9
13
  import { RecordsApiService } from '../../../../../../../libs/data-access/gn4/src'
10
14
  import { UiInputsModule } from '../../../../../../../libs/ui/inputs/src'
15
+ import { FormControl } from '@angular/forms'
16
+ import { GraphicOverview } from '../../../../../../../libs/common/domain/src/lib/model/record'
17
+
18
+ const extractFileNameFromUrl = (url: string): string => {
19
+ const pattern = new RegExp(`attachments/([^/?#]+)(?:[/?#]|$)`, 'i')
20
+ const match = url.match(pattern)
21
+ return match ? match[1] : ''
22
+ }
11
23
 
12
24
  @Component({
13
25
  selector: 'gn-ui-overview-upload',
@@ -17,11 +29,15 @@ import { UiInputsModule } from '../../../../../../../libs/ui/inputs/src'
17
29
  styleUrls: ['./overview-upload.component.css'],
18
30
  changeDetection: ChangeDetectionStrategy.OnPush,
19
31
  })
20
- export class OverviewUploadComponent implements OnInit {
32
+ export class OverviewUploadComponent implements OnInit, OnChanges {
21
33
  @Input() metadataUuid: string
34
+ @Input() formControl!: FormControl
35
+ @Output() overviewChange = new EventEmitter<GraphicOverview | null>()
36
+ @Output() altTextChange: EventEmitter<string> = new EventEmitter()
22
37
 
23
- resourceFileName: string
24
- resourceUrl: string
38
+ resourceAltText = '' // = ressourceFileName by default
39
+ resourceFileName = ''
40
+ resourceUrl: URL
25
41
 
26
42
  constructor(
27
43
  private recordsApiService: RecordsApiService,
@@ -29,42 +45,122 @@ export class OverviewUploadComponent implements OnInit {
29
45
  ) {}
30
46
 
31
47
  ngOnInit(): void {
32
- this.recordsApiService
33
- .getAllResources(this.metadataUuid)
34
- .subscribe((resources) => {
35
- this.resourceFileName = resources[0]?.filename
36
- this.resourceUrl = resources[0]?.url
48
+ this.recordsApiService.getAllResources(this.metadataUuid).subscribe({
49
+ next: (resources) => {
50
+ if (resources && resources.length > 0) {
51
+ this.resourceUrl = new URL(resources[0]?.url)
52
+ this.resourceAltText =
53
+ this.resourceAltText === ''
54
+ ? resources[0].filename
55
+ : this.resourceAltText
56
+ this.resourceFileName = extractFileNameFromUrl(resources[0]?.url)
57
+ } else {
58
+ this.resourceUrl = null
59
+ this.resourceAltText = ''
60
+ this.resourceFileName = ''
61
+ }
62
+
37
63
  this.cd.markForCheck()
38
- })
64
+ },
65
+ error: this.errorHandle,
66
+ })
39
67
  }
40
68
 
41
69
  handleFileChange(file: File) {
42
70
  this.recordsApiService
43
71
  .putResource(this.metadataUuid, file, 'public')
44
- .subscribe((resource) => {
45
- this.resourceFileName = resource.filename
46
- this.resourceUrl = resource.url
47
- this.cd.markForCheck()
72
+ .subscribe({
73
+ next: (resource) => {
74
+ this.resourceUrl = new URL(resource.url)
75
+ this.resourceAltText = resource.filename
76
+
77
+ this.overviewChange.emit({
78
+ url: new URL(resource.url),
79
+ description: resource.filename,
80
+ })
81
+
82
+ this.cd.markForCheck()
83
+ },
84
+ error: this.errorHandle,
48
85
  })
49
86
  }
50
87
 
51
88
  handleUrlChange(url: string) {
52
89
  this.recordsApiService
53
90
  .putResourceFromURL(this.metadataUuid, url, 'public')
54
- .subscribe((resource) => {
55
- this.resourceFileName = resource.filename
56
- this.resourceUrl = resource.url
57
- this.cd.markForCheck()
91
+ .subscribe({
92
+ next: (resource) => {
93
+ this.resourceUrl = new URL(resource.url)
94
+ this.resourceAltText = resource.filename
95
+
96
+ this.overviewChange.emit({
97
+ url: new URL(resource.url),
98
+ description: resource.filename,
99
+ })
100
+
101
+ this.cd.markForCheck()
102
+ },
103
+ error: this.errorHandle,
58
104
  })
59
105
  }
60
106
 
107
+ handleAltTextChange(newAltText: string) {
108
+ this.resourceAltText = newAltText
109
+
110
+ this.overviewChange.emit({
111
+ url: this.resourceUrl,
112
+ description: this.resourceAltText,
113
+ })
114
+ this.cd.markForCheck()
115
+ }
116
+
61
117
  handleDelete() {
62
118
  this.recordsApiService
63
119
  .delResource(this.metadataUuid, this.resourceFileName)
64
- .subscribe(() => {
65
- this.resourceFileName = null
66
- this.resourceUrl = null
67
- this.cd.markForCheck()
120
+ .subscribe({
121
+ next: () => {
122
+ this.resourceAltText = null
123
+ this.resourceUrl = null
124
+
125
+ this.overviewChange.emit(null)
126
+
127
+ this.cd.markForCheck()
128
+ },
129
+ error: this.errorHandle,
68
130
  })
69
131
  }
132
+
133
+ private errorHandle = (error: never) => {
134
+ console.error(error)
135
+
136
+ this.resourceUrl = null
137
+ this.resourceAltText = ''
138
+ this.resourceFileName = ''
139
+
140
+ this.overviewChange.emit(null)
141
+
142
+ this.cd.markForCheck()
143
+ }
144
+
145
+ ngOnChanges(changes: SimpleChanges): void {
146
+ const overviewChanges = changes['formControl']
147
+ if (
148
+ overviewChanges &&
149
+ overviewChanges.currentValue !== overviewChanges.previousValue
150
+ ) {
151
+ let overview: GraphicOverview
152
+ if (
153
+ overviewChanges.currentValue.value &&
154
+ overviewChanges.currentValue.value.length > 0
155
+ ) {
156
+ overview = overviewChanges.currentValue.value[0] as GraphicOverview
157
+ } else {
158
+ return
159
+ }
160
+ if (overview.description && overview.description !== '') {
161
+ this.resourceAltText = overview.description
162
+ this.cd.markForCheck()
163
+ }
164
+ }
165
+ }
70
166
  }
@@ -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
+ }
@@ -76,6 +76,12 @@
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"
@@ -28,6 +28,9 @@ 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'
32
35
 
33
36
  @Component({
@@ -55,6 +58,7 @@ import { FormFieldConfig } from '../../../models'
55
58
  FormFieldArrayComponent,
56
59
  FormFieldKeywordsComponent,
57
60
  TranslateModule,
61
+ FormFieldOverviewsComponent,
58
62
  ],
59
63
  })
60
64
  export class FormFieldComponent {
@@ -70,9 +74,14 @@ export class FormFieldComponent {
70
74
 
71
75
  @ViewChild('titleInput') titleInput: ElementRef
72
76
 
77
+ metadataUuid$ = this.facade.record$.pipe(
78
+ take(1),
79
+ map((record) => record.uniqueIdentifier)
80
+ )
81
+
73
82
  formControl = new FormControl()
74
83
 
75
- constructor() {
84
+ constructor(private facade: EditorFacade) {
76
85
  this.valueChange = this.formControl.valueChanges
77
86
  }
78
87
 
@@ -101,6 +110,9 @@ export class FormFieldComponent {
101
110
  get isSpatialExtentField() {
102
111
  return this.model === 'spatialExtents'
103
112
  }
113
+ get isGraphicOverview() {
114
+ return this.model === 'overviews'
115
+ }
104
116
  get isSimpleField() {
105
117
  return this.model === 'uniqueIdentifier' || this.model === 'recordUpdated'
106
118
  }
@@ -24,6 +24,7 @@ export class RecordFormComponent {
24
24
  if (!model) {
25
25
  return
26
26
  }
27
+ console.log(newValue)
27
28
  this.facade.updateRecordField(model, newValue)
28
29
  }
29
30
 
@@ -83,6 +83,13 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
83
83
  },
84
84
  }
85
85
 
86
+ export const RECORD_GRAPHICAL_OVERVIEW_FIELD: EditorField = {
87
+ model: 'overviews',
88
+ formFieldConfig: {
89
+ labelKey: marker('editor.record.form.field.overviews'),
90
+ },
91
+ }
92
+
86
93
  /************************************************************
87
94
  *************** SECTIONS *****************
88
95
  ************************************************************
@@ -90,7 +97,11 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
90
97
 
91
98
  export const TITLE_SECTION: EditorSection = {
92
99
  hidden: false,
93
- fields: [RECORD_TITLE_FIELD, RECORD_ABSTRACT_FIELD],
100
+ fields: [
101
+ RECORD_TITLE_FIELD,
102
+ RECORD_ABSTRACT_FIELD,
103
+ RECORD_GRAPHICAL_OVERVIEW_FIELD,
104
+ ],
94
105
  }
95
106
 
96
107
  export const ABOUT_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,11 +220,15 @@ export class MapUtilsService {
220
220
  if (!('spatialExtents' in record) || record.spatialExtents.length === 0) {
221
221
  return null
222
222
  }
223
- // transform an array of geojson geometries into a bbox
223
+ // extend all the spatial extents into an including bbox
224
224
  const totalExtent = record.spatialExtents.reduce(
225
225
  (prev, curr) => {
226
- const geom = GEOJSON.readGeometry(curr.geometry)
227
- return extend(prev, geom.getExtent())
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
228
232
  },
229
233
  [Infinity, Infinity, -Infinity, -Infinity]
230
234
  )
@@ -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,32 @@ 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
+ },
58
+ error: (error) => {
59
+ this.notificationsService.showNotification({
60
+ type: 'error',
61
+ title: this.translateService.instant(
62
+ 'editor.record.deleteError.title'
63
+ ),
64
+ text: `${this.translateService.instant(
65
+ 'editor.record.deleteError.body'
66
+ )} ${error}`,
67
+ closeMessage: this.translateService.instant(
68
+ 'editor.record.deleteError.closeMessage'
69
+ ),
70
+ })
71
+ },
72
+ })
73
+ )
74
+ }
75
+
43
76
  handleSortByChange(col: string, order: 'asc' | 'desc') {
44
77
  this.searchService.setSortBy([order, col])
45
78
  }
@@ -51,4 +84,8 @@ export class ResultsTableContainerComponent {
51
84
  this.selectionService.selectRecords(records)
52
85
  }
53
86
  }
87
+
88
+ ngOnDestroy() {
89
+ this.subscription.unsubscribe()
90
+ }
54
91
  }
@@ -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>
@@ -0,0 +1,37 @@
1
+ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'
2
+ import {
3
+ MAT_DIALOG_DATA,
4
+ MatDialogModule,
5
+ MatDialogRef,
6
+ } from '@angular/material/dialog'
7
+ import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
8
+
9
+ export interface ConfirmationDialogData {
10
+ title: string
11
+ message: string
12
+ confirmText: string
13
+ cancelText: string
14
+ }
15
+
16
+ @Component({
17
+ selector: 'gn-ui-confirmation-dialog',
18
+ templateUrl: './confirmation-dialog.component.html',
19
+ styleUrls: ['./confirmation-dialog.component.css'],
20
+ changeDetection: ChangeDetectionStrategy.OnPush,
21
+ standalone: true,
22
+ imports: [MatDialogModule, ButtonComponent],
23
+ })
24
+ export class ConfirmationDialogComponent {
25
+ constructor(
26
+ public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
27
+ @Inject(MAT_DIALOG_DATA) public data: ConfirmationDialogData
28
+ ) {}
29
+
30
+ onConfirm() {
31
+ this.dialogRef.close(true)
32
+ }
33
+
34
+ onCancel() {
35
+ this.dialogRef.close(false)
36
+ }
37
+ }
@@ -1,5 +1,8 @@
1
1
  <div class="h-full flex flex-col">
2
- <p class="flex-none mb-2 font-medium text-sm text-gray-900">
2
+ <p
3
+ *ngIf="helperText"
4
+ class="flex-none mb-2 font-medium text-sm text-gray-900"
5
+ >
3
6
  {{ helperText }}
4
7
  </p>
5
8
  <div class="flex-1" [hidden]="preview">
@@ -2,9 +2,10 @@
2
2
  :host ::ng-deep .markdown-body {
3
3
  -ms-text-size-adjust: 100%;
4
4
  -webkit-text-size-adjust: 100%;
5
- margin: 0px 0px 1.5rem 0px;
5
+ margin: 0;
6
6
  line-height: 1.5;
7
7
  word-wrap: break-word;
8
+ height: 100%;
8
9
  }
9
10
 
10
11
  /** Emphasis **/
@@ -1,7 +1,7 @@
1
1
  <div class="mb-6 md-description sm:mb-4 sm:pr-16">
2
2
  <gn-ui-content-ghost ghostClass="h-32" [showContent]="fieldReady('abstract')">
3
3
  <gn-ui-max-lines [maxLines]="6" *ngIf="metadata.abstract">
4
- <div>
4
+ <div class="mb-6">
5
5
  <gn-ui-markdown-parser
6
6
  [textContent]="metadata.abstract"
7
7
  ></gn-ui-markdown-parser>
@@ -47,19 +47,23 @@
47
47
  </ng-template>
48
48
  </ng-container>
49
49
  <ng-container *ngIf="legalConstraints.length">
50
- <gn-ui-markdown-parser
51
- *ngFor="let constraint of legalConstraints"
52
- [textContent]="constraint"
53
- >
54
- </gn-ui-markdown-parser>
50
+ <div class="mb-6">
51
+ <gn-ui-markdown-parser
52
+ *ngFor="let constraint of legalConstraints"
53
+ [textContent]="constraint"
54
+ >
55
+ </gn-ui-markdown-parser>
56
+ </div>
55
57
  </ng-container>
56
58
  <ng-container *ngIf="otherConstraints.length">
57
59
  <div gnUiLinkify *ngFor="let constraint of otherConstraints">
58
60
  <h5 translate class="font-medium text-black text-sm mb-[2px] mt-[16px]">
59
61
  record.metadata.otherConstraints
60
62
  </h5>
61
- <gn-ui-markdown-parser [textContent]="constraint">
62
- </gn-ui-markdown-parser>
63
+ <div class="mb-6">
64
+ <gn-ui-markdown-parser [textContent]="constraint">
65
+ </gn-ui-markdown-parser>
66
+ </div>
63
67
  </div>
64
68
  </ng-container>
65
69
 
@@ -51,7 +51,7 @@
51
51
  <div class="w-full h-full flex flex-col gap-2">
52
52
  <label
53
53
  gnUiFilesDrop
54
- class="block flex-1 border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center gap-4"
54
+ class="block flex-1 border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center gap-4 hover:cursor-pointer"
55
55
  (dragFilesOver)="handleDragFilesOver($event)"
56
56
  (dropFiles)="handleDropFiles($event)"
57
57
  >
@@ -16,6 +16,7 @@ import { ButtonComponent } from '../button/button.component'
16
16
  import { FilesDropDirective } from '../files-drop/files-drop.directive'
17
17
  import { TranslateModule } from '@ngx-translate/core'
18
18
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
19
+ import { FormControl, ReactiveFormsModule } from '@angular/forms'
19
20
 
20
21
  @Component({
21
22
  selector: 'gn-ui-image-input',
@@ -30,11 +31,13 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
30
31
  FilesDropDirective,
31
32
  MatProgressSpinnerModule,
32
33
  TranslateModule,
34
+ ReactiveFormsModule,
33
35
  ],
34
36
  })
35
37
  export class ImageInputComponent {
38
+ @Input() formControl!: FormControl
36
39
  @Input() maxSizeMB: number
37
- @Input() previewUrl?: string
40
+ @Input() previewUrl?: URL
38
41
  @Input() altText?: string
39
42
  @Input() uploadProgress?: number
40
43
  @Input() uploadError?: boolean
@@ -127,7 +130,8 @@ export class ImageInputComponent {
127
130
  const file = new File([blob], name)
128
131
  this.fileChange.emit(file)
129
132
  },
130
- error: () => {
133
+ error: (error) => {
134
+ console.error(error)
131
135
  this.downloadError = true
132
136
  this.cd.markForCheck()
133
137
  this.urlChange.emit(this.urlInputValue)
@@ -165,6 +169,7 @@ export class ImageInputComponent {
165
169
  }
166
170
 
167
171
  handleDelete() {
172
+ this.formControl.markAsDirty()
168
173
  this.delete.emit()
169
174
  }
170
175
 
@@ -12,7 +12,7 @@
12
12
  </span>
13
13
  </div>
14
14
  </div>
15
- <div class="flex-1">
15
+ <div class="flex-1 overflow-y-auto">
16
16
  <ng-content></ng-content>
17
17
  </div>
18
18
  </div>
@@ -30,6 +30,7 @@
30
30
  class="contents text-gray-900 cursor-pointer group"
31
31
  *ngFor="let item of items"
32
32
  (click)="handleRowClick(item)"
33
+ data-cy="table-row"
33
34
  >
34
35
  <div
35
36
  class="relative h-0"