geonetwork-ui 2.6.0-dev.01d2b5fc0 → 2.6.0-dev.4fa0a0afc

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 (91) hide show
  1. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +18 -11
  2. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  3. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +3 -3
  4. package/esm2022/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.mjs +2 -2
  5. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +2 -1
  6. package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +3 -3
  7. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-map-container/form-field-map-container.component.mjs +1 -1
  8. package/esm2022/libs/feature/map/src/lib/map-state-container/map-state-container.component.mjs +2 -2
  9. package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +2 -4
  10. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +40 -14
  11. package/esm2022/libs/ui/elements/src/lib/api-card/api-card.component.mjs +27 -6
  12. package/esm2022/libs/ui/elements/src/lib/download-item/download-item.component.mjs +22 -6
  13. package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +3 -3
  14. package/esm2022/libs/ui/elements/src/lib/link-card/link-card.component.mjs +29 -7
  15. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +3 -2
  16. package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
  17. package/esm2022/libs/ui/map/src/lib/components/map-container/map-container.component.mjs +14 -3
  18. package/esm2022/libs/ui/map/src/lib/components/map-legend/map-legend.component.mjs +5 -1
  19. package/esm2022/libs/util/data-fetcher/src/lib/data-fetcher.mjs +6 -2
  20. package/esm2022/libs/util/data-fetcher/src/lib/model.mjs +4 -1
  21. package/esm2022/libs/util/data-fetcher/src/lib/readers/wfs.mjs +30 -2
  22. package/esm2022/libs/util/shared/src/lib/links/link-utils.mjs +21 -19
  23. package/esm2022/translations/de.json +1 -0
  24. package/esm2022/translations/en.json +2 -1
  25. package/esm2022/translations/es.json +1 -0
  26. package/esm2022/translations/fr.json +1 -0
  27. package/esm2022/translations/it.json +1 -0
  28. package/esm2022/translations/nl.json +1 -0
  29. package/esm2022/translations/pt.json +1 -0
  30. package/fesm2022/geonetwork-ui.mjs +221 -75
  31. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  32. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +1 -0
  33. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  34. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +18 -2
  35. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  36. package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
  37. package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts +1 -1
  38. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
  39. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +7 -2
  40. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  41. package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts +9 -1
  42. package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts.map +1 -1
  43. package/libs/ui/elements/src/lib/download-item/download-item.component.d.ts +8 -1
  44. package/libs/ui/elements/src/lib/download-item/download-item.component.d.ts.map +1 -1
  45. package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts +10 -2
  46. package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts.map +1 -1
  47. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
  48. package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts +4 -2
  49. package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts.map +1 -1
  50. package/libs/ui/map/src/lib/components/map-legend/map-legend.component.d.ts.map +1 -1
  51. package/libs/util/data-fetcher/src/lib/data-fetcher.d.ts.map +1 -1
  52. package/libs/util/data-fetcher/src/lib/model.d.ts +3 -2
  53. package/libs/util/data-fetcher/src/lib/model.d.ts.map +1 -1
  54. package/libs/util/data-fetcher/src/lib/readers/wfs.d.ts +1 -0
  55. package/libs/util/data-fetcher/src/lib/readers/wfs.d.ts.map +1 -1
  56. package/libs/util/shared/src/lib/links/link-utils.d.ts +16 -16
  57. package/libs/util/shared/src/lib/links/link-utils.d.ts.map +1 -1
  58. package/package.json +1 -1
  59. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +20 -12
  60. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +17 -1
  61. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +18 -2
  62. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.html +1 -0
  63. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +1 -0
  64. package/src/libs/feature/dataviz/src/lib/table-view/table-view.component.html +10 -8
  65. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +1 -3
  66. package/src/libs/feature/record/src/lib/map-view/map-view.component.html +1 -0
  67. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +36 -7
  68. package/src/libs/ui/elements/src/lib/api-card/api-card.component.html +64 -38
  69. package/src/libs/ui/elements/src/lib/api-card/api-card.component.ts +26 -2
  70. package/src/libs/ui/elements/src/lib/download-item/download-item.component.html +17 -17
  71. package/src/libs/ui/elements/src/lib/download-item/download-item.component.ts +20 -2
  72. package/src/libs/ui/elements/src/lib/downloads-list/downloads-list.component.html +1 -0
  73. package/src/libs/ui/elements/src/lib/link-card/link-card.component.html +27 -29
  74. package/src/libs/ui/elements/src/lib/link-card/link-card.component.ts +33 -3
  75. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +2 -1
  76. package/src/libs/ui/layout/src/lib/carousel/carousel.component.css +0 -4
  77. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +14 -0
  78. package/src/libs/ui/map/src/lib/components/map-legend/map-legend.component.ts +3 -0
  79. package/src/libs/util/data-fetcher/src/lib/data-fetcher.ts +3 -1
  80. package/src/libs/util/data-fetcher/src/lib/model.ts +11 -1
  81. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +29 -3
  82. package/src/libs/util/shared/src/lib/links/link-utils.ts +20 -18
  83. package/tailwind.base.css +29 -1
  84. package/translations/de.json +1 -0
  85. package/translations/en.json +2 -1
  86. package/translations/es.json +1 -0
  87. package/translations/fr.json +1 -0
  88. package/translations/it.json +1 -0
  89. package/translations/nl.json +1 -0
  90. package/translations/pt.json +1 -0
  91. package/translations/sk.json +1 -0
@@ -187,8 +187,24 @@ As such, **it is not very interesting at all.**`,
187
187
  ],
188
188
  code: '',
189
189
  aliases: '',
190
- typeName: "Catalogue d'attributs",
191
- definition: '',
190
+ typeName: "Catalogue d'attributs N°1",
191
+ definition: 'Définition du catalogue d attributs N°1',
192
+ isAbstract: 'false',
193
+ },
194
+ {
195
+ attributeTable: [
196
+ {
197
+ code: 'UniqueObject',
198
+ name: 'unique object ',
199
+ link: '',
200
+ definition: 'this is the only object of this catalog',
201
+ type: 'String (50)',
202
+ },
203
+ ],
204
+ code: '',
205
+ aliases: '',
206
+ typeName: "Catalogue d'attributs N°2",
207
+ definition: 'Définition du catalogue d attributs N°2',
192
208
  isAbstract: 'false',
193
209
  },
194
210
  ],
@@ -40,6 +40,7 @@
40
40
  class="relative h-full mt-2 bg-white border border-gray-300 rounded-lg overflow-hidden"
41
41
  >
42
42
  <gn-ui-chart
43
+ *ngIf="!error"
43
44
  [data]="chartData$ | async"
44
45
  [type]="chartType$.value"
45
46
  [labelProperty]="labelProperty"
@@ -30,6 +30,7 @@ import {
30
30
 
31
31
  marker('wfs.unreachable.cors')
32
32
  marker('wfs.unreachable.http')
33
+ marker('dataset.error.forbidden')
33
34
  marker('wfs.unreachable.unknown')
34
35
  marker('wfs.featuretype.notfound')
35
36
  marker('wfs.geojsongml.notsupported')
@@ -11,13 +11,15 @@
11
11
  class="absolute inset-0"
12
12
  [message]="'table.loading.data' | translate"
13
13
  ></gn-ui-loading-mask>
14
- <gn-ui-popup-alert
15
- *ngIf="error"
16
- type="warning"
17
- icon="matErrorOutlineOutline"
18
- class="absolute m-2 inset-0"
19
- >
20
- <span translate>{{ error }}</span>
21
- </gn-ui-popup-alert>
14
+ <ng-content *ngIf="error">
15
+ <div class="border border-gray-300 rounded-lg bg-white h-full"></div>
16
+ <gn-ui-popup-alert
17
+ type="warning"
18
+ icon="matErrorOutlineOutline"
19
+ class="absolute m-2 inset-0"
20
+ >
21
+ <span translate>{{ error }}</span>
22
+ </gn-ui-popup-alert>
23
+ </ng-content>
22
24
  </div>
23
25
  </div>
@@ -1,7 +1,6 @@
1
1
  import { Injectable } from '@angular/core'
2
2
  import { extend, Extent } from 'ol/extent'
3
3
  import GeoJSON from 'ol/format/GeoJSON'
4
- import { transformExtent } from 'ol/proj'
5
4
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
6
5
 
7
6
  const GEOJSON = new GeoJSON()
@@ -15,7 +14,7 @@ export class MapUtilsService {
15
14
  return null
16
15
  }
17
16
  // extend all the spatial extents into an including bbox
18
- const totalExtent = record.spatialExtents.reduce(
17
+ return record.spatialExtents.reduce(
19
18
  (prev, curr) => {
20
19
  if ('bbox' in curr) return extend(prev, curr.bbox)
21
20
  else if ('geometry' in curr) {
@@ -26,6 +25,5 @@ export class MapUtilsService {
26
25
  },
27
26
  [Infinity, Infinity, -Infinity, -Infinity]
28
27
  )
29
- return transformExtent(totalExtent, 'EPSG:4326', 'EPSG:3857')
30
28
  }
31
29
  }
@@ -31,6 +31,7 @@
31
31
  #mapContainer
32
32
  [context]="mapContext$ | async"
33
33
  (featuresClick)="onMapFeatureSelect($event)"
34
+ (sourceLoadError)="onSourceLoadError($event)"
34
35
  ></gn-ui-map-container>
35
36
  <div
36
37
  class="top-[1em] right-[1em] p-3 bg-white absolute overflow-y-auto overflow-x-hidden max-h-72 w-56"
@@ -34,6 +34,7 @@ import {
34
34
  createViewFromLayer,
35
35
  MapContext,
36
36
  MapContextLayer,
37
+ SourceLoadErrorEvent,
37
38
  } from '@geospatial-sdk/core'
38
39
  import {
39
40
  FeatureDetailComponent,
@@ -49,13 +50,14 @@ import {
49
50
  ButtonComponent,
50
51
  DropdownSelectorComponent,
51
52
  } from '../../../../../../libs/ui/inputs/src'
52
- import { TranslateModule } from '@ngx-translate/core'
53
+ import { TranslateModule, TranslateService } from '@ngx-translate/core'
53
54
  import { ExternalViewerButtonComponent } from '../external-viewer-button/external-viewer-button.component'
54
55
  import {
55
56
  LoadingMaskComponent,
56
57
  PopupAlertComponent,
57
58
  } from '../../../../../../libs/ui/widgets/src'
58
59
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
60
+ import { FetchError } from '../../../../../../libs/util/data-fetcher/src'
59
61
 
60
62
  marker('map.dropdown.placeholder')
61
63
  marker('wfs.feature.limit')
@@ -100,9 +102,6 @@ export class MapViewComponent implements AfterViewInit {
100
102
 
101
103
  onLegendStatusChange(status: boolean) {
102
104
  this.legendExists = status
103
- if (!status) {
104
- this.showLegend = false
105
- }
106
105
  }
107
106
 
108
107
  compatibleMapLinks$ = combineLatest([
@@ -149,8 +148,7 @@ export class MapViewComponent implements AfterViewInit {
149
148
  return this.getLayerFromLink(link).pipe(
150
149
  map((layer) => [layer]),
151
150
  catchError((e) => {
152
- this.error = e.message
153
- console.warn(e.stack || e.message)
151
+ this.handleError(e)
154
152
  return of([])
155
153
  }),
156
154
  finalize(() => (this.loading = false))
@@ -192,7 +190,8 @@ export class MapViewComponent implements AfterViewInit {
192
190
  private mdViewFacade: MdViewFacade,
193
191
  private mapUtils: MapUtilsService,
194
192
  private dataService: DataService,
195
- private changeRef: ChangeDetectorRef
193
+ private changeRef: ChangeDetectorRef,
194
+ private translateService: TranslateService
196
195
  ) {}
197
196
 
198
197
  async ngAfterViewInit() {
@@ -210,6 +209,16 @@ export class MapViewComponent implements AfterViewInit {
210
209
  this.changeRef.detectChanges()
211
210
  }
212
211
 
212
+ onSourceLoadError(error: SourceLoadErrorEvent) {
213
+ if (error.httpStatus === 403 || error.httpStatus === 401) {
214
+ this.error = this.translateService.instant(`dataset.error.forbidden`)
215
+ } else {
216
+ this.error = this.translateService.instant(`dataset.error.http`, {
217
+ info: error.httpStatus,
218
+ })
219
+ }
220
+ }
221
+
213
222
  resetSelection(): void {
214
223
  if (this.selection) {
215
224
  // FIXME: restore styling of selected feature
@@ -255,4 +264,24 @@ export class MapViewComponent implements AfterViewInit {
255
264
  selectLinkToDisplay(link: number) {
256
265
  this.selectedLinkIndex$.next(link)
257
266
  }
267
+
268
+ handleError(error: FetchError | Error | string) {
269
+ if (error instanceof FetchError) {
270
+ this.error = this.translateService.instant(
271
+ `dataset.error.${error.type}`,
272
+ {
273
+ info: error.info,
274
+ }
275
+ )
276
+ console.warn(error.message)
277
+ } else if (error instanceof Error) {
278
+ this.error = this.translateService.instant(error.message)
279
+ console.warn(error.stack || error)
280
+ } else {
281
+ this.error = this.translateService.instant(error)
282
+ console.warn(error)
283
+ }
284
+ this.loading = false
285
+ this.changeRef.detectChanges()
286
+ }
258
287
  }
@@ -1,13 +1,66 @@
1
1
  <div
2
- class="group flex flex-col justify-between h-40 pt-5 pb-6 px-7 rounded filter overflow-hidden cursor-default"
2
+ class="group flex justify-between rounded filter overflow-hidden"
3
+ [ngClass]="cardClass"
3
4
  >
4
- <div
5
- class="font-title font-medium text-21 text-black text-ellipsis overflow-hidden break-words pb-5 h-[4.5rem]"
6
- >
7
- {{ link.name || link.description }}
5
+ <ng-container *ngIf="size !== 'S'">
6
+ <div>
7
+ <ng-container *ngTemplateOutlet="content"></ng-container>
8
+ </div>
9
+ <div class="flex items-center">
10
+ <ng-container *ngTemplateOutlet="buttons"></ng-container>
11
+ </div>
12
+ </ng-container>
13
+ <ng-container *ngIf="size === 'S'">
14
+ <ng-container *ngTemplateOutlet="content"></ng-container>
15
+ </ng-container>
16
+ </div>
17
+
18
+ <ng-template #buttons>
19
+ <div class="flex flex-row gap-2">
20
+ <gn-ui-copy-text-button
21
+ [text]="link.url"
22
+ [tooltipText]="'tooltip.url.copy' | translate"
23
+ [displayText]="false"
24
+ class="border border-gray-300 rounded-lg pt-1 px-2 h-[34px]"
25
+ ></gn-ui-copy-text-button>
26
+ <button
27
+ *ngIf="displayApiFormButton"
28
+ type="button"
29
+ class="gn-ui-card-icon"
30
+ [ngClass]="{
31
+ 'py-2 px-4 rounded-r-md bg-gray-400 hover:bg-gray-600 focus:bg-gray-800 text-white':
32
+ displayText,
33
+ }"
34
+ [matTooltip]="
35
+ !currentlyActive
36
+ ? ('record.metadata.api.form.openForm' | translate)
37
+ : ('record.metadata.api.form.closeForm' | translate)
38
+ "
39
+ matTooltipPosition="above"
40
+ (click)="openRecordApiFormPanel()"
41
+ >
42
+ <ng-icon
43
+ class="pointer-events-none align-middle card-icon"
44
+ name="iconoirSettings"
45
+ [ngClass]="{
46
+ 'text-secondary opacity-100': currentlyActive,
47
+ }"
48
+ ></ng-icon>
49
+ </button>
8
50
  </div>
9
- <div class="">
10
- <div class="flex flex-row justify-between">
51
+ </ng-template>
52
+
53
+ <ng-template #content>
54
+ <div>
55
+ <div class="gn-ui-card-title">
56
+ {{ link.description || link.name }}
57
+ </div>
58
+ <div class="gn-ui-card-detail">
59
+ {{ link.name }}
60
+ </div>
61
+ </div>
62
+ <div class="flex flex-row justify-between">
63
+ <div class="flex flex-row gap-2.5 items-center pt-1">
11
64
  <span
12
65
  *ngIf="link.accessServiceProtocol !== 'GPFDL'"
13
66
  class="bg-primary-opacity-50 uppercase inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded text-primary-lightest group-hover:bg-primary transition-colors"
@@ -26,36 +79,9 @@
26
79
  >
27
80
  record.metadata.api.gpfdl</span
28
81
  >
29
- <div class="flex flex-row gap-2 items-center">
30
- <gn-ui-copy-text-button
31
- [text]="link.url"
32
- [tooltipText]="'tooltip.url.copy' | translate"
33
- [displayText]="false"
34
- ></gn-ui-copy-text-button>
35
- <button
36
- *ngIf="displayApiFormButton"
37
- type="button"
38
- [ngClass]="{
39
- 'py-2 px-4 rounded-r-md bg-gray-400 hover:bg-gray-600 focus:bg-gray-800 text-white':
40
- displayText,
41
- }"
42
- [matTooltip]="
43
- !currentlyActive
44
- ? ('record.metadata.api.form.openForm' | translate)
45
- : ('record.metadata.api.form.closeForm' | translate)
46
- "
47
- matTooltipPosition="above"
48
- (click)="openRecordApiFormPanel()"
49
- >
50
- <ng-icon
51
- class="pointer-events-none align-middle card-icon"
52
- name="matMoreHoriz"
53
- [ngClass]="{
54
- 'text-secondary opacity-100': currentlyActive,
55
- }"
56
- ></ng-icon>
57
- </button>
58
- </div>
82
+ </div>
83
+ <div *ngIf="size === 'S'">
84
+ <ng-container *ngTemplateOutlet="buttons"></ng-container>
59
85
  </div>
60
86
  </div>
61
- </div>
87
+ </ng-template>
@@ -14,7 +14,9 @@ import { CopyTextButtonComponent } from '../../../../../../libs/ui/inputs/src'
14
14
  import { TranslateModule } from '@ngx-translate/core'
15
15
  import { MatTooltipModule } from '@angular/material/tooltip'
16
16
  import { NgIcon, provideIcons } from '@ng-icons/core'
17
- import { matMoreHoriz } from '@ng-icons/material-icons/baseline'
17
+ import { iconoirSettings } from '@ng-icons/iconoir'
18
+
19
+ type CardSize = 'L' | 'M' | 'S' | 'XS'
18
20
 
19
21
  @Component({
20
22
  selector: 'gn-ui-api-card',
@@ -31,18 +33,40 @@ import { matMoreHoriz } from '@ng-icons/material-icons/baseline'
31
33
  ],
32
34
  viewProviders: [
33
35
  provideIcons({
34
- matMoreHoriz,
36
+ iconoirSettings,
35
37
  }),
36
38
  ],
37
39
  })
38
40
  export class ApiCardComponent implements OnInit, OnChanges {
41
+ private _size: 'L' | 'M' | 'S' | 'XS'
39
42
  @Input() link: DatasetServiceDistribution
40
43
  @Input() currentLink: DatasetServiceDistribution
44
+ private readonly sizeClassMap: Record<CardSize, string> = {
45
+ L: 'gn-ui-card-l py-2 px-5 flex-row',
46
+ M: 'gn-ui-card-m py-2 px-5 flex-row',
47
+ S: 'gn-ui-card-s p-4 flex-col',
48
+ XS: 'gn-ui-card-xs py-2 px-5 flex-row',
49
+ }
50
+
51
+ @Input() set size(value: CardSize) {
52
+ this._size = value
53
+ this.cardClass = this.sizeClassMap[value]
54
+ }
55
+ get size(): 'L' | 'M' | 'S' | 'XS' {
56
+ return this._size
57
+ }
58
+ cardClass = ''
41
59
  displayApiFormButton: boolean
42
60
  currentlyActive = false
43
61
  @Output() openRecordApiForm: EventEmitter<DatasetServiceDistribution> =
44
62
  new EventEmitter<DatasetServiceDistribution>()
45
63
 
64
+ get generatedText() {
65
+ return this.link.accessServiceProtocol === 'wfs'
66
+ ? 'datahub.search.filter.generatedByWfs'
67
+ : 'datahub.search.filter.generatedByAPI'
68
+ }
69
+
46
70
  ngOnInit() {
47
71
  this.displayApiFormButton =
48
72
  this.link.accessServiceProtocol === 'ogcFeatures' ||
@@ -1,36 +1,36 @@
1
1
  <a
2
2
  href="{{ link.url }}"
3
3
  target="_blank"
4
- class="group flex justify-between card-shadow px-6 py-5 cursor-pointer"
4
+ class="group flex flex-row justify-between card-shadow cursor-pointer rounded overflow-hidden"
5
5
  rel="noopener"
6
+ [ngClass]="cardClass"
6
7
  >
7
- <div class="grow-1 w-full overflow-hidden">
8
- <div
9
- class="text-21 text-black truncate font-title w-11/12"
10
- [title]="link.description || link.name"
11
- >
8
+ <div class="flex flex-col justify-between">
9
+ <div class="gn-ui-card-title" [title]="link.description || link.name">
12
10
  {{ link.description || link.name }}
13
11
  </div>
14
- <div class="pt-1">
12
+ <div class="gn-ui-card-detail">
13
+ {{ link.name }}
14
+ </div>
15
+ <div class="flex flex-row gap-2 items-center pt-1">
15
16
  <span
16
17
  class="inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded transition-opacity opacity-70 group-hover:opacity-100"
17
18
  [style.background-color]="color"
18
19
  data-cy="download-format"
19
20
  >{{ format || ('downloads.format.unknown' | translate) }}</span
20
21
  >
21
- <span
22
- class="pl-2 inline-flex items-center text-gray-800 text-sm"
23
- *ngIf="isFromApi"
24
- translate=""
22
+ <span class="text-gray-800 text-xs" *ngIf="isFromApi" translate=""
25
23
  >datahub.search.filter.generatedByAPI</span
26
24
  >
27
25
  </div>
28
26
  </div>
29
- <div class="shrink-1 w-14 flex flex-col justify-center items-center">
30
- <ng-icon
31
- class="!w-8 !h-8 card-icon text-3xl"
32
- name="matCloudDownloadOutline"
33
- >
34
- </ng-icon>
27
+ <div class="flex" [ngClass]="size === 'S' ? 'items-end' : 'items-center'">
28
+ <div class="gn-ui-card-icon">
29
+ <ng-icon
30
+ class="inline-block card-icon align-middle"
31
+ name="iconoirDownload"
32
+ >
33
+ </ng-icon>
34
+ </div>
35
35
  </div>
36
36
  </a>
@@ -9,7 +9,9 @@ import { DatasetOnlineResource } from '../../../../../../libs/common/domain/src/
9
9
  import { TranslateModule } from '@ngx-translate/core'
10
10
  import { CommonModule } from '@angular/common'
11
11
  import { NgIcon, provideIcons } from '@ng-icons/core'
12
- import { matCloudDownloadOutline } from '@ng-icons/material-icons/outline'
12
+ import { iconoirDownload } from '@ng-icons/iconoir'
13
+
14
+ type CardSize = 'L' | 'M' | 'S' | 'XS'
13
15
 
14
16
  @Component({
15
17
  selector: 'gn-ui-download-item',
@@ -20,15 +22,31 @@ import { matCloudDownloadOutline } from '@ng-icons/material-icons/outline'
20
22
  standalone: true,
21
23
  viewProviders: [
22
24
  provideIcons({
23
- matCloudDownloadOutline,
25
+ iconoirDownload,
24
26
  }),
25
27
  ],
26
28
  })
27
29
  export class DownloadItemComponent {
30
+ private _size: 'L' | 'M' | 'S' | 'XS'
28
31
  @Input() link: DatasetOnlineResource
29
32
  @Input() color: string
30
33
  @Input() format: string
31
34
  @Input() isFromApi: boolean
35
+ private readonly sizeClassMap: Record<CardSize, string> = {
36
+ L: 'gn-ui-card-l py-2 px-5',
37
+ M: 'gn-ui-card-m py-2 px-5',
38
+ S: 'gn-ui-card-s p-4',
39
+ XS: 'gn-ui-card-xs py-2 px-5',
40
+ }
41
+
42
+ @Input() set size(value: CardSize) {
43
+ this._size = value
44
+ this.cardClass = this.sizeClassMap[value]
45
+ }
46
+ get size(): 'L' | 'M' | 'S' | 'XS' {
47
+ return this._size
48
+ }
49
+ cardClass = ''
32
50
  @Output() exportUrl = new EventEmitter<string>()
33
51
 
34
52
  openUrl() {
@@ -28,6 +28,7 @@
28
28
  </div>
29
29
  <div class="mb-2 sm:mb-3" *ngFor="let link of filteredLinks">
30
30
  <gn-ui-download-item
31
+ size="L"
31
32
  [link]="link"
32
33
  [color]="getLinkColor(link)"
33
34
  [format]="getLinkFormat(link)"
@@ -1,39 +1,37 @@
1
1
  <a
2
2
  [href]="link.url"
3
3
  target="_blank"
4
- class="flex flex-col justify-between group grow py-5 px-5 bg-white rounded border-gray-300 filter card-shadow overflow-hidden"
5
- [ngClass]="{ 'h-40': !compact }"
4
+ class="group flex flex-row justify-between card-shadow cursor-pointer rounded overflow-hidden"
5
+ [ngClass]="cardClass"
6
6
  [title]="title"
7
7
  >
8
- <ng-container *ngIf="!compact; else compactTpl">
9
- <div class="max-h-24 overflow-hidden text-ellipsis">
10
- <p
11
- class="font-title font-medium text-21 text-black break-words mb-1 line-clamp-2"
12
- >
13
- {{ link.name }}
14
- </p>
15
- <p class="font-medium text-sm break-words">
16
- {{ link.description }}
17
- </p>
18
- <p
19
- *ngIf="!link.name && !link.description"
20
- class="font-medium text-sm break-words truncate"
21
- >
22
- {{ link.url }}
23
- </p>
8
+ <div class="flex flex-col justify-between">
9
+ <div class="gn-ui-card-title">
10
+ {{ link.description || link.name }}
24
11
  </div>
25
- <div>
26
- <ng-icon class="card-icon" name="matOpenInNew"></ng-icon>
12
+ <div class="gn-ui-card-detail">
13
+ {{ link.name }}
27
14
  </div>
28
- </ng-container>
29
- <ng-template #compactTpl>
30
- <div class="flex items-center justify-between gap-4">
31
- <p
32
- class="overflow-hidden font-title font-medium text-21 text-black text-ellipsis whitespace-nowrap"
15
+ <p *ngIf="!link.name && !link.description" class="gn-ui-card-title">
16
+ {{ link.url }}
17
+ </p>
18
+ <div class="pt-1">
19
+ <span
20
+ class="inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded transition-opacity opacity-70 group-hover:opacity-100"
21
+ [style.background-color]="getLinkColor(link)"
22
+ data-cy="download-format"
23
+ >{{
24
+ getLinkFormat(link) || ('downloads.format.unknown' | translate)
25
+ }}</span
33
26
  >
34
- {{ link.name || link.description }}
35
- </p>
36
- <ng-icon class="card-icon flex-shrink-0" name="matOpenInNew"></ng-icon>
37
27
  </div>
38
- </ng-template>
28
+ </div>
29
+ <div class="flex" [ngClass]="size === 'S' ? 'items-end' : 'items-center'">
30
+ <div class="gn-ui-card-icon">
31
+ <ng-icon
32
+ class="inline-block card-icon align-middle"
33
+ name="matOpenInNew"
34
+ ></ng-icon>
35
+ </div>
36
+ </div>
39
37
  </a>
@@ -1,5 +1,9 @@
1
1
  import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
- import { DatasetOnlineResource } from '../../../../../../libs/common/domain/src/lib/model/record'
2
+ import {
3
+ DatasetDownloadDistribution,
4
+ DatasetOnlineResource,
5
+ DatasetServiceDistribution,
6
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
3
7
  import { CommonModule } from '@angular/common'
4
8
  import {
5
9
  NgIconComponent,
@@ -7,14 +11,17 @@ import {
7
11
  provideNgIconsConfig,
8
12
  } from '@ng-icons/core'
9
13
  import { matOpenInNew } from '@ng-icons/material-icons/baseline'
14
+ import { getBadgeColor, getFileFormat } from '../../../../../../libs/util/shared/src'
15
+ import { TranslateModule } from '@ngx-translate/core'
10
16
 
17
+ type CardSize = 'L' | 'M' | 'S' | 'XS'
11
18
  @Component({
12
19
  selector: 'gn-ui-link-card',
13
20
  templateUrl: './link-card.component.html',
14
21
  styleUrls: ['./link-card.component.css'],
15
22
  changeDetection: ChangeDetectionStrategy.OnPush,
16
23
  standalone: true,
17
- imports: [CommonModule, NgIconComponent],
24
+ imports: [CommonModule, NgIconComponent, TranslateModule],
18
25
  providers: [
19
26
  provideIcons({
20
27
  matOpenInNew,
@@ -23,8 +30,23 @@ import { matOpenInNew } from '@ng-icons/material-icons/baseline'
23
30
  ],
24
31
  })
25
32
  export class LinkCardComponent {
33
+ private _size: 'L' | 'M' | 'S' | 'XS'
26
34
  @Input() link: DatasetOnlineResource
27
- @Input() compact = false
35
+ private readonly sizeClassMap: Record<CardSize, string> = {
36
+ L: 'gn-ui-card-l py-2 px-5',
37
+ M: 'gn-ui-card-m py-2 px-5',
38
+ S: 'gn-ui-card-s p-4',
39
+ XS: 'gn-ui-card-xs py-2 px-5',
40
+ }
41
+
42
+ @Input() set size(value: CardSize) {
43
+ this._size = value
44
+ this.cardClass = this.sizeClassMap[value]
45
+ }
46
+ get size(): 'L' | 'M' | 'S' | 'XS' {
47
+ return this._size
48
+ }
49
+ cardClass = ''
28
50
 
29
51
  get title() {
30
52
  if (this.link.name && this.link.description) {
@@ -32,4 +54,12 @@ export class LinkCardComponent {
32
54
  }
33
55
  return this.link.name || this.link.description || ''
34
56
  }
57
+
58
+ getLinkFormat(link: any) {
59
+ return getFileFormat(link)
60
+ }
61
+
62
+ getLinkColor(link: any) {
63
+ return getBadgeColor(getFileFormat(link))
64
+ }
35
65
  }
@@ -162,7 +162,7 @@ export class RecordApiFormComponent {
162
162
  limit: limit !== '-1' ? Number(limit) : -1,
163
163
  offset: offset !== '' ? Number(offset) : undefined,
164
164
  outputCrs:
165
- format === ('application/json' || 'geojson') ? 'EPSG:4326' : undefined,
165
+ format.toLowerCase().indexOf('json') > -1 ? 'EPSG:4326' : undefined,
166
166
  }
167
167
 
168
168
  if (this.endpoint instanceof WfsEndpoint) {
@@ -170,6 +170,7 @@ export class RecordApiFormComponent {
170
170
  options.maxFeatures = limit !== '-1' ? Number(limit) : undefined
171
171
  return this.endpoint.getFeatureUrl(this.apiFeatureType, options)
172
172
  } else {
173
+ delete options.outputCrs
173
174
  return await this.endpoint.getCollectionItemsUrl(
174
175
  this.apiFeatureType,
175
176
  options
@@ -1,7 +1,3 @@
1
- :host .carousel-container ::ng-deep > * {
2
- flex-shrink: 0;
3
- }
4
-
5
1
  :host {
6
2
  position: relative;
7
3
  display: block;
@@ -28,6 +28,8 @@ import {
28
28
  MapContextLayer,
29
29
  MapContextLayerXyz,
30
30
  MapContextView,
31
+ SourceLoadErrorEvent,
32
+ SourceLoadErrorType,
31
33
  } from '@geospatial-sdk/core'
32
34
  import {
33
35
  applyContextDiffToMap,
@@ -119,6 +121,18 @@ export class MapContainerComponent implements AfterViewInit, OnChanges {
119
121
  }
120
122
  return this._mapClick
121
123
  }
124
+ _sourceLoadError: EventEmitter<SourceLoadErrorEvent>
125
+ @Output() get sourceLoadError() {
126
+ if (!this._sourceLoadError) {
127
+ this.openlayersMap.then((olMap) => {
128
+ listen(olMap, SourceLoadErrorType, (error: SourceLoadErrorEvent) =>
129
+ this._sourceLoadError.emit(error)
130
+ )
131
+ })
132
+ this._sourceLoadError = new EventEmitter<SourceLoadErrorEvent>()
133
+ }
134
+ return this._sourceLoadError
135
+ }
122
136
 
123
137
  @ViewChild('map') container: ElementRef
124
138
  displayMessage$: Observable<boolean>