geonetwork-ui 2.8.0-dev.6ea037ab6 → 2.8.0-dev.7ecc6ee1d

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 (146) hide show
  1. package/esm2022/index.mjs +2 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/common/distribution.mapper.mjs +3 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.mjs +3 -3
  4. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +25 -1
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +7 -7
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +3 -2
  7. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +4 -3
  8. package/esm2022/libs/common/domain/src/index.mjs +3 -0
  9. package/esm2022/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.mjs +1 -1
  10. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +2 -1
  11. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  12. package/esm2022/libs/feature/dataviz/src/index.mjs +2 -1
  13. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +3 -1
  14. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +18 -7
  15. package/esm2022/libs/feature/dataviz/src/lib/stac-view/stac-view.component.mjs +51 -0
  16. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +23 -3
  17. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +2 -2
  18. package/esm2022/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.mjs +13 -4
  19. package/esm2022/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.mjs +23 -8
  20. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +14 -1
  21. package/esm2022/libs/ui/elements/src/index.mjs +2 -1
  22. package/esm2022/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.mjs +37 -0
  23. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +5 -9
  24. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.mjs +5 -5
  25. package/esm2022/libs/util/i18n/src/lib/date-locales.mjs +33 -0
  26. package/esm2022/libs/util/shared/src/index.mjs +2 -1
  27. package/esm2022/libs/util/shared/src/lib/humanize-date.directive.mjs +33 -0
  28. package/esm2022/libs/util/shared/src/lib/links/link-classifier.service.mjs +3 -1
  29. package/esm2022/libs/util/shared/src/lib/services/date.service.mjs +19 -2
  30. package/esm2022/translations/de.json +13 -4
  31. package/esm2022/translations/en.json +13 -4
  32. package/esm2022/translations/es.json +9 -0
  33. package/esm2022/translations/fr.json +13 -4
  34. package/esm2022/translations/it.json +14 -5
  35. package/esm2022/translations/nl.json +9 -0
  36. package/esm2022/translations/pt.json +9 -0
  37. package/esm2022/translations/sk.json +10 -1
  38. package/fesm2022/geonetwork-ui-date-locales-MYnkDJ5h.mjs +35 -0
  39. package/fesm2022/geonetwork-ui-date-locales-MYnkDJ5h.mjs.map +1 -0
  40. package/fesm2022/geonetwork-ui.mjs +345 -116
  41. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  42. package/index.d.ts +1 -0
  43. package/index.d.ts.map +1 -1
  44. package/index.ts +1 -0
  45. package/libs/api/metadata-converter/src/lib/common/distribution.mapper.d.ts.map +1 -1
  46. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  47. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -1
  48. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +5 -1
  49. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  50. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  51. package/libs/common/domain/src/index.d.ts +3 -0
  52. package/libs/common/domain/src/index.d.ts.map +1 -0
  53. package/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.d.ts +1 -1
  54. package/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.d.ts.map +1 -1
  55. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +7 -2
  56. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  57. package/libs/common/domain/src/lib/platform.service.interface.d.ts +1 -1
  58. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  59. package/libs/feature/dataviz/src/index.d.ts +1 -0
  60. package/libs/feature/dataviz/src/index.d.ts.map +1 -1
  61. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts.map +1 -1
  62. package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
  63. package/libs/feature/dataviz/src/lib/stac-view/stac-view.component.d.ts +16 -0
  64. package/libs/feature/dataviz/src/lib/stac-view/stac-view.component.d.ts.map +1 -0
  65. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +2 -0
  66. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  67. package/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.d.ts +3 -2
  68. package/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.d.ts.map +1 -1
  69. package/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.d.ts +3 -2
  70. package/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.d.ts.map +1 -1
  71. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +28 -24
  72. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  73. package/libs/ui/elements/src/index.d.ts +1 -0
  74. package/libs/ui/elements/src/index.d.ts.map +1 -1
  75. package/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.d.ts +8 -0
  76. package/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.d.ts.map +1 -0
  77. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +0 -2
  78. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
  79. package/libs/util/i18n/src/lib/date-locales.d.ts +5 -0
  80. package/libs/util/i18n/src/lib/date-locales.d.ts.map +1 -0
  81. package/libs/util/shared/src/index.d.ts +1 -0
  82. package/libs/util/shared/src/index.d.ts.map +1 -1
  83. package/libs/util/shared/src/lib/humanize-date.directive.d.ts +15 -0
  84. package/libs/util/shared/src/lib/humanize-date.directive.d.ts.map +1 -0
  85. package/libs/util/shared/src/lib/links/link-classifier.service.d.ts.map +1 -1
  86. package/libs/util/shared/src/lib/services/date.service.d.ts +4 -0
  87. package/libs/util/shared/src/lib/services/date.service.d.ts.map +1 -1
  88. package/package.json +1 -1
  89. package/src/libs/api/metadata-converter/src/lib/common/distribution.mapper.ts +1 -0
  90. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +2 -2
  91. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +1 -1
  92. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.service+eaux-usees.ts +1 -1
  93. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +5 -2
  94. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -1
  95. package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +1 -1
  96. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +2 -2
  97. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +1 -1
  98. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.service+napitswallonia.ts +1 -1
  99. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +27 -0
  100. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +13 -6
  101. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +6 -2
  102. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +4 -2
  103. package/src/libs/common/domain/src/index.ts +2 -0
  104. package/src/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.ts +1 -1
  105. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +10 -1
  106. package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -1
  107. package/src/libs/common/fixtures/src/lib/elasticsearch/metadata-links.fixtures.ts +5 -0
  108. package/src/libs/common/fixtures/src/lib/link.fixtures.ts +10 -0
  109. package/src/libs/feature/dataviz/src/index.ts +1 -0
  110. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +1 -0
  111. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +16 -5
  112. package/src/libs/feature/dataviz/src/lib/stac-view/stac-view.component.css +0 -0
  113. package/src/libs/feature/dataviz/src/lib/stac-view/stac-view.component.html +40 -0
  114. package/src/libs/feature/dataviz/src/lib/stac-view/stac-view.component.ts +62 -0
  115. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +3 -3
  116. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +30 -0
  117. package/src/libs/feature/editor/src/lib/fields.config.ts +1 -1
  118. package/src/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts +7 -1
  119. package/src/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.ts +23 -4
  120. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +30 -1
  121. package/src/libs/ui/elements/src/index.ts +1 -0
  122. package/src/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.css +0 -0
  123. package/src/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.html +31 -0
  124. package/src/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.ts +30 -0
  125. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +67 -21
  126. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -9
  127. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.html +1 -1
  128. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.ts +2 -2
  129. package/src/libs/util/i18n/src/lib/date-locales.ts +63 -0
  130. package/src/libs/util/shared/src/index.ts +1 -0
  131. package/src/libs/util/shared/src/lib/humanize-date.directive.ts +35 -0
  132. package/src/libs/util/shared/src/lib/links/link-classifier.service.ts +2 -0
  133. package/src/libs/util/shared/src/lib/services/date.service.ts +27 -1
  134. package/translations/de.json +13 -4
  135. package/translations/en.json +13 -4
  136. package/translations/es.json +9 -0
  137. package/translations/fr.json +13 -4
  138. package/translations/it.json +14 -5
  139. package/translations/nl.json +9 -0
  140. package/translations/pt.json +9 -0
  141. package/translations/sk.json +10 -1
  142. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.mjs +0 -59
  143. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts +0 -11
  144. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts.map +0 -1
  145. package/src/libs/common/domain/src/lib/index.ts +0 -2
  146. package/src/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.ts +0 -54
@@ -3,6 +3,7 @@ import {
3
3
  Component,
4
4
  Inject,
5
5
  Input,
6
+ Optional,
6
7
  } from '@angular/core'
7
8
  import { Configuration } from '../../../../../../libs/data-access/gn4/src'
8
9
  import { MdViewFacade } from '../state'
@@ -10,7 +11,7 @@ import { BehaviorSubject, combineLatest, map } from 'rxjs'
10
11
  import { CopyTextButtonComponent } from '../../../../../../libs/ui/inputs/src'
11
12
  import { CommonModule } from '@angular/common'
12
13
  import { TranslatePipe } from '@ngx-translate/core'
13
- import { GEONETWORK_UI_TAG_NAME } from '../../../../../../libs/util/shared/src'
14
+ import { GEONETWORK_UI_TAG_NAME, PROXY_PATH } from '../../../../../../libs/util/shared/src'
14
15
 
15
16
  @Component({
16
17
  selector: 'gn-ui-data-view-web-component',
@@ -42,7 +43,12 @@ export class DataViewWebComponentComponent {
42
43
  api-url="${new URL(
43
44
  this.config.basePath,
44
45
  window.location.origin
45
- ).toString()}"
46
+ ).toString()}"${
47
+ this.proxyPath
48
+ ? `
49
+ proxy-path="${this.proxyPath}"`
50
+ : ''
51
+ }
46
52
  dataset-id="${metadata.uniqueIdentifier}"
47
53
  aggregation="${aggregation}"
48
54
  x-property="${xProperty}"
@@ -65,7 +71,12 @@ export class DataViewWebComponentComponent {
65
71
  api-url="${new URL(
66
72
  this.config.basePath,
67
73
  window.location.origin
68
- ).toString()}"
74
+ ).toString()}"${
75
+ this.proxyPath
76
+ ? `
77
+ proxy-path="${this.proxyPath}"`
78
+ : ''
79
+ }
69
80
  dataset-id="${metadata.uniqueIdentifier}"
70
81
  primary-color="#0f4395"
71
82
  secondary-color="#8bc832"
@@ -82,7 +93,12 @@ export class DataViewWebComponentComponent {
82
93
  api-url="${new URL(
83
94
  this.config.basePath,
84
95
  window.location.origin
85
- ).toString()}"
96
+ ).toString()}"${
97
+ this.proxyPath
98
+ ? `
99
+ proxy-path="${this.proxyPath}"`
100
+ : ''
101
+ }
86
102
  dataset-id="${metadata.uniqueIdentifier}"
87
103
  primary-color="#0f4395"
88
104
  secondary-color="#8bc832"
@@ -97,6 +113,9 @@ export class DataViewWebComponentComponent {
97
113
 
98
114
  constructor(
99
115
  @Inject(Configuration) private config: Configuration,
116
+ @Optional()
117
+ @Inject(PROXY_PATH)
118
+ private proxyPath: string,
100
119
  private facade: MdViewFacade
101
120
  ) {}
102
121
  }
@@ -20,7 +20,7 @@ import {
20
20
  } from '../../../../../../libs/common/domain/src/lib/model/record'
21
21
  import { AvatarServiceInterface } from '../../../../../../libs/api/repository/src'
22
22
  import { OgcApiRecord } from '@camptocamp/ogc-client'
23
- import { from, of, Observable } from 'rxjs'
23
+ import { from, of } from 'rxjs'
24
24
  import { DataService } from '../../../../../../libs/feature/dataviz/src'
25
25
 
26
26
  @Injectable()
@@ -89,6 +89,25 @@ export class MdViewFacade {
89
89
  shareReplay(1)
90
90
  )
91
91
 
92
+ resourceDoi$ = this.metadata$.pipe(
93
+ map((record) => {
94
+ if (!record?.resourceIdentifiers?.length) return null
95
+ const doiIdentifier = record.resourceIdentifiers.find(
96
+ (id) =>
97
+ id.codeSpace?.toLowerCase().includes('doi.org') ||
98
+ id.code.startsWith('10.')
99
+ )
100
+
101
+ if (!doiIdentifier) return null
102
+
103
+ return {
104
+ code: doiIdentifier.code,
105
+ url: doiIdentifier.url ? doiIdentifier.url : null,
106
+ }
107
+ }),
108
+ shareReplay(1)
109
+ )
110
+
92
111
  apiLinks$ = this.allLinks$.pipe(
93
112
  map((links) =>
94
113
  links.filter((link) => this.linkClassifier.hasUsage(link, LinkUsage.API))
@@ -105,6 +124,16 @@ export class MdViewFacade {
105
124
  shareReplay(1)
106
125
  )
107
126
 
127
+ stacLinks$ = this.allLinks$.pipe(
128
+ map((links) =>
129
+ links.filter(
130
+ (link) =>
131
+ link.type === 'service' && link.accessServiceProtocol === 'stac'
132
+ )
133
+ ),
134
+ shareReplay(1)
135
+ )
136
+
108
137
  downloadLinks$ = this.allLinks$.pipe(
109
138
  map((links) =>
110
139
  links.filter((link) =>
@@ -14,6 +14,7 @@ export * from './lib/markdown-editor/markdown-editor.component'
14
14
  export * from './lib/markdown-parser/markdown-parser.component'
15
15
  export * from './lib/metadata-catalog/metadata-catalog.component'
16
16
  export * from './lib/metadata-contact/metadata-contact.component'
17
+ export * from './lib/metadata-doi/metadata-doi.component'
17
18
  export * from './lib/metadata-info/metadata-info.component'
18
19
  export * from './lib/metadata-quality-item/metadata-quality-item.component'
19
20
  export * from './lib/metadata-quality/metadata-quality.component'
@@ -0,0 +1,31 @@
1
+ <div
2
+ class="border border-gray-300 rounded-lg py-4 px-5 text-black flex justify-between items-center gap-4"
3
+ >
4
+ <div class="overflow-hidden flex-1">
5
+ <p class="text-base font-medium mb-3">DOI</p>
6
+ <p
7
+ class="text-base font-medium overflow-hidden text-ellipsis whitespace-nowrap"
8
+ [title]="code"
9
+ >
10
+ {{ code }}
11
+ </p>
12
+ </div>
13
+ <div class="flex gap-2 items-start">
14
+ <gn-ui-copy-text-button
15
+ [text]="code"
16
+ [displayText]="false"
17
+ [tooltipText]="'record.metadata.doi.copy' | translate"
18
+ class="[&>div]:flex [&>div]:items-center [&>div]:justify-center [&_button]:w-[40px] [&_button]:h-[32px] [&_button]:flex [&_button]:items-center [&_button]:justify-center [&_button]:hover:bg-gray-100 [&_button]:rounded-lg [&_button]:transition-colors [&_button]:border [&_button]:border-gray-300 [&_button]:px-2 [&_button]:py-1 [&_ng-icon]:w-5 [&_ng-icon]:h-5"
19
+ ></gn-ui-copy-text-button>
20
+ <a
21
+ *ngIf="link"
22
+ [href]="link"
23
+ target="_blank"
24
+ rel="noopener noreferrer"
25
+ class="w-[40px] h-[32px] flex items-center justify-center hover:bg-gray-100 rounded-lg transition-colors border border-gray-300 px-2 py-1"
26
+ [matTooltip]="'record.metadata.doi.open' | translate"
27
+ >
28
+ <ng-icon name="matOpenInNew" size="20"></ng-icon>
29
+ </a>
30
+ </div>
31
+ </div>
@@ -0,0 +1,30 @@
1
+ import { Component, Input } from '@angular/core'
2
+ import { CommonModule } from '@angular/common'
3
+ import { NgIcon, provideIcons } from '@ng-icons/core'
4
+ import { MatTooltipModule } from '@angular/material/tooltip'
5
+ import { matOpenInNew } from '@ng-icons/material-icons/baseline'
6
+ import { TranslatePipe } from '@ngx-translate/core'
7
+ import { CopyTextButtonComponent } from '../../../../../../libs/ui/inputs/src'
8
+
9
+ @Component({
10
+ selector: 'gn-ui-metadata-doi',
11
+ standalone: true,
12
+ imports: [
13
+ CommonModule,
14
+ MatTooltipModule,
15
+ NgIcon,
16
+ TranslatePipe,
17
+ CopyTextButtonComponent,
18
+ ],
19
+ templateUrl: './metadata-doi.component.html',
20
+ styleUrl: './metadata-doi.component.css',
21
+ viewProviders: [
22
+ provideIcons({
23
+ matOpenInNew,
24
+ }),
25
+ ],
26
+ })
27
+ export class MetadataDoiComponent {
28
+ @Input() code!: string
29
+ @Input() link?: string
30
+ }
@@ -3,7 +3,11 @@
3
3
  ghostClass="h-[178px]"
4
4
  [showContent]="fieldReady('abstract')"
5
5
  >
6
- <gn-ui-max-lines [maxLines]="6" *ngIf="metadata.abstract">
6
+ <gn-ui-max-lines
7
+ [maxLines]="6"
8
+ *ngIf="metadata.abstract"
9
+ data-test="metadata-info-abstract"
10
+ >
7
11
  <div class="mb-6">
8
12
  <gn-ui-markdown-parser
9
13
  [textContent]="metadata.abstract"
@@ -101,19 +105,31 @@
101
105
  <gn-ui-expandable-panel
102
106
  *ngIf="
103
107
  (metadata.kind === 'dataset' && metadata.lineage) ||
108
+ resourceContact ||
109
+ metadata.resourceCreated ||
110
+ metadata.resourcePublished ||
104
111
  metadata.resourceUpdated ||
105
- metadata.updateFrequency ||
106
- (metadata.kind === 'dataset' && metadata.status)
112
+ (metadata.kind === 'dataset' && metadata.updateFrequency) ||
113
+ metadata.otherLanguages?.length ||
114
+ (metadata.kind === 'dataset' && temporalExtent)
107
115
  "
108
116
  [title]="'record.metadata.details' | translate"
109
117
  data-test="details-panel"
110
118
  >
111
- <div *ngIf="metadata.lineage" class="text-gray-900 flex flex-col mt-4 gap-2">
119
+ <div
120
+ *ngIf="metadata.kind === 'dataset' && metadata.lineage"
121
+ class="text-gray-900 flex flex-col mt-4 gap-2"
122
+ data-test="details-panel-lineage"
123
+ >
112
124
  <p class="whitespace-pre-line break-words text-gray-900" gnUiLinkify>
113
125
  {{ metadata.lineage }}
114
126
  </p>
115
127
  </div>
116
- <div class="flex flex-row gap-6 mt-5 mb-8" *ngIf="resourceContact">
128
+ <div
129
+ class="flex flex-row gap-6 mt-5 mb-8 resource-contact"
130
+ *ngIf="resourceContact"
131
+ data-test="details-panel-resource-contact"
132
+ >
117
133
  <div
118
134
  *ngIf="resourceContact.organization?.logoUrl?.href"
119
135
  class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
@@ -165,19 +181,40 @@
165
181
  <div
166
182
  class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
167
183
  >
168
- <div *ngIf="metadata.resourceCreated">
184
+ <div
185
+ *ngIf="metadata.resourceCreated"
186
+ data-test="details-panel-resource-created"
187
+ >
169
188
  <p class="text-sm" translate>record.metadata.creation</p>
170
- <p class="text-primary font-medium mt-1">
171
- {{ formatDate(metadata.resourceCreated) }}
172
- </p>
189
+ <p
190
+ class="text-primary font-medium mt-1 resource-created"
191
+ [gnUiHumanizeDate]="metadata.resourceCreated"
192
+ ></p>
173
193
  </div>
174
- <div *ngIf="metadata.resourcePublished">
194
+ <div
195
+ *ngIf="metadata.resourcePublished"
196
+ data-test="details-panel-resource-published"
197
+ >
175
198
  <p class="text-sm" translate>record.metadata.publication</p>
176
- <p class="text-primary font-medium mt-1">
177
- {{ formatDate(metadata.resourcePublished) }}
178
- </p>
199
+ <p
200
+ class="text-primary font-medium mt-1 resource-published"
201
+ [gnUiHumanizeDate]="metadata.resourcePublished"
202
+ ></p>
203
+ </div>
204
+ <div
205
+ *ngIf="metadata.resourceUpdated"
206
+ data-test="details-panel-resource-updated"
207
+ >
208
+ <p class="text-sm" translate>record.metadata.update</p>
209
+ <p
210
+ class="text-primary font-medium mt-1 resource-updated"
211
+ [gnUiHumanizeDate]="metadata.resourceUpdated"
212
+ ></p>
179
213
  </div>
180
- <div *ngIf="updateFrequency">
214
+ <div
215
+ *ngIf="metadata.kind === 'dataset' && metadata.updateFrequency"
216
+ data-test="details-panel-update-frequency"
217
+ >
181
218
  <p class="text-sm" translate>record.metadata.updateFrequency</p>
182
219
  <p
183
220
  class="text-primary font-medium mt-1 updateFrequency"
@@ -187,11 +224,14 @@
187
224
  {{ updateFrequency }}
188
225
  </p>
189
226
  </div>
190
- <div *ngIf="metadata.otherLanguages?.length">
227
+ <div
228
+ *ngIf="metadata.otherLanguages?.length"
229
+ data-test="details-panel-other-languages"
230
+ >
191
231
  <p class="text-sm mb-1" translate>record.metadata.languages</p>
192
232
  <div class="flex flex-row gap-1 flex-wrap">
193
233
  <p
194
- class="text-primary font-medium"
234
+ class="text-primary font-medium other-languages"
195
235
  translate
196
236
  *ngFor="let language of metadata.otherLanguages"
197
237
  >
@@ -199,9 +239,14 @@
199
239
  </p>
200
240
  </div>
201
241
  </div>
202
- <div *ngIf="temporalExtent">
242
+ <div
243
+ *ngIf="metadata.kind === 'dataset' && temporalExtent"
244
+ data-test="details-panel-temporal-extent"
245
+ >
203
246
  <p class="text-sm" translate>record.metadata.temporalExtent</p>
204
- <div class="flex flex-row gap-1 mb-1 text-primary font-medium">
247
+ <div
248
+ class="flex flex-row gap-1 mb-1 text-primary font-medium temporal-extent"
249
+ >
205
250
  <p
206
251
  *ngIf="temporalExtent.start && temporalExtent.end"
207
252
  translate
@@ -252,9 +297,10 @@
252
297
  <div class="flex flex-col gap-4 mr-4 py-5 rounded text-gray-700">
253
298
  <div *ngIf="metadata.recordUpdated">
254
299
  <p class="text-sm" translate>record.metadata.updatedOn</p>
255
- <p class="text-primary font-medium">
256
- {{ metadata.recordUpdated && formatDateTime(metadata.recordUpdated) }}
257
- </p>
300
+ <p
301
+ class="text-primary font-medium"
302
+ [gnUiHumanizeDate]="metadata.recordUpdated"
303
+ ></p>
258
304
  </div>
259
305
  <div *ngIf="metadata.landingPage">
260
306
  <p class="text-sm" translate>record.metadata.sheet</p>
@@ -26,7 +26,7 @@ import { matOpenInNew } from '@ng-icons/material-icons/baseline'
26
26
  import { matMailOutline } from '@ng-icons/material-icons/outline'
27
27
  import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
28
28
  import { GnUiLinkifyDirective } from './linkify.directive'
29
-
29
+ import { GnUiHumanizeDateDirective } from '../../../../../../libs/util/shared/src'
30
30
  import { CommonModule } from '@angular/common'
31
31
  import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
32
32
 
@@ -49,6 +49,7 @@ import { SpatialExtentComponent } from '../../../../../../libs/ui/map/src'
49
49
  CopyTextButtonComponent,
50
50
  NgIcon,
51
51
  GnUiLinkifyDirective,
52
+ GnUiHumanizeDateDirective,
52
53
  SpatialExtentComponent,
53
54
  ],
54
55
  viewProviders: [
@@ -146,12 +147,4 @@ export class MetadataInfoComponent {
146
147
  onKeywordClick(keyword: Keyword) {
147
148
  this.keyword.emit(keyword)
148
149
  }
149
-
150
- formatDate(date: Date): string {
151
- return this.dateService.formatDate(date)
152
- }
153
-
154
- formatDateTime(date: Date): string {
155
- return this.dateService.formatDateTime(date)
156
- }
157
150
  }
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <div class="p-4 flex flex-col">
15
15
  <span>{{ userFeedbackParent.authorName }}</span>
16
- <span> {{ userFeedbackParent.date | timeSince }}</span>
16
+ <span [gnUiHumanizeDate]="userFeedbackParent.date"></span>
17
17
  </div>
18
18
  </div>
19
19
  <div data-cy="commentText" class="mt-4 whitespace-pre-line">
@@ -11,13 +11,13 @@ import {
11
11
  UserFeedbackViewModel,
12
12
  } from '../../../../../../libs/common/domain/src/lib/model/record'
13
13
  import { UserModel } from '../../../../../../libs/common/domain/src/lib/model/user'
14
- import { TimeSincePipe } from './time-since.pipe'
15
14
  import { CommonModule } from '@angular/common'
16
15
  import { ButtonComponent, TextAreaComponent } from '../../../../../../libs/ui/inputs/src'
17
16
  import { TranslatePipe } from '@ngx-translate/core'
18
17
  import { SpinningLoaderComponent } from '../../../../../../libs/ui/widgets/src'
19
18
  import { NgIcon, provideIcons } from '@ng-icons/core'
20
19
  import { matSendOutline } from '@ng-icons/material-icons/outline'
20
+ import { GnUiHumanizeDateDirective } from '../../../../../../libs/util/shared/src'
21
21
 
22
22
  @Component({
23
23
  selector: 'gn-ui-user-feedback-item',
@@ -27,11 +27,11 @@ import { matSendOutline } from '@ng-icons/material-icons/outline'
27
27
  standalone: true,
28
28
  imports: [
29
29
  CommonModule,
30
- TimeSincePipe,
31
30
  TextAreaComponent,
32
31
  TranslatePipe,
33
32
  ButtonComponent,
34
33
  SpinningLoaderComponent,
34
+ GnUiHumanizeDateDirective,
35
35
  NgIcon,
36
36
  ],
37
37
  viewProviders: [
@@ -0,0 +1,63 @@
1
+ import { LanguageCode2 } from './language-codes'
2
+ import {
3
+ ar,
4
+ az,
5
+ ca,
6
+ cs,
7
+ cy,
8
+ da,
9
+ de,
10
+ enUS,
11
+ es,
12
+ fi,
13
+ fr,
14
+ hy,
15
+ is,
16
+ it,
17
+ ka,
18
+ ko,
19
+ Locale,
20
+ nl,
21
+ nn,
22
+ pl,
23
+ pt,
24
+ ru,
25
+ sk,
26
+ sv,
27
+ tr,
28
+ uk,
29
+ zhCN,
30
+ } from 'date-fns/locale'
31
+
32
+ // all 2-char language codes should be listed here
33
+ const locales: Record<LanguageCode2, Locale> = {
34
+ en: enUS,
35
+ nl: nl,
36
+ fr: fr,
37
+ de: de,
38
+ ko: ko,
39
+ es: es,
40
+ cs: cs,
41
+ ca: ca,
42
+ fi: fi,
43
+ is: is,
44
+ it: it,
45
+ pt: pt,
46
+ ru: ru,
47
+ zh: zhCN,
48
+ sk: sk,
49
+ ar: ar,
50
+ da: da,
51
+ no: nn,
52
+ pl: pl,
53
+ sv: sv,
54
+ tr: tr,
55
+ hy: hy,
56
+ az: az,
57
+ ka: ka,
58
+ uk: uk,
59
+ cy: cy,
60
+ rm: enUS, // locale is unavailable
61
+ }
62
+
63
+ export default locales
@@ -4,3 +4,4 @@ export * from './lib/links'
4
4
  export * from './lib/image-fallback.directive'
5
5
  export * from './lib/gn-ui-version'
6
6
  export * from './lib/record'
7
+ export * from './lib/humanize-date.directive'
@@ -0,0 +1,35 @@
1
+ import { Renderer2, Directive, ElementRef, Input, OnInit } from '@angular/core'
2
+ import { DateService } from './services/date.service'
3
+
4
+ @Directive({
5
+ selector: '[gnUiHumanizeDate]',
6
+ standalone: true,
7
+ })
8
+ export class GnUiHumanizeDateDirective implements OnInit {
9
+ @Input() gnUiHumanizeDate: Date | string
10
+
11
+ constructor(
12
+ private dateService: DateService,
13
+ private el: ElementRef,
14
+ private renderer: Renderer2
15
+ ) {}
16
+
17
+ async ngOnInit() {
18
+ await this.updateElement()
19
+ }
20
+
21
+ private async updateElement(): Promise<void> {
22
+ const dateValue = this.gnUiHumanizeDate
23
+
24
+ const fullDateTime = this.dateService.formatDateTime(dateValue)
25
+ const relativeDate =
26
+ await this.dateService.formatRelativeDateTime(dateValue)
27
+
28
+ this.renderer.setAttribute(this.el.nativeElement, 'title', fullDateTime)
29
+ this.renderer.setProperty(
30
+ this.el.nativeElement,
31
+ 'textContent',
32
+ relativeDate
33
+ )
34
+ }
35
+ }
@@ -41,6 +41,8 @@ export class LinkClassifierService {
41
41
  return [LinkUsage.API]
42
42
  case 'postgis':
43
43
  return [LinkUsage.UNKNOWN]
44
+ case 'stac':
45
+ return [LinkUsage.API]
44
46
  default:
45
47
  return [LinkUsage.UNKNOWN]
46
48
  }
@@ -1,10 +1,18 @@
1
1
  import { Injectable } from '@angular/core'
2
2
  import { TranslateService } from '@ngx-translate/core'
3
+ import { type Locale } from 'date-fns/locale'
4
+ import { formatDistance } from 'date-fns/formatDistance'
5
+
6
+ const DEFAULT_LANGUAGE = 'en'
3
7
 
4
8
  @Injectable({
5
9
  providedIn: 'root',
6
10
  })
7
11
  export class DateService {
12
+ dateLocales = import('../../../../../../libs/util/i18n/src/lib/date-locales').then(
13
+ (obj) => obj.default
14
+ )
15
+
8
16
  constructor(private translateService: TranslateService) {}
9
17
 
10
18
  private getDateObject(date: Date | string): Date {
@@ -22,11 +30,17 @@ export class DateService {
22
30
  locale: string
23
31
  dateObj: Date
24
32
  } {
25
- const locale = this.translateService.currentLang || 'en-US'
33
+ const locale = this.translateService.currentLang || DEFAULT_LANGUAGE
26
34
  const dateObj = this.getDateObject(date)
27
35
  return { locale, dateObj }
28
36
  }
29
37
 
38
+ private async getDateLocale(): Promise<Locale> {
39
+ const lang = this.translateService.currentLang || DEFAULT_LANGUAGE
40
+ const locales = await this.dateLocales
41
+ return locales[lang]
42
+ }
43
+
30
44
  formatDate(
31
45
  date: Date | string,
32
46
  options?: Intl.DateTimeFormatOptions
@@ -42,4 +56,16 @@ export class DateService {
42
56
  const { locale, dateObj } = this.getLocaleAndDate(date)
43
57
  return dateObj.toLocaleString(locale, options)
44
58
  }
59
+
60
+ async formatRelativeDateTime(date: Date | string): Promise<string> {
61
+ const dateObj = this.getDateObject(date)
62
+
63
+ const now = new Date()
64
+ const locale = await this.getDateLocale()
65
+
66
+ return formatDistance(dateObj, now, {
67
+ addSuffix: true,
68
+ locale: locale,
69
+ })
70
+ }
45
71
  }
@@ -419,6 +419,7 @@
419
419
  "record.metadata.api.accessServiceProtocol.ogcFeatures": "",
420
420
  "record.metadata.api.accessServiceProtocol.other": "",
421
421
  "record.metadata.api.accessServiceProtocol.postgis": "",
422
+ "record.metadata.api.accessServiceProtocol.stac": "",
422
423
  "record.metadata.api.accessServiceProtocol.tms": "",
423
424
  "record.metadata.api.accessServiceProtocol.wfs": "",
424
425
  "record.metadata.api.accessServiceProtocol.wms": "",
@@ -460,6 +461,8 @@
460
461
  "record.metadata.contact": "Kontakt",
461
462
  "record.metadata.creation": "Erstellungsdatum",
462
463
  "record.metadata.details": "Über die Daten",
464
+ "record.metadata.doi.copy": "",
465
+ "record.metadata.doi.open": "",
463
466
  "record.metadata.download": "Downloads",
464
467
  "record.metadata.feature.catalog": "",
465
468
  "record.metadata.formats": "Formate",
@@ -508,9 +511,9 @@
508
511
  "record.metadata.quality.updateFrequency.failed": "Aktualisierungsfrequenz nicht angegeben",
509
512
  "record.metadata.quality.updateFrequency.success": "Aktualisierungsfrequenz angegeben",
510
513
  "record.metadata.related": "Entdecken Sie den Katalog",
511
- "record.metadata.resourceCreated": "Erstellt am {date}",
512
- "record.metadata.resourcePublished": "Veröffentlicht am {date}",
513
- "record.metadata.resourceUpdated": "Zuletzt aktualisiert am {date}",
514
+ "record.metadata.resourceCreated": "Erstellt",
515
+ "record.metadata.resourcePublished": "Veröffentlicht",
516
+ "record.metadata.resourceUpdated": "Zuletzt aktualisiert",
514
517
  "record.metadata.ressources.and.links": "Ressourcen und Links",
515
518
  "record.metadata.sheet": "Weitere Informationen verfügbar unter:",
516
519
  "record.metadata.status": "Status",
@@ -523,8 +526,9 @@
523
526
  "record.metadata.title": "Titel",
524
527
  "record.metadata.topics": "Kategorien",
525
528
  "record.metadata.uniqueId": "Eindeutige Kennung",
529
+ "record.metadata.update": "Aktualisierungsdatum",
526
530
  "record.metadata.updateFrequency": "Aktualisierungsfrequenz der Daten",
527
- "record.metadata.updatedOn": "Geändert am",
531
+ "record.metadata.updatedOn": "Informationen geändert",
528
532
  "record.metadata.usage": "Nutzung und Einschränkungen",
529
533
  "record.metadata.userFeedbacks": "",
530
534
  "record.metadata.userFeedbacks.anonymousUser": "",
@@ -539,6 +543,7 @@
539
543
  "record.tab.chart": "Diagramm",
540
544
  "record.tab.data": "Tabelle",
541
545
  "record.tab.map": "Karte",
546
+ "record.tab.stac": "",
542
547
  "record.was.created.time": "erstellte diesen Ressource {time}",
543
548
  "records": "Datensätze",
544
549
  "results.layout.selectOne": "Layout auswählen",
@@ -630,6 +635,10 @@
630
635
  "service.metadata.spatialExtent": "",
631
636
  "share.tab.permalink": "Teilen",
632
637
  "share.tab.webComponent": "Integrieren",
638
+ "stac.filter.from": "",
639
+ "stac.filter.period": "",
640
+ "stac.filter.reset": "",
641
+ "stac.filter.to": "",
633
642
  "table.loading.data": "Daten werden geladen...",
634
643
  "table.object.count": "Objekte in diesem Datensatz",
635
644
  "table.paginator.firstPage": "Erste Seite",