geonetwork-ui 2.2.0-dev.723017a4 → 2.2.0-dev.751c5530

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 (156) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +16 -4
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +3 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +7 -2
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +4 -1
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +1 -1
  7. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +2 -2
  8. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  9. package/esm2022/libs/feature/editor/src/index.mjs +6 -1
  10. package/esm2022/libs/feature/editor/src/lib/+state/editor.actions.mjs +8 -0
  11. package/esm2022/libs/feature/editor/src/lib/+state/editor.effects.mjs +26 -0
  12. package/esm2022/libs/feature/editor/src/lib/+state/editor.facade.mjs +30 -0
  13. package/esm2022/libs/feature/editor/src/lib/+state/editor.models.mjs +2 -0
  14. package/esm2022/libs/feature/editor/src/lib/+state/editor.reducer.mjs +42 -0
  15. package/esm2022/libs/feature/editor/src/lib/+state/editor.selectors.mjs +13 -0
  16. package/esm2022/libs/feature/editor/src/lib/expressions.mjs +13 -0
  17. package/esm2022/libs/feature/editor/src/lib/feature-editor.module.mjs +16 -4
  18. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +34 -0
  19. package/esm2022/libs/feature/editor/src/lib/models/fields.model.mjs +2 -0
  20. package/esm2022/libs/feature/editor/src/lib/record-form/record-form.component.mjs +15 -11
  21. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +22 -44
  22. package/esm2022/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.mjs +13 -13
  23. package/esm2022/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.mjs +3 -3
  24. package/esm2022/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.mjs +3 -3
  25. package/esm2022/libs/ui/elements/src/lib/max-lines/max-lines.component.mjs +5 -3
  26. package/esm2022/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.mjs +3 -3
  27. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +17 -5
  28. package/esm2022/libs/ui/elements/src/lib/thumbnail/thumbnail.component.mjs +3 -3
  29. package/esm2022/libs/ui/inputs/src/lib/button/button.component.mjs +9 -9
  30. package/esm2022/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.mjs +3 -3
  31. package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +3 -3
  32. package/esm2022/libs/ui/inputs/src/lib/form-field/form-field.component.mjs +4 -2
  33. package/esm2022/libs/ui/inputs/src/lib/form-field/form-field.model.mjs +1 -1
  34. package/esm2022/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.mjs +3 -3
  35. package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
  36. package/esm2022/libs/util/i18n/src/lib/i18n.constants.mjs +18 -1
  37. package/esm2022/libs/util/shared/src/lib/utils/index.mjs +2 -1
  38. package/esm2022/libs/util/shared/src/lib/utils/temporal-extent-union.mjs +32 -0
  39. package/esm2022/translations/de.json +35 -26
  40. package/esm2022/translations/en.json +27 -18
  41. package/esm2022/translations/es.json +24 -15
  42. package/esm2022/translations/fr.json +45 -36
  43. package/esm2022/translations/it.json +39 -30
  44. package/esm2022/translations/nl.json +25 -16
  45. package/esm2022/translations/pt.json +24 -15
  46. package/fesm2022/geonetwork-ui.mjs +581 -300
  47. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  48. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  49. package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +1 -1
  50. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +1 -0
  51. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
  52. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +1 -1
  53. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +1 -0
  54. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  55. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  56. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  57. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +3 -0
  58. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  59. package/libs/feature/editor/src/index.d.ts +5 -0
  60. package/libs/feature/editor/src/index.d.ts.map +1 -1
  61. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts +23 -0
  62. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts.map +1 -0
  63. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts +15 -0
  64. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts.map +1 -0
  65. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts +19 -0
  66. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts.map +1 -0
  67. package/libs/feature/editor/src/lib/+state/editor.models.d.ts +2 -0
  68. package/libs/feature/editor/src/lib/+state/editor.models.d.ts.map +1 -0
  69. package/libs/feature/editor/src/lib/+state/editor.reducer.d.ts +18 -0
  70. package/libs/feature/editor/src/lib/+state/editor.reducer.d.ts.map +1 -0
  71. package/libs/feature/editor/src/lib/+state/editor.selectors.d.ts +15 -0
  72. package/libs/feature/editor/src/lib/+state/editor.selectors.d.ts.map +1 -0
  73. package/libs/feature/editor/src/lib/expressions.d.ts +4 -0
  74. package/libs/feature/editor/src/lib/expressions.d.ts.map +1 -0
  75. package/libs/feature/editor/src/lib/feature-editor.module.d.ts +3 -1
  76. package/libs/feature/editor/src/lib/feature-editor.module.d.ts.map +1 -1
  77. package/libs/feature/editor/src/lib/fields.config.d.ts +3 -0
  78. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -0
  79. package/libs/feature/editor/src/lib/models/fields.model.d.ts +15 -0
  80. package/libs/feature/editor/src/lib/models/fields.model.d.ts.map +1 -0
  81. package/libs/feature/editor/src/lib/record-form/record-form.component.d.ts +10 -5
  82. package/libs/feature/editor/src/lib/record-form/record-form.component.d.ts.map +1 -1
  83. package/libs/feature/editor/src/lib/services/editor.service.d.ts +3 -13
  84. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  85. package/libs/ui/elements/src/lib/max-lines/max-lines.component.d.ts.map +1 -1
  86. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +6 -0
  87. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
  88. package/libs/ui/inputs/src/lib/button/button.component.d.ts.map +1 -1
  89. package/libs/ui/inputs/src/lib/form-field/form-field.component.d.ts.map +1 -1
  90. package/libs/ui/inputs/src/lib/form-field/form-field.model.d.ts +0 -1
  91. package/libs/ui/inputs/src/lib/form-field/form-field.model.d.ts.map +1 -1
  92. package/libs/util/i18n/src/lib/i18n.constants.d.ts +17 -0
  93. package/libs/util/i18n/src/lib/i18n.constants.d.ts.map +1 -1
  94. package/libs/util/shared/src/lib/utils/index.d.ts +1 -0
  95. package/libs/util/shared/src/lib/utils/index.d.ts.map +1 -1
  96. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts +5 -0
  97. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts.map +1 -0
  98. package/package.json +1 -1
  99. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +2 -0
  100. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +2 -0
  101. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +4 -0
  102. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +19 -3
  103. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.ts +2 -0
  104. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  105. package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +6 -0
  106. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +5 -1
  107. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +8 -2
  108. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +1 -1
  109. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -0
  110. package/src/libs/common/fixtures/src/lib/elasticsearch/full-response.ts +1 -1
  111. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +33 -11
  112. package/src/libs/feature/editor/src/index.ts +5 -0
  113. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +24 -0
  114. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +49 -0
  115. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +30 -0
  116. package/src/libs/feature/editor/src/lib/+state/editor.models.ts +1 -0
  117. package/src/libs/feature/editor/src/lib/+state/editor.reducer.ts +68 -0
  118. package/src/libs/feature/editor/src/lib/+state/editor.selectors.ts +39 -0
  119. package/src/libs/feature/editor/src/lib/expressions.ts +16 -0
  120. package/src/libs/feature/editor/src/lib/feature-editor.module.ts +11 -0
  121. package/src/libs/feature/editor/src/lib/fields.config.ts +35 -0
  122. package/src/libs/feature/editor/src/lib/models/fields.model.ts +29 -0
  123. package/src/libs/feature/editor/src/lib/record-form/record-form.component.html +9 -7
  124. package/src/libs/feature/editor/src/lib/record-form/record-form.component.ts +11 -5
  125. package/src/libs/feature/editor/src/lib/services/editor.service.ts +34 -73
  126. package/src/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts +12 -12
  127. package/src/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.html +3 -4
  128. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.html +1 -1
  129. package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.html +5 -1
  130. package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.ts +1 -0
  131. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.html +1 -1
  132. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +108 -20
  133. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +14 -0
  134. package/src/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html +2 -2
  135. package/src/libs/ui/inputs/src/lib/button/button.component.css +0 -5
  136. package/src/libs/ui/inputs/src/lib/button/button.component.html +0 -1
  137. package/src/libs/ui/inputs/src/lib/button/button.component.ts +6 -6
  138. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  139. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +3 -1
  140. package/src/libs/ui/inputs/src/lib/form-field/form-field.component.ts +3 -1
  141. package/src/libs/ui/inputs/src/lib/form-field/form-field.model.ts +0 -1
  142. package/src/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.css +3 -0
  143. package/src/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.html +1 -1
  144. package/src/libs/ui/layout/src/lib/carousel/carousel.component.html +1 -0
  145. package/src/libs/util/i18n/src/lib/i18n.constants.ts +18 -0
  146. package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
  147. package/src/libs/util/shared/src/lib/utils/temporal-extent-union.ts +32 -0
  148. package/tailwind.base.css +44 -15
  149. package/translations/de.json +35 -26
  150. package/translations/en.json +27 -18
  151. package/translations/es.json +24 -15
  152. package/translations/fr.json +45 -36
  153. package/translations/it.json +39 -30
  154. package/translations/nl.json +25 -16
  155. package/translations/pt.json +24 -15
  156. package/translations/sk.json +117 -108
@@ -1,7 +1,8 @@
1
1
  import { CommonModule } from '@angular/common'
2
2
  import { ChangeDetectionStrategy, Component } from '@angular/core'
3
- import { EditorService, FormField } from '../services/editor.service'
4
3
  import { UiInputsModule } from '../../../../../../libs/ui/inputs/src'
4
+ import { EditorFacade } from '../+state/editor.facade'
5
+ import { EditorFieldState, EditorFieldValue } from '../models/fields.model'
5
6
 
6
7
  @Component({
7
8
  selector: 'gn-ui-record-form',
@@ -12,13 +13,18 @@ import { UiInputsModule } from '../../../../../../libs/ui/inputs/src'
12
13
  imports: [CommonModule, UiInputsModule],
13
14
  })
14
15
  export class RecordFormComponent {
15
- constructor(public editorService: EditorService) {}
16
+ fields$ = this.facade.recordFields$
16
17
 
17
- handleFieldValueChange(fieldName: string, value: unknown) {
18
- this.editorService.updateRecordField(fieldName, value)
18
+ constructor(public facade: EditorFacade) {}
19
+
20
+ handleFieldValueChange(field: EditorFieldState, newValue: EditorFieldValue) {
21
+ if (!field.config.model) {
22
+ return
23
+ }
24
+ this.facade.updateRecordField(field.config.model, newValue)
19
25
  }
20
26
 
21
- fieldTracker(index: number, field: FormField) {
27
+ fieldTracker(index: number, field: EditorFieldState) {
22
28
  return field.config.model
23
29
  }
24
30
  }
@@ -1,59 +1,27 @@
1
1
  import { Inject, Injectable, Optional } from '@angular/core'
2
2
  import { toModel, toXml } from '../../../../../../libs/api/metadata-converter/src'
3
3
  import { Configuration } from '../../../../../../libs/data-access/gn4/src'
4
- import { BehaviorSubject, Observable } from 'rxjs'
5
- import { finalize, map, switchMap, take, tap } from 'rxjs/operators'
4
+ import { Observable } from 'rxjs'
5
+ import { map } from 'rxjs/operators'
6
6
  import { HttpClient } from '@angular/common/http'
7
- import { FormFieldConfig } from '../../../../../../libs/ui/inputs/src'
8
7
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
9
-
10
- export interface FormField {
11
- config: FormFieldConfig
12
- value: string | number | boolean | unknown
13
- }
8
+ import { EditorFieldsConfig } from '../models/fields.model'
9
+ import { evaluate } from '../expressions'
14
10
 
15
11
  @Injectable({
16
12
  providedIn: 'root',
17
13
  })
18
14
  export class EditorService {
19
- private record$ = new BehaviorSubject<CatalogRecord | null>(null)
20
- private fieldsConfig: FormFieldConfig[] = [
21
- {
22
- model: 'title',
23
- labelKey: 'Metadata title',
24
- type: 'text',
25
- },
26
- {
27
- model: 'abstract',
28
- labelKey: 'Abstract',
29
- type: 'rich',
30
- },
31
- {
32
- model: 'uniqueIdentifier',
33
- labelKey: 'Unique identifier',
34
- type: 'text',
35
- locked: true,
36
- },
37
- ]
38
-
39
15
  private apiUrl = `${this.apiConfiguration?.basePath || '/geonetwork/srv/api'}`
40
16
 
41
- fields$: Observable<FormField[]> = this.record$.pipe(
42
- map((record) =>
43
- this.fieldsConfig.map((fieldConfig) => ({
44
- config: fieldConfig,
45
- value: record?.[fieldConfig.model] || null,
46
- }))
47
- )
48
- )
49
- saving$ = new BehaviorSubject(false)
50
-
51
17
  constructor(
52
18
  private http: HttpClient,
53
19
  @Optional()
54
20
  @Inject(Configuration)
55
21
  private apiConfiguration: Configuration
56
22
  ) {}
23
+
24
+ // TODO: use the catalog repository instead
57
25
  loadRecordByUuid(uuid: string): Observable<CatalogRecord> {
58
26
  return this.http
59
27
  .get(`${this.apiUrl}/records/${uuid}/formatters/xml`, {
@@ -65,43 +33,36 @@ export class EditorService {
65
33
  .pipe(map((response) => toModel(response.toString())))
66
34
  }
67
35
 
68
- saveCurrentRecord(): Observable<void> {
69
- return this.record$.pipe(
70
- take(1),
71
- tap((record) => {
72
- if (!record)
73
- throw new Error('Save record failed: no record currently open')
74
- this.saving$.next(true)
75
- }),
76
- switchMap((record) =>
77
- this.http.put(
78
- `${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`,
79
- toXml(record),
80
- {
81
- headers: {
82
- 'Content-Type': 'application/xml',
83
- },
84
- withCredentials: true,
85
- }
86
- )
87
- ),
88
- map(() => undefined),
89
- finalize(() => {
90
- this.saving$.next(false)
91
- })
92
- )
93
- }
36
+ // returns the record as it was when saved
37
+ saveRecord(
38
+ record: CatalogRecord,
39
+ fieldsConfig: EditorFieldsConfig
40
+ ): Observable<CatalogRecord> {
41
+ const savedRecord = { ...record }
94
42
 
95
- setCurrentRecord(record: CatalogRecord) {
96
- this.record$.next(record)
97
- }
43
+ // run onSave processes
44
+ for (const field of fieldsConfig) {
45
+ if (field.onSaveProcess && field.model) {
46
+ const evaluator = evaluate(field.onSaveProcess)
47
+ savedRecord[field.model] = evaluator({
48
+ config: field,
49
+ value: record[field.model],
50
+ })
51
+ }
52
+ }
98
53
 
99
- updateRecordField(fieldName: string, value: unknown) {
100
- this.record$
101
- .pipe(
102
- take(1),
103
- map((record) => ({ ...record, [fieldName]: value }))
54
+ // TODO: use the catalog repository instead
55
+ return this.http
56
+ .put(
57
+ `${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`,
58
+ toXml(savedRecord),
59
+ {
60
+ headers: {
61
+ 'Content-Type': 'application/xml',
62
+ },
63
+ withCredentials: true,
64
+ }
104
65
  )
105
- .subscribe((record) => this.record$.next(record))
66
+ .pipe(map(() => savedRecord))
106
67
  }
107
68
  }
@@ -29,18 +29,18 @@ export class DataViewPermalinkComponent {
29
29
  if (config) {
30
30
  const { aggregation, xProperty, yProperty, chartType } = config
31
31
  const url = new URL(`${this.wcEmbedderBaseUrl}`, window.location.origin)
32
- url.search = `?v=${this.version}
33
- &e=gn-dataset-view-chart
34
- &a=api-url=${this.config.basePath}
35
- &a=dataset-id=${metadata.uniqueIdentifier}
36
- &a=primary-color=%230f4395
37
- &a=secondary-color=%238bc832
38
- &a=main-color=%23555
39
- &a=background-color=%23fdfbff
40
- &a=aggregation=${aggregation}
41
- &a=x-property=${xProperty}
42
- &a=y-property=${yProperty}
43
- &a=chart-type=${chartType}`
32
+ url.searchParams.set('v', `${this.version}`)
33
+ url.searchParams.append('e', `gn-dataset-view-chart`)
34
+ url.searchParams.append('a', `api-url=${this.config.basePath}`)
35
+ url.searchParams.append('a', `dataset-id=${metadata.uniqueIdentifier}`)
36
+ url.searchParams.append('a', `primary-color=#0f4395`)
37
+ url.searchParams.append('a', `secondary-color=#8bc832`)
38
+ url.searchParams.append('a', `main-color=#555`)
39
+ url.searchParams.append('a', `background-color=#fdfbff`)
40
+ url.searchParams.append('a', `aggregation=${aggregation}`)
41
+ url.searchParams.append('a', `x-property=${xProperty}`)
42
+ url.searchParams.append('a', `y-property=${yProperty}`)
43
+ url.searchParams.append('a', `chart-type=${chartType}`)
44
44
  return url.toString()
45
45
  }
46
46
  return ''
@@ -1,6 +1,6 @@
1
- <div class="flex flex-row content-center">
1
+ <div class="flex flex-row items-center">
2
2
  <span
3
- class="align-text-top mr-1.5 mt-1.5 favorite-count"
3
+ class="align-text-top mr-1.5 favorite-count"
4
4
  *ngIf="hasFavoriteCount && displayCount"
5
5
  >{{ favoriteCount }}</span
6
6
  >
@@ -8,10 +8,9 @@
8
8
  [toggled]="isFavorite$ | async"
9
9
  (newValue)="toggleFavorite($event)"
10
10
  [disabled]="loading || (isAnonymous$ | async)"
11
- class="mt-1"
12
11
  ></gn-ui-star-toggle>
13
12
  <span
14
- class="align-text-top ml-1.5 favorite-count mt-1.5"
13
+ class="align-text-top ml-1.5 favorite-count"
15
14
  *ngIf="!displayCount"
16
15
  translate="datahub.record.addToFavorites"
17
16
  ></span>
@@ -5,6 +5,6 @@
5
5
  [selected]="currentLang"
6
6
  ariaName="languages"
7
7
  [showTitle]="false"
8
- [extraBtnClass]="'flex justify-items-center text-white !pl-2 !py-1'"
8
+ extraBtnClass="bg-transparent flex justify-items-center !pl-2 !py-1"
9
9
  >
10
10
  </gn-ui-dropdown-selector>
@@ -1,10 +1,14 @@
1
1
  <div
2
2
  #container
3
- class="max-lines overflow-hidden transition-[max-height] duration-300"
3
+ class="max-lines overflow-hidden transition-[max-height] duration-300 relative"
4
4
  [ngClass]="isExpanded ? 'ease-in' : 'ease-out'"
5
5
  [style.maxHeight]="maxHeight"
6
6
  >
7
7
  <ng-content></ng-content>
8
+ <div
9
+ *ngIf="showToggleButton && !isExpanded"
10
+ class="absolute inset-x-0 bottom-0 bg-gradient-to-b from-transparent to-white h-3"
11
+ ></div>
8
12
  </div>
9
13
  <div
10
14
  *ngIf="showToggleButton"
@@ -78,6 +78,7 @@ export class MaxLinesComponent implements AfterViewInit, OnDestroy {
78
78
  }
79
79
 
80
80
  ngOnDestroy(): void {
81
+ if (!this.observer) return
81
82
  this.observer.unobserve(this.container.nativeElement.children[0])
82
83
  }
83
84
  }
@@ -1,5 +1,5 @@
1
1
  <div class="py-5 px-5 rounded bg-gray-100 text-black mb-6">
2
- <div class="grid gap-3">
2
+ <div class="grid gap-3 overflow-hidden">
3
3
  <div>
4
4
  <p class="text-sm font-medium" translate>record.metadata.contact</p>
5
5
  </div>
@@ -55,29 +55,82 @@
55
55
  </div>
56
56
  </gn-ui-expandable-panel>
57
57
  <gn-ui-expandable-panel
58
- class="metadata-origin"
59
58
  *ngIf="
60
59
  metadata.lineage ||
61
60
  metadata.recordUpdated ||
62
61
  metadata.updateFrequency ||
63
62
  metadata.status
64
63
  "
65
- [title]="'record.metadata.origin' | translate"
64
+ [title]="'record.metadata.details' | translate"
66
65
  >
67
- <p
68
- *ngIf="metadata.lineage"
69
- class="mb-5 pt-4 whitespace-pre-line break-words text-gray-900"
70
- gnUiLinkify
71
- >
72
- {{ metadata.lineage }}
73
- </p>
66
+ <div *ngIf="metadata.lineage" class="text-gray-900 flex flex-col mt-4 gap-2">
67
+ <p class="whitespace-pre-line break-words text-gray-900" gnUiLinkify>
68
+ {{ metadata.lineage }}
69
+ </p>
70
+ </div>
71
+ <div class="flex flex-row gap-6 mt-5 mb-8" *ngIf="resourceContact">
72
+ <div
73
+ *ngIf="resourceContact.organization?.logoUrl?.href"
74
+ class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
75
+ >
76
+ <gn-ui-thumbnail
77
+ class="relative h-full w-full"
78
+ [thumbnailUrl]="resourceContact.organization.logoUrl.href"
79
+ fit="contain"
80
+ ></gn-ui-thumbnail>
81
+ </div>
82
+ <div class="flex flex-col gap-1">
83
+ <p class="text-sm font-medium" translate>record.metadata.producer</p>
84
+ <div
85
+ class="text-primary font-title text-21 mr-2 cursor-pointer hover:underline"
86
+ data-cy="organization-name"
87
+ >
88
+ {{ resourceContact.organization?.name }}
89
+ </div>
90
+ <div *ngIf="resourceContact.organization?.website">
91
+ <a
92
+ [href]="resourceContact.organization.website"
93
+ target="_blank"
94
+ class="contact-website text-primary text-sm cursor-pointer hover:underline transition-all"
95
+ >{{ resourceContact.organization.website }}
96
+ <mat-icon
97
+ class="material-symbols-outlined !w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
98
+ >open_in_new</mat-icon
99
+ >
100
+ </a>
101
+ </div>
102
+ <div class="mt-4" *ngIf="resourceContact.email">
103
+ <div class="flex">
104
+ <mat-icon
105
+ class="material-symbols-outlined !w-5 !h-5 !text-[20px] opacity-75 shrink-0"
106
+ >
107
+ mail_outline</mat-icon
108
+ >
109
+ <a
110
+ *ngIf="resourceContact.email"
111
+ [href]="'mailto:' + resourceContact.email"
112
+ class="text-sm hover:underline ml-2"
113
+ target="_blank"
114
+ data-cy="contact-email"
115
+ >{{ resourceContact?.email }}</a
116
+ >
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
74
121
  <div
75
- class="py-4 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-[10px] gap-x-[20px] text-gray-700 info-grid"
122
+ class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
76
123
  >
77
- <div *ngIf="metadata.recordUpdated">
78
- <p class="text-sm" translate>record.metadata.updatedOn</p>
124
+ <div *ngIf="metadata.recordCreated">
125
+ <p class="text-sm" translate>record.metadata.creation</p>
79
126
  <p class="text-primary font-medium mt-1">
80
- {{ metadata.recordUpdated && metadata.recordUpdated.toLocaleString() }}
127
+ {{ metadata.recordCreated.toLocaleDateString() }}
128
+ </p>
129
+ </div>
130
+ <div *ngIf="metadata.recordPublished">
131
+ <p class="text-sm" translate>record.metadata.publication</p>
132
+ <p class="text-primary font-medium mt-1">
133
+ {{ metadata.recordPublished.toLocaleDateString() }}
81
134
  </p>
82
135
  </div>
83
136
  <div *ngIf="updateFrequency">
@@ -90,17 +143,52 @@
90
143
  {{ updateFrequency }}
91
144
  </p>
92
145
  </div>
93
- <div *ngIf="metadata.status">
94
- <p class="text-sm" translate>record.metadata.updateStatus</p>
95
- <p class="text-primary font-medium mt-1" translate>
96
- domain.record.status.{{ metadata.status }}
97
- </p>
146
+ <div *ngIf="metadata.languages">
147
+ <p class="text-sm mb-1" translate>record.metadata.languages</p>
148
+ <div class="flex flex-row gap-1 flex-wrap">
149
+ <p
150
+ class="text-primary font-medium"
151
+ translate
152
+ *ngFor="let language of metadata.languages"
153
+ >
154
+ language.{{ language }}
155
+ </p>
156
+ </div>
157
+ </div>
158
+ <div *ngIf="temporalExtent">
159
+ <p class="text-sm" translate>record.metadata.temporalExtent</p>
160
+ <div class="flex flex-row gap-1 mb-1 text-primary font-medium">
161
+ <p
162
+ *ngIf="temporalExtent.start && temporalExtent.end"
163
+ translate
164
+ [translateParams]="{
165
+ start: temporalExtent.start,
166
+ end: temporalExtent.end
167
+ }"
168
+ >
169
+ record.metadata.temporalExtent.fromDateToDate
170
+ </p>
171
+ <p
172
+ *ngIf="temporalExtent.start && !temporalExtent.end"
173
+ translate
174
+ [translateParams]="{ start: temporalExtent.start }"
175
+ >
176
+ record.metadata.temporalExtent.sinceDate
177
+ </p>
178
+ <p
179
+ *ngIf="!temporalExtent.start && temporalExtent.end"
180
+ translate
181
+ [translateParams]="{ end: temporalExtent.end }"
182
+ >
183
+ record.metadata.temporalExtent.untilDate
184
+ </p>
185
+ </div>
98
186
  </div>
99
187
  </div>
100
188
  </gn-ui-expandable-panel>
101
189
  <gn-ui-expandable-panel
102
190
  *ngIf="metadata.landingPage"
103
- [title]="'record.metadata.details' | translate"
191
+ [title]="'record.metadata.technical' | translate"
104
192
  >
105
193
  <div class="flex flex-col gap-4 mr-4 py-5 rounded text-gray-700">
106
194
  <div *ngIf="metadata.recordUpdated">
@@ -140,7 +228,7 @@
140
228
  <p class="text-sm mb-1" translate>record.metadata.topics</p>
141
229
  <div class="sm:pb-4 sm:pr-16">
142
230
  <gn-ui-badge
143
- class="inline-block mr-2 lowercase"
231
+ class="inline-block mr-2 mb-2 lowercase"
144
232
  *ngFor="let topic of metadata.topics"
145
233
  >{{ topic }}</gn-ui-badge
146
234
  >
@@ -9,6 +9,7 @@ import {
9
9
  DatasetRecord,
10
10
  Keyword,
11
11
  } from '../../../../../../libs/common/domain/src/lib/model/record'
12
+ import { getTemporalRangeUnion } from '../../../../../../libs/util/shared/src'
12
13
 
13
14
  @Component({
14
15
  selector: 'gn-ui-metadata-info',
@@ -76,6 +77,19 @@ export class MetadataInfoComponent {
76
77
  }
77
78
  }
78
79
 
80
+ get temporalExtent(): { start: string; end: string } {
81
+ const temporalExtents = this.metadata.temporalExtents
82
+ return getTemporalRangeUnion(temporalExtents)
83
+ }
84
+
85
+ get shownOrganization() {
86
+ return this.metadata.ownerOrganization
87
+ }
88
+
89
+ get resourceContact() {
90
+ return this.metadata.contactsForResource?.[0]
91
+ }
92
+
79
93
  fieldReady(propName: string) {
80
94
  return !this.incomplete || propName in this.metadata
81
95
  }
@@ -1,13 +1,13 @@
1
1
  <div
2
2
  #containerElement
3
- class="h-full w-full relative shrink-0 overflow-hidden flex items-center"
3
+ class="h-full w-full relative shrink-0 overflow-hidden flex items-center justify-center"
4
4
  [ngClass]="isPlaceholder ? 'bg-gray-100' : 'bg-white'"
5
5
  [attr.data-cy-is-placeholder]="isPlaceholder.toString()"
6
6
  >
7
7
  <img
8
8
  #imageElement
9
9
  class="relative w-full object-center"
10
- [ngClass]="imgFit === 'contain' ? 'h-4/5' : 'h-full'"
10
+ [ngClass]="imgFit === 'contain' ? 'h-4/5 w-4/5' : 'h-full'"
11
11
  [ngStyle]="{ objectFit: imgFit }"
12
12
  alt="thumbnail"
13
13
  loading="lazy"
@@ -1,5 +0,0 @@
1
- /* makes sure icons will not make the buttons grow vertically */
2
- :host ::ng-deep mat-icon.mat-icon {
3
- margin-top: -0.325em;
4
- margin-bottom: -0.325em;
5
- }
@@ -1,6 +1,5 @@
1
1
  <button
2
2
  type="button"
3
- class="flex flex-row items-center text-[1em] leading-none p-[1em] rounded-[0.25em] transition-all duration-100 focus:outline-none disabled:opacity-50 disabled:pointer-events-none"
4
3
  [class]="classList"
5
4
  [disabled]="disabled"
6
5
  (click)="handleClick($event)"
@@ -17,25 +17,25 @@ import { propagateToDocumentOnly } from '../../../../../../libs/util/shared/src'
17
17
  export class ButtonComponent {
18
18
  private btnClass: string
19
19
 
20
- // btn-classes are explicited to allow tailwind recognize them and add it in css.
21
20
  @Input() set type(
22
21
  value: 'primary' | 'secondary' | 'default' | 'outline' | 'light'
23
22
  ) {
23
+ // btn-classes are written in full to be picked up by tailwind
24
24
  switch (value) {
25
25
  case 'primary':
26
- this.btnClass = 'btn-primary'
26
+ this.btnClass = 'gn-ui-btn-primary'
27
27
  break
28
28
  case 'secondary':
29
- this.btnClass = 'btn-secondary'
29
+ this.btnClass = 'gn-ui-btn-secondary'
30
30
  break
31
31
  case 'outline':
32
- this.btnClass = 'btn-outline'
32
+ this.btnClass = 'gn-ui-btn-outline'
33
33
  break
34
34
  case 'light':
35
- this.btnClass = 'btn-light'
35
+ this.btnClass = 'gn-ui-btn-light'
36
36
  break
37
37
  default:
38
- this.btnClass = 'btn-default'
38
+ this.btnClass = 'gn-ui-btn-default'
39
39
  break
40
40
  }
41
41
  }
@@ -1,6 +1,6 @@
1
1
  <gn-ui-button
2
2
  type="outline"
3
- extraClass="w-full !p-[8px] !pl-[16px]"
3
+ extraClass="bg-background w-full !p-[8px] !pl-[16px]"
4
4
  [title]="title"
5
5
  [attr.aria-owns]="id"
6
6
  (buttonClick)="openOverlay()"
@@ -9,7 +9,9 @@
9
9
  <gn-ui-button
10
10
  type="outline"
11
11
  class="grow min-w-0"
12
- extraClass="!p-[8px] !pl-[16px] flex flex-row w-full {{ extraBtnClass }}"
12
+ extraClass="bg-background !p-[8px] !pl-[16px] flex flex-row w-full {{
13
+ extraBtnClass
14
+ }}"
13
15
  [title]="title"
14
16
  [attr.aria-owns]="id"
15
17
  (buttonClick)="openOverlay()"
@@ -17,7 +17,9 @@ import { Observable } from 'rxjs'
17
17
  export class FormFieldComponent {
18
18
  @Input() config: FormFieldConfig
19
19
  @Input() set value(v: unknown) {
20
- this.formControl.setValue(v)
20
+ this.formControl.setValue(v, {
21
+ emitEvent: false,
22
+ })
21
23
  }
22
24
  @Output() valueChange: Observable<unknown>
23
25
 
@@ -13,7 +13,6 @@ type BaseFormFieldType =
13
13
  type AllFormFieldType = BaseFormFieldType | 'object' | 'array'
14
14
 
15
15
  interface FormFieldConfigBase {
16
- model?: string
17
16
  type: AllFormFieldType
18
17
  labelKey: string
19
18
  hintKey?: string
@@ -0,0 +1,3 @@
1
+ button {
2
+ color: var(--navigation-button-color, --color-background);
3
+ }
@@ -1,5 +1,5 @@
1
1
  <button
2
- class="group flex items-center justify-center gap-1 backdrop-blur p-1 bg-primary-opacity-30 text-white rounded content-center"
2
+ class="group flex items-center justify-center gap-1 backdrop-blur p-1 bg-primary-opacity-30 rounded content-center"
3
3
  >
4
4
  <mat-icon class="material-symbols-outlined align-middle w-[18px]">{{
5
5
  icon
@@ -4,6 +4,7 @@
4
4
  </div>
5
5
  </div>
6
6
  <div
7
+ *ngIf="steps.length > 1"
7
8
  class="absolute right-0 top-0 flex flex-row justify-center gap-[10px] p-1"
8
9
  [ngClass]="stepsContainerClass"
9
10
  >
@@ -40,6 +40,24 @@ export const LANG_3_TO_2_MAPPER = {
40
40
  slo: 'sk',
41
41
  }
42
42
 
43
+ export const LANGUAGE_NAMES = {
44
+ en: 'English',
45
+ nl: 'Nederlands',
46
+ fr: 'Français',
47
+ de: 'Deutsch',
48
+ ko: '한국어',
49
+ es: 'Español',
50
+ cs: 'Čeština',
51
+ ca: 'Català',
52
+ fi: 'Suomi',
53
+ is: 'Íslenska',
54
+ it: 'Italiano',
55
+ pt: 'Português',
56
+ ru: 'Русский',
57
+ zh: '中文',
58
+ sk: 'Slovenčina',
59
+ }
60
+
43
61
  // Caution: changing this can break language selection from third parties!
44
62
  export const LANGUAGE_STORAGE_KEY = 'geonetwork-ui-language'
45
63
 
@@ -6,3 +6,4 @@ export * from './sort-by'
6
6
  export * from './url'
7
7
  export * from './event'
8
8
  export * from './fuzzy-filter'
9
+ export * from './temporal-extent-union'
@@ -0,0 +1,32 @@
1
+ export function getTemporalRangeUnion(ranges) {
2
+ let earliestStartDate = Infinity
3
+ let latestEndDate = -Infinity
4
+ if (ranges.length) {
5
+ for (let i = 0; i < ranges.length; i++) {
6
+ const rangeStart = ranges[i].start
7
+ ? new Date(ranges[i].start).getTime()
8
+ : -Infinity
9
+ const rangeEnd = ranges[i].end
10
+ ? new Date(ranges[i].end).getTime()
11
+ : Infinity
12
+ if (rangeStart < earliestStartDate) {
13
+ earliestStartDate = rangeStart
14
+ }
15
+ if (rangeEnd > latestEndDate) {
16
+ latestEndDate = rangeEnd
17
+ }
18
+ }
19
+ return {
20
+ start:
21
+ earliestStartDate !== -Infinity
22
+ ? new Date(earliestStartDate).toLocaleDateString()
23
+ : undefined,
24
+ end:
25
+ latestEndDate !== Infinity
26
+ ? new Date(latestEndDate).toLocaleDateString()
27
+ : undefined,
28
+ }
29
+ } else {
30
+ return undefined
31
+ }
32
+ }