geonetwork-ui 2.10.0-dev.e97ea6950 → 2.10.0-dev.f1c00d5fe

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 (174) hide show
  1. package/fesm2022/geonetwork-ui.mjs +2558 -6985
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +299 -189
  4. package/index.d.ts.map +1 -1
  5. package/package.json +25 -35
  6. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +20 -0
  7. package/src/libs/api/metadata-converter/src/lib/fixtures/eu.dcat-ap.records.ts +4 -0
  8. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +23 -0
  9. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +8 -0
  10. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+roilaye.ts +2 -0
  11. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +2 -0
  12. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +2 -0
  13. package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +2 -0
  14. package/src/libs/api/metadata-converter/src/lib/fixtures/metadata-for-i18n.records.ts +4 -0
  15. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +23 -0
  16. package/src/libs/api/metadata-converter/src/lib/fixtures/opendataswiss.records.ts +2 -0
  17. package/src/libs/api/metadata-converter/src/lib/fixtures/sextant.records.ts +4 -0
  18. package/src/libs/api/metadata-converter/src/lib/fixtures/vlaanderen.dcat-ap.records.ts +2 -0
  19. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +9 -0
  20. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
  21. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.converter.ts +2 -0
  22. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +6 -5
  23. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  24. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  25. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +11 -0
  26. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +21 -0
  27. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +52 -0
  28. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +24 -1
  29. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +73 -0
  30. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +79 -0
  31. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +8 -4
  32. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  33. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +79 -41
  34. package/src/libs/api/repository/src/lib/gn4/gn4.provider.ts +6 -1
  35. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  36. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  37. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +37 -2
  38. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +23 -5
  39. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  40. package/src/libs/common/domain/src/lib/model/user/group.model.ts +8 -0
  41. package/src/libs/common/domain/src/lib/model/user/index.ts +1 -0
  42. package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
  43. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -1
  44. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +62 -0
  45. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  46. package/src/libs/feature/editor/src/index.ts +1 -0
  47. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +10 -1
  48. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -20
  49. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +15 -2
  50. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  51. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.css +0 -0
  52. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +68 -0
  53. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +41 -0
  54. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
  55. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
  56. package/src/libs/feature/editor/src/lib/components/metadata-quality-panel/metadata-quality-panel.component.html +18 -3
  57. package/src/libs/feature/editor/src/lib/components/metadata-quality-panel/metadata-quality-panel.component.ts +33 -40
  58. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  59. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  60. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +41 -0
  61. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +33 -34
  62. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +13 -13
  63. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +18 -4
  64. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.html +8 -7
  65. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.ts +6 -6
  66. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  67. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.css +0 -0
  68. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.html +5 -0
  69. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-single-link-resource/form-field-online-single-link-resource.component.ts +89 -0
  70. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  71. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  72. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  73. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
  74. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  75. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  76. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +3 -0
  77. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +28 -16
  78. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +16 -0
  79. package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -0
  80. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  81. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  82. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +118 -5
  83. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  84. package/src/libs/feature/editor/src/lib/fields.config.ts +354 -337
  85. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -3
  86. package/src/libs/feature/editor/src/lib/services/editor.service.ts +9 -13
  87. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  88. package/src/libs/feature/notify-reuse/src/index.ts +2 -0
  89. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
  90. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
  91. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
  92. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.css +0 -0
  93. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -0
  94. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +234 -0
  95. package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
  96. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  97. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  98. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  99. package/src/libs/ui/dataviz/src/index.ts +0 -1
  100. package/src/libs/ui/elements/src/index.ts +3 -0
  101. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +88 -0
  102. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.ts +45 -0
  103. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +41 -0
  104. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.ts +70 -0
  105. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  106. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  107. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  108. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  109. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  110. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +1 -1
  111. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +0 -1
  112. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
  113. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
  114. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  115. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.ts +2 -5
  116. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +3 -2
  117. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +26 -68
  118. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +30 -10
  119. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  120. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  121. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
  122. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
  123. package/src/libs/ui/inputs/src/lib/button/button.component.ts +8 -0
  124. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  125. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  126. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  127. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
  128. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
  129. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
  130. package/src/libs/ui/inputs/src/lib/url-input/url-input.component.html +2 -2
  131. package/src/libs/ui/inputs/src/lib/url-input/url-input.component.ts +2 -1
  132. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  133. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  134. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  135. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  136. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  137. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  138. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +2 -1
  139. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +15 -64
  140. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  141. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  142. package/src/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html +0 -1
  143. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  144. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  145. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  146. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  147. package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
  148. package/src/libs/util/app-config/src/lib/app-config.ts +70 -9
  149. package/src/libs/util/app-config/src/lib/model.ts +7 -0
  150. package/src/libs/util/app-config/src/lib/parse-utils.ts +50 -1
  151. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
  152. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
  153. package/src/libs/util/i18n/src/index.ts +0 -1
  154. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  155. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  156. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  157. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  158. package/src/libs/util/shared/src/lib/links/link-utils.ts +23 -1
  159. package/src/libs/util/shared/src/lib/record/quality-score.util.ts +33 -18
  160. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  161. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  162. package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
  163. package/src/libs/util/shared/src/lib/utils/user-display.ts +32 -0
  164. package/style.css +0 -1
  165. package/tailwind.base.css +26 -2
  166. package/translations/de.json +112 -50
  167. package/translations/en.json +117 -55
  168. package/translations/es.json +86 -24
  169. package/translations/fr.json +114 -52
  170. package/translations/it.json +113 -51
  171. package/translations/nl.json +85 -23
  172. package/translations/pt.json +86 -24
  173. package/translations/sk.json +86 -24
  174. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
@@ -6,7 +6,7 @@ import {
6
6
  } from '@angular/common/http'
7
7
  import { DEFAULT_LANG } from './i18n.constants'
8
8
  import { Observable } from 'rxjs'
9
- import { Injectable, Injector, inject } from '@angular/core'
9
+ import { inject, Injectable, Injector } from '@angular/core'
10
10
  import { TranslateService } from '@ngx-translate/core'
11
11
 
12
12
  @Injectable()
@@ -21,7 +21,7 @@ export class I18nInterceptor implements HttpInterceptor {
21
21
  const translate = this.injector.get(TranslateService)
22
22
  request = request.clone({
23
23
  setHeaders: {
24
- 'Accept-Language': translate.currentLang || DEFAULT_LANG,
24
+ 'Accept-Language': translate.getCurrentLang() || DEFAULT_LANG,
25
25
  },
26
26
  })
27
27
  return next.handle(request)
@@ -1,7 +1,8 @@
1
1
  import {
2
- APP_INITIALIZER,
3
2
  EnvironmentProviders,
3
+ inject,
4
4
  makeEnvironmentProviders,
5
+ provideAppInitializer,
5
6
  Provider,
6
7
  } from '@angular/core'
7
8
  import {
@@ -22,17 +23,16 @@ import {
22
23
  } from '@angular/common/http'
23
24
  import { I18nInterceptor } from './i18n.interceptor'
24
25
 
25
- function i18nInitializerFromLocalStorageFactory(translate: TranslateService) {
26
- return () => {
27
- translate.setDefaultLang(DEFAULT_LANG)
28
- let storageLang = null
29
- try {
30
- storageLang = localStorage.getItem(LANGUAGE_STORAGE_KEY)
31
- } catch (error) {
32
- console.warn(error)
33
- }
34
- translate.use(storageLang || translate.getBrowserLang() || DEFAULT_LANG)
26
+ function i18nInitializerFromLocalStorageFactory() {
27
+ const translate = inject(TranslateService)
28
+ translate.setFallbackLang(DEFAULT_LANG)
29
+ let storageLang = null
30
+ try {
31
+ storageLang = localStorage.getItem(LANGUAGE_STORAGE_KEY)
32
+ } catch (error) {
33
+ console.warn(error)
35
34
  }
35
+ translate.use(storageLang || translate.getBrowserLang() || DEFAULT_LANG)
36
36
  }
37
37
 
38
38
  export function provideI18n(
@@ -56,12 +56,9 @@ export function provideI18n(
56
56
  provideTranslateService(usedConfig),
57
57
  ]
58
58
  if (useLocalStorage) {
59
- providers.push({
60
- provide: APP_INITIALIZER,
61
- useFactory: i18nInitializerFromLocalStorageFactory,
62
- deps: [TranslateService],
63
- multi: true,
64
- })
59
+ providers.push(
60
+ provideAppInitializer(i18nInitializerFromLocalStorageFactory)
61
+ )
65
62
  }
66
63
 
67
64
  return makeEnvironmentProviders(providers)
@@ -0,0 +1,48 @@
1
+ import { inject, Injectable, InjectionToken } from '@angular/core'
2
+ import {
3
+ provideTranslateService,
4
+ TranslateCompiler,
5
+ TranslateLoader,
6
+ TranslationObject,
7
+ } from '@ngx-translate/core'
8
+ import { Observable, of } from 'rxjs'
9
+ import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler'
10
+
11
+ /**
12
+ * This translate loader is used for testing purposes, it allows to provide translations directly in the test file without having to create JSON files
13
+ * Taken from https://github.com/mwootendev/ngx-translate-plugins/issues/87
14
+ */
15
+
16
+ const TestTranslations = new InjectionToken<Record<string, TranslationObject>>(
17
+ 'test-translations'
18
+ )
19
+
20
+ @Injectable()
21
+ class TestTranslateLoader implements TranslateLoader {
22
+ translations = inject(TestTranslations)
23
+ getTranslation(lang: string): Observable<TranslationObject> {
24
+ return of(this.translations[lang] as TranslationObject)
25
+ }
26
+ }
27
+
28
+ export function provideTranslateTestingService(
29
+ translations: Record<string, TranslationObject>
30
+ ) {
31
+ return provideTranslateService({
32
+ loader: [
33
+ {
34
+ provide: TestTranslations,
35
+ useValue: translations,
36
+ },
37
+ {
38
+ provide: TranslateLoader,
39
+ useClass: TestTranslateLoader,
40
+ },
41
+ ],
42
+ fallbackLang: 'en',
43
+ compiler: {
44
+ provide: TranslateCompiler,
45
+ useClass: TranslateMessageFormatCompiler,
46
+ },
47
+ })
48
+ }
@@ -171,6 +171,28 @@ export const FORMATS = {
171
171
  },
172
172
  } as const
173
173
 
174
+ marker('downloads.format.csv')
175
+ marker('downloads.format.excel')
176
+ marker('downloads.format.geojson')
177
+ marker('downloads.format.json')
178
+ marker('downloads.format.shp')
179
+ marker('downloads.format.gml')
180
+ marker('downloads.format.kml')
181
+ marker('downloads.format.gpkg')
182
+ marker('downloads.format.zip')
183
+ marker('downloads.format.pdf')
184
+ marker('downloads.format.jpg')
185
+ marker('downloads.format.png')
186
+ marker('downloads.format.tiff')
187
+ marker('downloads.format.svg')
188
+ marker('downloads.format.dxf')
189
+ marker('downloads.format.html')
190
+ marker('downloads.format.xml')
191
+ marker('downloads.format.fgb')
192
+ marker('downloads.format.jsonfg')
193
+ marker('downloads.format.webp')
194
+ marker('downloads.format.postgis')
195
+
174
196
  export type FileFormat = keyof typeof FORMATS
175
197
 
176
198
  export function getFormatPriority(linkFormat: FileFormat): number {
@@ -266,7 +288,7 @@ export function checkFileFormat(
266
288
  new RegExp(`[./]${format}`, 'i').test(link.name.toLowerCase())) ||
267
289
  ('url' in link &&
268
290
  new RegExp(`[./]${format}`, 'i').test(link.url.toString())) ||
269
- ('name' in link && link.name.toLowerCase().includes(format))
291
+ ('name' in link && new RegExp(`\\b${format}\\b`, 'i').test(link.name))
270
292
  )
271
293
  }
272
294
 
@@ -3,27 +3,41 @@ import {
3
3
  RecordKind,
4
4
  } from '../../../../../../libs/common/domain/src/lib/model/record'
5
5
 
6
+ type TValidatorEntry = {
7
+ validator: (metadata: Partial<CatalogRecord>) => boolean
8
+ alias?: string
9
+ }
10
+
6
11
  type TValidatorMapper = {
7
- [key: string]: (metadata: Partial<CatalogRecord>) => boolean
12
+ [key: string]: TValidatorEntry
8
13
  }
9
14
 
10
15
  const ValidatorMapper: TValidatorMapper = {
11
- title: (record) => !!record?.title,
12
- abstract: (record) => !!record?.abstract,
13
- keywords: (record) => (record?.keywords?.length ?? 0) > 0,
14
- legalConstraints: (record) =>
15
- !!(
16
- record?.legalConstraints?.length &&
17
- record.legalConstraints.some((c) => c?.text?.trim().length > 0)
18
- ),
19
- contacts: (record) =>
20
- !!record?.contacts?.[0]?.email &&
21
- record.contacts[0].email !== 'missing@missing.com',
22
- updateFrequency: (record) =>
23
- !!record?.updateFrequency && record.updateFrequency !== 'unknown',
24
- topics: (record) => (record?.topics?.length ?? 0) > 0,
25
- organisation: (record) => !!record?.contacts?.[0]?.organization?.name,
26
- source: (record) => !!record?.extras?.sourcesIdentifiers,
16
+ title: { validator: (record) => !!record?.title },
17
+ abstract: { validator: (record) => !!record?.abstract },
18
+ keywords: { validator: (record) => (record?.keywords?.length ?? 0) > 0 },
19
+ legalConstraints: {
20
+ validator: (record) =>
21
+ !!(
22
+ record?.legalConstraints?.length &&
23
+ record.legalConstraints.some((c) => c?.text?.trim().length > 0)
24
+ ),
25
+ },
26
+ contacts: {
27
+ validator: (record) =>
28
+ !!record?.contacts?.[0]?.email &&
29
+ record.contacts[0].email !== 'missing@missing.com',
30
+ },
31
+ updateFrequency: {
32
+ validator: (record) =>
33
+ !!record?.updateFrequency && record.updateFrequency !== 'unknown',
34
+ },
35
+ topics: { validator: (record) => (record?.topics?.length ?? 0) > 0 },
36
+ organisation: {
37
+ validator: (record) => !!record?.contacts?.[0]?.organization?.name,
38
+ alias: 'contacts',
39
+ },
40
+ source: { validator: (record) => !!record?.extras?.sourcesIdentifiers },
27
41
  } as const
28
42
 
29
43
  export type ValidatorMapperKeys = keyof typeof ValidatorMapper & string
@@ -67,6 +81,7 @@ export function getQualityValidators(
67
81
 
68
82
  return filteredProps.map((name) => ({
69
83
  name,
70
- validator: () => ValidatorMapper[name](record),
84
+ validator: () => ValidatorMapper[name].validator(record),
85
+ alias: ValidatorMapper[name].alias,
71
86
  }))
72
87
  }
@@ -1,4 +1,4 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import { TranslateService } from '@ngx-translate/core'
3
3
  import { type Locale } from 'date-fns/locale'
4
4
  import { formatDistance } from 'date-fns/formatDistance'
@@ -30,13 +30,13 @@ export class DateService {
30
30
  locale: string
31
31
  dateObj: Date
32
32
  } {
33
- const locale = this.translateService.currentLang || DEFAULT_LANGUAGE
33
+ const locale = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE
34
34
  const dateObj = this.getDateObject(date)
35
35
  return { locale, dateObj }
36
36
  }
37
37
 
38
38
  private async getDateLocale(): Promise<Locale> {
39
- const lang = this.translateService.currentLang || DEFAULT_LANGUAGE
39
+ const lang = this.translateService.getCurrentLang() || DEFAULT_LANGUAGE
40
40
  const locales = await this.dateLocales
41
41
  return locales[lang]
42
42
  }
@@ -1,4 +1,11 @@
1
- import type { Feature, FeatureCollection, Geometry, Position } from 'geojson'
1
+ import type {
2
+ Feature,
3
+ FeatureCollection,
4
+ Geometry,
5
+ Polygon,
6
+ Position,
7
+ } from 'geojson'
8
+ import type { DatasetSpatialExtent } from '../../../../../../libs/common/domain/src/lib/model/record'
2
9
 
3
10
  /**
4
11
  * @returns The geometry if available, otherwise null.
@@ -94,3 +101,53 @@ export function getGeometryBoundingBox(geometry: Geometry): BoundingBox {
94
101
  return coordinatesReducer(emptyExtent, geometry.coordinates)
95
102
  }
96
103
  }
104
+
105
+ /**
106
+ * Builds the closed GeoJSON Polygon matching the given bounding box.
107
+ */
108
+ export function bboxToPolygon(bbox: BoundingBox): Polygon {
109
+ const [minX, minY, maxX, maxY] = bbox
110
+ return {
111
+ type: 'Polygon',
112
+ coordinates: [
113
+ [
114
+ [minX, minY],
115
+ [minX, maxY],
116
+ [maxX, maxY],
117
+ [maxX, minY],
118
+ [minX, minY],
119
+ ],
120
+ ],
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Returns the geometry carried by a spatial extent, falling back to the polygon
126
+ * derived from its bounding box. Returns null when the extent has neither.
127
+ */
128
+ export function spatialExtentToGeometry(
129
+ extent: DatasetSpatialExtent
130
+ ): Geometry | null {
131
+ if (extent.geometry) return extent.geometry
132
+ if (extent.bbox) return bboxToPolygon(extent.bbox)
133
+ return null
134
+ }
135
+
136
+ /**
137
+ * Converts a list of dataset spatial extents into a GeoJSON FeatureCollection,
138
+ * e.g. to be used as the data source of a map layer.
139
+ */
140
+ export function spatialExtentsToFeatureCollection(
141
+ extents: DatasetSpatialExtent[]
142
+ ): FeatureCollection {
143
+ return {
144
+ type: 'FeatureCollection',
145
+ features: extents.reduce<Feature[]>((features, extent) => {
146
+ const geometry = spatialExtentToGeometry(extent)
147
+ if (geometry) {
148
+ features.push({ type: 'Feature', properties: {}, geometry })
149
+ }
150
+ return features
151
+ }, []),
152
+ }
153
+ }
@@ -13,3 +13,4 @@ export * from './sort-by'
13
13
  export * from './strip-html'
14
14
  export * from './temporal-extent-union'
15
15
  export * from './url'
16
+ export * from './user-display'
@@ -0,0 +1,32 @@
1
+ import { UserModel } from '../../../../../../libs/common/domain/src/lib/model/user'
2
+ import { Individual } from '../../../../../../libs/common/domain/src/lib/model/record'
3
+
4
+ export function getIndividualDisplayName(individual: Individual): string {
5
+ const nameParts = [individual.firstName, individual.lastName]
6
+ .filter(Boolean)
7
+ .join(' ')
8
+ const orgPart = individual.organization?.name
9
+ ? ` (${individual.organization.name})`
10
+ : ''
11
+ if (nameParts) return `${nameParts}${orgPart}`
12
+ return individual.organization?.name ?? individual.email ?? ''
13
+ }
14
+
15
+ export function getAddressLines(address: string | undefined): string[] {
16
+ return address
17
+ ? address
18
+ .split(',')
19
+ .map((part) => part.trim())
20
+ .filter(Boolean)
21
+ : []
22
+ }
23
+
24
+ export function toIndividual(user: UserModel): Individual {
25
+ return {
26
+ firstName: user.name,
27
+ lastName: user.surname,
28
+ email: user.email,
29
+ role: 'unspecified',
30
+ organization: user.organisation ? { name: user.organisation } : undefined,
31
+ }
32
+ }
package/style.css CHANGED
@@ -1,4 +1,3 @@
1
1
  @import 'tippy.js/dist/tippy.css';
2
2
  @import 'ol/ol.css';
3
- @import '@angular/material/prebuilt-themes/indigo-pink.css';
4
3
  @import './tailwind.base.css';
package/tailwind.base.css CHANGED
@@ -74,7 +74,10 @@
74
74
  --bg-hover: var(--gn-ui-button-bg-hover, var(--color-background));
75
75
  --font-size: var(--gn-ui-button-font-size, 1em);
76
76
  --color: var(--gn-ui-button-color, var(--color-main));
77
- @apply flex flex-row items-center justify-center
77
+ --disabled-opacity: var(--gn-ui-button-disabled-opacity, 0.5);
78
+ --justify: var(--gn-ui-button-justify, center);
79
+ justify-content: var(--justify);
80
+ @apply flex flex-row items-center
78
81
  text-[length:--font-size] leading-none
79
82
  text-[color:--color]
80
83
  p-[--padding] rounded-[--rounded] w-[--width] h-[--height] overflow-hidden
@@ -82,7 +85,7 @@
82
85
  hover:bg-[--bg-hover] focus:bg-[--bg-hover] active:bg-[--background]
83
86
  outline-none
84
87
  relative
85
- disabled:opacity-50 disabled:pointer-events-none
88
+ disabled:opacity-[--disabled-opacity] disabled:pointer-events-none
86
89
  focus:z-10 active:z-10 hover:z-10;
87
90
  }
88
91
  /* makes sure icons will not make the buttons grow vertically */
@@ -116,6 +119,12 @@
116
119
  border-gray-100 focus:ring-4 focus:ring-gray-50;
117
120
  }
118
121
 
122
+ .gn-ui-btn-gray-light {
123
+ @apply gn-ui-btn text-black
124
+ bg-gray-50 hover:bg-gray-100 focus:bg-gray-100 active:bg-gray-200
125
+ border-gray-50 focus:ring-4 focus:ring-gray-100;
126
+ }
127
+
119
128
  .gn-ui-btn-black {
120
129
  @apply gn-ui-btn text-white
121
130
  bg-black hover:bg-gray-950 focus:bg-gray-950 active:bg-gray-900
@@ -134,6 +143,12 @@
134
143
  bg-white border-white focus:ring-4 focus:ring-gray-300;
135
144
  }
136
145
 
146
+ .gn-ui-btn-primary-light {
147
+ @apply gn-ui-btn text-primary-darkest
148
+ bg-primary-white hover:bg-primary focus:bg-primary hover:text-white focus:text-white active:bg-primary-darker
149
+ border-transparent;
150
+ }
151
+
137
152
  .gn-ui-card-s {
138
153
  @apply min-h-[64px] w-full xs:min-w-[260px] xs:max-w-[280px] sm:min-w-[300px] sm:max-w-[500px] md:min-w-[230px];
139
154
  }
@@ -169,9 +184,18 @@
169
184
  --text-color: var(--gn-ui-badge-text-color, var(--color-gray-50));
170
185
  --background-color: var(--gn-ui-badge-background-color, black);
171
186
  --opacity: var(--gn-ui-badge-opacity, 0.7);
187
+ text-transform: inherit;
172
188
  @apply opacity-[--opacity] p-[--padding] rounded-[--rounded]
173
189
  font-[--font-weight] text-[length:--text-size] text-[color:--text-color] bg-[color:--background-color] flex justify-center items-center content-center;
174
190
  }
191
+ .gn-ui-badge-clickable {
192
+ @apply gn-ui-badge hover:bg-primary focus:bg-primary active:bg-primary-darker
193
+ hover:text-white active:text-white focus:text-white
194
+ transition-all duration-100
195
+ outline-none
196
+ relative
197
+ focus:z-10 active:z-10 hover:z-10;
198
+ }
175
199
  /* makes sure icons will not make the badges grow vertically; also make size proportional */
176
200
  .gn-ui-badge ng-icon {
177
201
  margin-top: -0.325em;