geonetwork-ui 2.10.0-dev.9b93be024 → 2.10.0-dev.a201a91b9

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 (158) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1495 -6128
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +247 -172
  4. package/index.d.ts.map +1 -1
  5. package/material-styles.css +483 -0
  6. package/package.json +25 -35
  7. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +9 -0
  8. package/src/libs/api/metadata-converter/src/lib/fixtures/eu.dcat-ap.records.ts +2 -0
  9. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +1 -0
  10. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +7 -0
  11. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+roilaye.ts +1 -0
  12. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +1 -0
  13. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -0
  14. package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +1 -0
  15. package/src/libs/api/metadata-converter/src/lib/fixtures/metadata-for-i18n.records.ts +2 -0
  16. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +1 -0
  17. package/src/libs/api/metadata-converter/src/lib/fixtures/opendataswiss.records.ts +1 -0
  18. package/src/libs/api/metadata-converter/src/lib/fixtures/sextant.records.ts +2 -0
  19. package/src/libs/api/metadata-converter/src/lib/fixtures/vlaanderen.dcat-ap.records.ts +1 -0
  20. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +8 -0
  21. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
  22. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.converter.ts +1 -0
  23. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +5 -4
  24. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  25. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  26. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +7 -0
  27. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +8 -0
  28. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +8 -0
  29. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +11 -0
  30. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +33 -0
  31. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +33 -0
  32. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +8 -4
  33. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  34. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +72 -38
  35. package/src/libs/api/repository/src/lib/gn4/gn4.provider.ts +6 -1
  36. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  37. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  38. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +48 -2
  39. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +13 -5
  40. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  41. package/src/libs/common/domain/src/lib/model/user/group.model.ts +8 -0
  42. package/src/libs/common/domain/src/lib/model/user/index.ts +1 -0
  43. package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
  44. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +56 -0
  45. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  46. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +10 -1
  47. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -20
  48. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +15 -2
  49. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  50. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.css +0 -0
  51. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +67 -0
  52. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +39 -0
  53. package/src/libs/feature/editor/src/lib/components/metadata-quality-panel/metadata-quality-panel.component.html +18 -3
  54. package/src/libs/feature/editor/src/lib/components/metadata-quality-panel/metadata-quality-panel.component.ts +33 -40
  55. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  56. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  57. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +41 -0
  58. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +33 -34
  59. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +13 -13
  60. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +18 -4
  61. 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
  62. 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
  63. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  64. 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
  65. 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
  66. 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
  67. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  68. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  69. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  70. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
  71. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  72. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  73. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +3 -0
  74. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +21 -16
  75. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +14 -0
  76. package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -0
  77. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  78. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  79. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +118 -5
  80. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  81. package/src/libs/feature/editor/src/lib/fields.config.ts +310 -336
  82. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +6 -3
  83. package/src/libs/feature/editor/src/lib/services/editor.service.ts +9 -13
  84. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  85. package/src/libs/feature/notify-reuse/src/index.ts +1 -0
  86. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.css +0 -0
  87. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +1 -0
  88. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +21 -0
  89. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  90. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  91. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  92. package/src/libs/ui/dataviz/src/index.ts +0 -1
  93. package/src/libs/ui/elements/src/index.ts +2 -0
  94. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +88 -0
  95. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.ts +45 -0
  96. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +41 -0
  97. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.ts +70 -0
  98. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  99. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  100. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  101. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  102. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  103. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +1 -1
  104. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +0 -1
  105. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  106. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.ts +2 -5
  107. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +0 -4
  108. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +39 -68
  109. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +59 -11
  110. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  111. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  112. package/src/libs/ui/inputs/src/lib/button/button.component.ts +8 -0
  113. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  114. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  115. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  116. package/src/libs/ui/inputs/src/lib/url-input/url-input.component.html +2 -2
  117. package/src/libs/ui/inputs/src/lib/url-input/url-input.component.ts +2 -1
  118. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  119. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  120. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  121. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  122. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  123. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  124. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +2 -1
  125. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +15 -64
  126. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  127. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  128. package/src/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html +0 -1
  129. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  130. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  131. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  132. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  133. package/src/libs/util/app-config/src/lib/app-config.ts +70 -9
  134. package/src/libs/util/app-config/src/lib/model.ts +7 -0
  135. package/src/libs/util/app-config/src/lib/parse-utils.ts +50 -1
  136. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
  137. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
  138. package/src/libs/util/i18n/src/index.ts +0 -1
  139. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  140. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  141. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  142. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  143. package/src/libs/util/shared/src/lib/links/link-utils.ts +23 -1
  144. package/src/libs/util/shared/src/lib/record/quality-score.util.ts +33 -18
  145. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  146. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  147. package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
  148. package/src/libs/util/shared/src/lib/utils/user-display.ts +32 -0
  149. package/style.css +0 -1
  150. package/tailwind.base.css +19 -2
  151. package/translations/de.json +81 -48
  152. package/translations/en.json +86 -53
  153. package/translations/es.json +55 -22
  154. package/translations/fr.json +83 -50
  155. package/translations/it.json +81 -48
  156. package/translations/nl.json +54 -21
  157. package/translations/pt.json +55 -22
  158. package/translations/sk.json +55 -22
@@ -58,7 +58,6 @@ export class InternalLinkCardComponent implements OnInit {
58
58
  protected elementRef = inject(ElementRef)
59
59
 
60
60
  @Input() record: CatalogRecord
61
- @Input() linkTarget = '_blank'
62
61
  @Input() linkHref: string = null
63
62
  @Input() metadataQualityDisplay: boolean
64
63
  @Input() favoriteTemplate: TemplateRef<{ $implicit: CatalogRecord }>
@@ -1,5 +1,5 @@
1
1
  import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
- import { marked } from 'marked'
2
+ import { parse } from 'marked'
3
3
 
4
4
  @Component({
5
5
  selector: 'gn-ui-markdown-parser',
@@ -14,6 +14,6 @@ export class MarkdownParserComponent {
14
14
  @Input() whitoutStyles?: boolean
15
15
 
16
16
  get parsedMarkdown() {
17
- return marked.parse(this.textContent ?? '')
17
+ return parse(this.textContent ?? '')
18
18
  }
19
19
  }
@@ -21,7 +21,7 @@ import {
21
21
  matCallOutline,
22
22
  matLocationOnOutline,
23
23
  } from '@ng-icons/material-icons/outline'
24
-
24
+ import { getAddressLines } from '../../../../../../libs/util/shared/src'
25
25
  import { TranslateDirective } from '@ngx-translate/core'
26
26
 
27
27
  @Component({
@@ -59,10 +59,7 @@ export class MetadataContactComponent {
59
59
  }
60
60
 
61
61
  get address() {
62
- const addressParts = this.contacts[0].address
63
- .split(',')
64
- .map((part) => part.trim())
65
- return addressParts
62
+ return getAddressLines(this.contacts[0]?.address)
66
63
  }
67
64
 
68
65
  onOrganizationClick() {
@@ -16,7 +16,3 @@
16
16
  --gn-ui-badge-background-color: var(--color-primary-white);
17
17
  --gn-ui-badge-text-color: var(--color-primary-darkest);
18
18
  }
19
-
20
- :host .metadata-info-keywords ::ng-deep gn-ui-badge:hover {
21
- --gn-ui-badge-text-color: white;
22
- }
@@ -28,12 +28,23 @@
28
28
  <gn-ui-max-lines [maxLines]="7">
29
29
  <div class="metadata-info-keywords sm:pb-4 flex flex-wrap gap-2">
30
30
  @for (keyword of metadata.keywords; track keyword) {
31
- <gn-ui-badge
32
- class="inline-block lowercase"
33
- (click)="onKeywordClick(keyword)"
34
- [clickable]="true"
35
- >{{ keyword.label }}</gn-ui-badge
36
- >
31
+ <ng-template #keywordTooltip>
32
+ @for (segment of keywordTooltipSegments(keyword); track $index) {
33
+ <span [class.font-bold]="$last">{{ segment }}</span>
34
+ @if (!$last) {
35
+ <span> &gt; </span>
36
+ }
37
+ }
38
+ </ng-template>
39
+ <gn-ui-popover [content]="keywordTooltip" theme="dark">
40
+ <gn-ui-button
41
+ type="primary-light"
42
+ class="inline-block opacity-70"
43
+ extraClass="lowercase text-sm py-1 px-2"
44
+ (buttonClick)="onKeywordClick(keyword)"
45
+ >{{ keyword.label }}</gn-ui-button
46
+ >
47
+ </gn-ui-popover>
37
48
  }
38
49
  </div>
39
50
  </gn-ui-max-lines>
@@ -52,7 +63,7 @@
52
63
  data-test="usage-panel"
53
64
  >
54
65
  <div class="flex flex-col gap-[10px] mr-4 py-[12px] rounded text-gray-900">
55
- @for (license of licenses; track license) {
66
+ @for (license of licenses; track $index) {
56
67
  @if (license.url) {
57
68
  <div class="text-primary">
58
69
  <a
@@ -105,9 +116,29 @@
105
116
  </div>
106
117
  </gn-ui-expandable-panel>
107
118
  }
119
+ @if (metadata.contactsForResource?.length) {
120
+ <gn-ui-expandable-panel
121
+ [title]="'record.metadata.resource.contacts' | translate"
122
+ data-test="contacts-panel"
123
+ >
124
+ <div class="flex flex-col gap-1 pt-3 pb-4">
125
+ @for (group of contactGroups; track group.role) {
126
+ <div class="flex flex-col gap-1 rounded py-4 px-2">
127
+ <p class="text-xs font-normal text-black">
128
+ {{ group.roleLabel | translate }}
129
+ </p>
130
+ <div class="grid gap-1 grid-cols-1 md:grid-cols-2">
131
+ @for (contact of group.contacts; track contact.email) {
132
+ <gn-ui-contact-pill [contact]="contact"></gn-ui-contact-pill>
133
+ }
134
+ </div>
135
+ </div>
136
+ }
137
+ </div>
138
+ </gn-ui-expandable-panel>
139
+ }
108
140
  @if (
109
141
  (metadata.kind === 'dataset' && metadata.lineage) ||
110
- resourceContact ||
111
142
  metadata.resourceCreated ||
112
143
  metadata.resourcePublished ||
113
144
  metadata.resourceUpdated ||
@@ -129,66 +160,6 @@
129
160
  </p>
130
161
  </div>
131
162
  }
132
- @if (resourceContact) {
133
- <div
134
- class="flex flex-row gap-6 mt-5 mb-8 resource-contact"
135
- data-test="details-panel-resource-contact"
136
- >
137
- @if (resourceContact.organization?.logoUrl?.href) {
138
- <div
139
- class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
140
- >
141
- <gn-ui-thumbnail
142
- class="relative h-full w-full"
143
- [thumbnailUrl]="resourceContact.organization.logoUrl.href"
144
- fit="contain"
145
- ></gn-ui-thumbnail>
146
- </div>
147
- }
148
- <div class="flex flex-col gap-1">
149
- <p class="text-sm font-medium" translate>record.metadata.producer</p>
150
- <div
151
- class="text-primary font-title text-21 mr-2 cursor-pointer hover:underline"
152
- data-cy="organization-name"
153
- >
154
- {{ resourceContact.organization?.name }}
155
- </div>
156
- @if (resourceContact.organization?.website) {
157
- <div>
158
- <a
159
- [href]="resourceContact.organization.website"
160
- target="_blank"
161
- class="contact-website text-primary text-sm cursor-pointer hover:underline transition-all"
162
- >{{ resourceContact.organization.website }}
163
- <ng-icon
164
- class="!w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
165
- name="matOpenInNew"
166
- ></ng-icon>
167
- </a>
168
- </div>
169
- }
170
- @if (resourceContact.email) {
171
- <div class="mt-4">
172
- <div class="flex">
173
- <ng-icon
174
- class="!w-5 !h-5 !text-[20px] opacity-75 shrink-0"
175
- name="matMailOutline"
176
- ></ng-icon>
177
- @if (resourceContact.email) {
178
- <a
179
- [href]="'mailto:' + resourceContact.email"
180
- class="text-sm hover:underline ml-2"
181
- target="_blank"
182
- data-cy="contact-email"
183
- >{{ resourceContact?.email }}</a
184
- >
185
- }
186
- </div>
187
- </div>
188
- }
189
- </div>
190
- </div>
191
- }
192
163
  <div
193
164
  class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
194
165
  >
@@ -8,7 +8,10 @@ import {
8
8
  } from '@angular/core'
9
9
  import {
10
10
  CatalogRecord,
11
+ Individual,
11
12
  Keyword,
13
+ Role,
14
+ RoleLabels,
12
15
  } from '../../../../../../libs/common/domain/src/lib/model/record'
13
16
  import { DateService, getTemporalRangeUnion } from '../../../../../../libs/util/shared/src'
14
17
  import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
@@ -16,20 +19,32 @@ import {
16
19
  ExpandablePanelComponent,
17
20
  MaxLinesComponent,
18
21
  } from '../../../../../../libs/ui/layout/src'
19
- import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
22
+ import {
23
+ TranslateDirective,
24
+ TranslatePipe,
25
+ TranslateService,
26
+ } from '@ngx-translate/core'
27
+ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
20
28
  import {
21
29
  BadgeComponent,
30
+ ButtonComponent,
22
31
  CopyTextButtonComponent,
23
32
  } from '../../../../../../libs/ui/inputs/src'
33
+ import { PopoverComponent } from '../../../../../../libs/ui/widgets/src'
24
34
  import { ContentGhostComponent } from '../content-ghost/content-ghost.component'
25
35
  import { NgIcon, provideIcons } from '@ng-icons/core'
26
36
  import { matOpenInNew } from '@ng-icons/material-icons/baseline'
27
37
  import { matMailOutline } from '@ng-icons/material-icons/outline'
28
- import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
29
38
  import { GnUiLinkifyDirective } from './linkify.directive'
30
39
  import { GnUiHumanizeDateDirective } from '../../../../../../libs/util/shared/src'
31
40
 
32
41
  import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
42
+ import { ContactPillComponent } from '../contact-pill/contact-pill.component'
43
+
44
+ marker('domain.record.keywordType.theme')
45
+ marker('domain.record.keywordType.place')
46
+ marker('domain.record.keywordType.temporal')
47
+ marker('domain.record.keywordType.other')
33
48
 
34
49
  @Component({
35
50
  selector: 'gn-ui-metadata-info',
@@ -42,15 +57,17 @@ import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
42
57
  TranslatePipe,
43
58
  MarkdownParserComponent,
44
59
  ExpandablePanelComponent,
60
+ ButtonComponent,
45
61
  BadgeComponent,
46
62
  ContentGhostComponent,
47
- ThumbnailComponent,
48
63
  MaxLinesComponent,
49
64
  CopyTextButtonComponent,
50
65
  NgIcon,
51
66
  GnUiLinkifyDirective,
52
67
  GnUiHumanizeDateDirective,
53
68
  SpatialExtentComponent,
69
+ ContactPillComponent,
70
+ PopoverComponent,
54
71
  ],
55
72
  viewProviders: [
56
73
  provideIcons({
@@ -61,6 +78,7 @@ import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
61
78
  })
62
79
  export class MetadataInfoComponent {
63
80
  private dateService = inject(DateService)
81
+ private translateService = inject(TranslateService)
64
82
 
65
83
  @Input() metadata: Partial<CatalogRecord>
66
84
  @Input() incomplete: boolean
@@ -132,19 +150,49 @@ export class MetadataInfoComponent {
132
150
  return getTemporalRangeUnion(temporalExtents, this.dateService)
133
151
  }
134
152
 
135
- get shownOrganization() {
136
- return this.metadata.ownerOrganization
137
- }
138
-
139
- get resourceContact() {
140
- return this.metadata.contactsForResource?.[0]
141
- }
142
-
143
153
  fieldReady(propName: string) {
144
154
  return !this.incomplete || propName in this.metadata
145
155
  }
146
156
 
157
+ get contactGroups(): {
158
+ role: Role
159
+ roleLabel: string
160
+ contacts: Individual[]
161
+ }[] {
162
+ const groups: { role: Role; roleLabel: string; contacts: Individual[] }[] =
163
+ []
164
+ const indexByRole = new Map<Role, number>()
165
+ for (const contact of this.metadata.contactsForResource ?? []) {
166
+ if (indexByRole.has(contact.role)) {
167
+ groups[indexByRole.get(contact.role)].contacts.push(contact)
168
+ } else {
169
+ indexByRole.set(contact.role, groups.length)
170
+ groups.push({
171
+ role: contact.role,
172
+ roleLabel: RoleLabels.get(contact.role),
173
+ contacts: [contact],
174
+ })
175
+ }
176
+ }
177
+ return groups
178
+ }
179
+
147
180
  onKeywordClick(keyword: Keyword) {
148
181
  this.keyword.emit(keyword)
149
182
  }
183
+
184
+ keywordTooltipSegments(keyword: Keyword): string[] {
185
+ if (keyword.hierarchyPath?.length) {
186
+ return keyword.hierarchyPath
187
+ }
188
+ if (keyword.thesaurus?.name) {
189
+ return [keyword.thesaurus.name, keyword.label]
190
+ }
191
+ return [
192
+ this.translateService.instant(
193
+ `domain.record.keywordType.${keyword.type}`
194
+ ),
195
+ keyword.label,
196
+ ]
197
+ }
150
198
  }
@@ -52,12 +52,11 @@
52
52
  </gn-ui-text-input>
53
53
  @if (!supportOffset) {
54
54
  <div class="flex items-center gap-2 text-orange-500 z-10 ml-3">
55
- <span
56
- class="material-symbols-outlined"
55
+ <ng-icon
56
+ name="matWarningOutline"
57
+ size="24"
57
58
  matTooltip="Not supported on this service"
58
- >
59
- warning
60
- </span>
59
+ ></ng-icon>
61
60
  </div>
62
61
  }
63
62
  </div>
@@ -15,6 +15,8 @@ import {
15
15
  import { CommonModule } from '@angular/common'
16
16
  import { TranslateDirective } from '@ngx-translate/core'
17
17
  import { MatTooltipModule } from '@angular/material/tooltip'
18
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
19
+ import { matWarningOutline } from '@ng-icons/material-icons/outline'
18
20
 
19
21
  const DEFAULT_PARAMS = {
20
22
  OFFSET: '',
@@ -35,7 +37,9 @@ const DEFAULT_PARAMS = {
35
37
  CopyTextButtonComponent,
36
38
  TranslateDirective,
37
39
  MatTooltipModule,
40
+ NgIconComponent,
38
41
  ],
42
+ providers: [provideIcons({ matWarningOutline })],
39
43
  })
40
44
  export class RecordApiFormComponent {
41
45
  @Input() set apiLink(value: DatasetServiceDistribution) {
@@ -25,7 +25,9 @@ export class ButtonComponent {
25
25
  | 'outline'
26
26
  | 'light'
27
27
  | 'gray'
28
+ | 'gray-light'
28
29
  | 'black'
30
+ | 'primary-light'
29
31
  ) {
30
32
  // btn-classes are written in full to be picked up by tailwind
31
33
  switch (value) {
@@ -44,9 +46,15 @@ export class ButtonComponent {
44
46
  case 'gray':
45
47
  this.btnClass = 'gn-ui-btn-gray'
46
48
  break
49
+ case 'gray-light':
50
+ this.btnClass = 'gn-ui-btn-gray-light'
51
+ break
47
52
  case 'black':
48
53
  this.btnClass = 'gn-ui-btn-black'
49
54
  break
55
+ case 'primary-light':
56
+ this.btnClass = 'gn-ui-btn-primary-light'
57
+ break
50
58
  case 'default':
51
59
  default:
52
60
  this.btnClass = 'gn-ui-btn-default'
@@ -2,9 +2,9 @@ import {
2
2
  ChangeDetectionStrategy,
3
3
  Component,
4
4
  EventEmitter,
5
+ inject,
5
6
  Input,
6
7
  Output,
7
- inject,
8
8
  } from '@angular/core'
9
9
  import {
10
10
  DateAdapter,
@@ -52,6 +52,6 @@ export class DatePickerComponent {
52
52
  @Output() dateChange = new EventEmitter<Date>()
53
53
 
54
54
  constructor() {
55
- this.dateAdapter.setLocale(this.translate.currentLang)
55
+ this.dateAdapter.setLocale(this.translate.getCurrentLang())
56
56
  }
57
57
  }
@@ -51,7 +51,7 @@
51
51
  <div
52
52
  class="bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container"
53
53
  [style.max-height]="overlayMaxHeight"
54
- [style.width]="overlayWidth"
54
+ [style.min-width]="overlayMinWidth"
55
55
  role="listbox"
56
56
  tabindex="-1"
57
57
  [attr.id]="id"
@@ -3,12 +3,12 @@ import {
3
3
  Component,
4
4
  ElementRef,
5
5
  EventEmitter,
6
+ inject,
6
7
  Input,
7
8
  Output,
8
9
  QueryList,
9
10
  ViewChild,
10
11
  ViewChildren,
11
- inject,
12
12
  } from '@angular/core'
13
13
  import {
14
14
  CdkConnectedOverlay,
@@ -85,7 +85,7 @@ export class DropdownMultiselectComponent {
85
85
  ]
86
86
  scrollStrategy = this.scrollStrategies.reposition()
87
87
  overlayOpen = false
88
- overlayWidth = 'auto'
88
+ overlayMinWidth = 'none'
89
89
  overlayMaxHeight = 'none'
90
90
  id = `dropdown-multiselect-${Math.floor(Math.random() * 10000)}`
91
91
 
@@ -120,7 +120,7 @@ export class DropdownMultiselectComponent {
120
120
  }
121
121
 
122
122
  openOverlay() {
123
- this.overlayWidth =
123
+ this.overlayMinWidth =
124
124
  this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
125
125
  .width + 'px'
126
126
  this.overlayMaxHeight = this.maxRows
@@ -6,7 +6,7 @@
6
6
  type="url"
7
7
  [value]="inputValue"
8
8
  (input)="handleInput($event)"
9
- (keydown.enter)="handleUpload(input)"
9
+ (keydown.enter)="handleUpload(input, $event)"
10
10
  [placeholder]="placeholder"
11
11
  [attr.aria-label]="placeholder"
12
12
  [disabled]="disabled"
@@ -25,7 +25,7 @@
25
25
  extraClass="absolute inset-y-[var(--side-padding)] right-[var(--side-padding)]"
26
26
  type="primary"
27
27
  [disabled]="disabled || input.value === '' || !isValidUrl(input.value)"
28
- (buttonClick)="handleUpload(input)"
28
+ (buttonClick)="handleUpload(input, $event)"
29
29
  >
30
30
  <ng-content>
31
31
  <ng-icon name="iconoirArrowUp"></ng-icon>
@@ -81,7 +81,8 @@ export class UrlInputComponent implements OnChanges {
81
81
  this.valueChange.next(value)
82
82
  }
83
83
 
84
- handleUpload(element: HTMLInputElement) {
84
+ handleUpload(element: HTMLInputElement, event: Event) {
85
+ event.stopPropagation()
85
86
  const value = element.value
86
87
  if (!value || !this.isValidUrl(value)) return
87
88
  this.uploadClick.next(value)
@@ -3,14 +3,14 @@
3
3
  <span class="flex-none font-bold" translate="">{{ label }}</span>
4
4
  <div class="flex-1 flex justify-end items-center">
5
5
  <ng-content select="[form-field-interaction]"></ng-content>
6
- <span
6
+ <ng-icon
7
7
  *ngIf="hint"
8
- class="material-symbols-outlined m-2 gn-ui-icon-small"
8
+ name="matHelpOutline"
9
+ size="16"
10
+ class="m-2"
9
11
  [matTooltip]="hint"
10
12
  matTooltipPosition="above"
11
- >
12
- help
13
- </span>
13
+ ></ng-icon>
14
14
  </div>
15
15
  </div>
16
16
  <div class="flex-1 mt-2">
@@ -2,6 +2,8 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
2
  import { MatTooltipModule } from '@angular/material/tooltip'
3
3
  import { CommonModule } from '@angular/common'
4
4
  import { TranslateDirective } from '@ngx-translate/core'
5
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
6
+ import { matHelpOutline } from '@ng-icons/material-icons/outline'
5
7
 
6
8
  @Component({
7
9
  selector: 'gn-ui-form-field-wrapper',
@@ -9,7 +11,13 @@ import { TranslateDirective } from '@ngx-translate/core'
9
11
  styleUrls: ['./form-field-wrapper.component.css'],
10
12
  changeDetection: ChangeDetectionStrategy.OnPush,
11
13
  standalone: true,
12
- imports: [MatTooltipModule, CommonModule, TranslateDirective],
14
+ imports: [
15
+ MatTooltipModule,
16
+ CommonModule,
17
+ TranslateDirective,
18
+ NgIconComponent,
19
+ ],
20
+ providers: [provideIcons({ matHelpOutline })],
13
21
  })
14
22
  export class FormFieldWrapperComponent {
15
23
  @Input() label?: string
@@ -37,7 +37,7 @@
37
37
  (click)="handleRowClick(item)"
38
38
  data-cy="table-row"
39
39
  [attr.data-cy-title]="item.title"
40
- [title]="getItemTitle(item) | translate"
40
+ [title]="getItemTitle(item) | translate: { recordKind: item['kind'] }"
41
41
  >
42
42
  <div
43
43
  class="relative h-0"
@@ -16,9 +16,6 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
16
16
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
17
17
  import { Observable, of } from 'rxjs'
18
18
 
19
- marker('editor.record.lock.resourceType')
20
- marker('editor.record.lock.harvested')
21
- marker('editor.record.lock.owner')
22
19
  @Component({
23
20
  selector: 'gn-ui-interactive-table',
24
21
  templateUrl: './interactive-table.component.html',
@@ -53,12 +50,10 @@ export class InteractiveTableComponent {
53
50
 
54
51
  getItemTitle(item: CatalogRecord) {
55
52
  if (!this.isDraftPage) {
56
- if (item.kind !== 'dataset') {
57
- return 'editor.record.lock.resourceType'
58
- } else if (item.extras?.isHarvested) {
59
- return 'editor.record.lock.harvested'
53
+ if (item.extras?.isHarvested) {
54
+ return marker('editor.record.lock.harvested')
60
55
  } else if (!item.extras?.edit) {
61
- return 'editor.record.lock.owner'
56
+ return marker('editor.record.lock.owner')
62
57
  }
63
58
  }
64
59
  return ''
@@ -5,12 +5,12 @@
5
5
  >
6
6
  @for (item of items; track trackByFn(index); let index = $index) {
7
7
  <div class="sortable-box bg-white flex items-center" cdkDrag>
8
- <span
8
+ <ng-icon
9
9
  cdkDragHandle
10
- class="material-symbols-outlined mx-[10px] cursor-grab gn-ui-icon-medium flex-none"
11
- >
12
- drag_handle
13
- </span>
10
+ name="matDragHandleOutline"
11
+ size="20"
12
+ class="mx-[10px] cursor-grab flex-none"
13
+ ></ng-icon>
14
14
  <div class="flex-1">
15
15
  <ng-container
16
16
  *ngTemplateOutlet="
@@ -29,8 +29,8 @@
29
29
  class="ml-[8px] mr-[10px]"
30
30
  (buttonClick)="removeItem(index)"
31
31
  data-test="remove-item"
32
- ><span class="material-symbols-outlined gn-ui-icon-medium">close</span>
33
- </gn-ui-button>
32
+ ><ng-icon name="matCloseOutline" size="20"></ng-icon
33
+ ></gn-ui-button>
34
34
  </div>
35
35
  }
36
36
  </div>
@@ -15,6 +15,11 @@ import {
15
15
  TemplateRef,
16
16
  } from '@angular/core'
17
17
  import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
18
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
19
+ import {
20
+ matCloseOutline,
21
+ matDragHandleOutline,
22
+ } from '@ng-icons/material-icons/outline'
18
23
 
19
24
  @Component({
20
25
  selector: 'gn-ui-sortable-list',
@@ -22,7 +27,15 @@ import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
22
27
  styleUrls: ['sortable-list.component.css'],
23
28
  changeDetection: ChangeDetectionStrategy.OnPush,
24
29
  standalone: true,
25
- imports: [CommonModule, CdkDropList, CdkDrag, CdkDragHandle, ButtonComponent],
30
+ imports: [
31
+ CommonModule,
32
+ CdkDropList,
33
+ CdkDrag,
34
+ CdkDragHandle,
35
+ ButtonComponent,
36
+ NgIconComponent,
37
+ ],
38
+ providers: [provideIcons({ matDragHandleOutline, matCloseOutline })],
26
39
  })
27
40
  export class SortableListComponent {
28
41
  @Input() elementTemplate: TemplateRef<unknown>
@@ -204,11 +204,12 @@ export class MapContainerComponent implements AfterViewInit, OnChanges {
204
204
 
205
205
  async ngOnChanges(changes: SimpleChanges) {
206
206
  if ('context' in changes && !changes['context'].isFirstChange()) {
207
+ const olMap = await this.openlayersMap
207
208
  const diff = computeMapContextDiff(
208
209
  this.processContext(changes['context'].currentValue),
209
210
  this.processContext(changes['context'].previousValue)
210
211
  )
211
- await applyContextDiffToMap(this.olMap, diff)
212
+ await applyContextDiffToMap(olMap, diff)
212
213
 
213
214
  if (this._resolvedExtentChange && diff.viewChanges) {
214
215
  this._resolvedExtentChange.emit(this.calculateCurrentMapExtent())