geonetwork-ui 2.3.0-dev.287bf00c → 2.3.0-dev.2b3239d3

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 (142) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +2 -2
  2. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +2 -2
  3. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +1 -1
  4. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +3 -21
  5. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.mjs +1 -1
  6. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.mjs +104 -0
  7. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +8 -3
  8. package/esm2022/libs/feature/editor/src/lib/components/wizard-field/wizard-field.component.mjs +1 -1
  9. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +8 -1
  10. package/esm2022/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.mjs +73 -20
  11. package/esm2022/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.mjs +1 -1
  12. package/esm2022/libs/feature/map/src/lib/add-layer-from-wms/add-layer-from-wms.component.mjs +1 -1
  13. package/esm2022/libs/feature/map/src/lib/map-context/map-context.model.mjs +1 -1
  14. package/esm2022/libs/feature/map/src/lib/map-context/map-context.service.mjs +29 -8
  15. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +1 -1
  16. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +1 -1
  17. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +1 -1
  18. package/esm2022/libs/feature/search/src/index.mjs +2 -1
  19. package/esm2022/libs/feature/search/src/lib/results-layout/results-layout.component.mjs +1 -1
  20. package/esm2022/libs/feature/search/src/lib/sort-by/sort-by.component.mjs +1 -1
  21. package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +1 -1
  22. package/esm2022/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.mjs +1 -1
  23. package/esm2022/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.mjs +1 -1
  24. package/esm2022/libs/ui/elements/src/lib/api-card/api-card.component.mjs +3 -2
  25. package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +2 -2
  26. package/esm2022/libs/ui/elements/src/lib/link-card/link-card.component.mjs +16 -3
  27. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +90 -54
  28. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +1 -6
  29. package/esm2022/libs/ui/inputs/src/index.mjs +2 -1
  30. package/esm2022/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.mjs +4 -3
  31. package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +5 -3
  32. package/esm2022/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.mjs +29 -0
  33. package/esm2022/libs/ui/inputs/src/lib/text-input/text-input.component.mjs +5 -3
  34. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +6 -5
  35. package/esm2022/libs/ui/layout/src/index.mjs +2 -1
  36. package/esm2022/libs/ui/layout/src/lib/block-list/block-list.component.mjs +76 -0
  37. package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +42 -18
  38. package/esm2022/libs/ui/layout/src/lib/ui-layout.module.mjs +3 -8
  39. package/esm2022/translations/de.json +11 -14
  40. package/esm2022/translations/en.json +11 -14
  41. package/esm2022/translations/es.json +11 -14
  42. package/esm2022/translations/fr.json +11 -14
  43. package/esm2022/translations/it.json +11 -14
  44. package/esm2022/translations/nl.json +11 -14
  45. package/esm2022/translations/pt.json +11 -14
  46. package/fesm2022/geonetwork-ui.mjs +569 -264
  47. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  48. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  49. package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
  50. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts +21 -0
  51. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts.map +1 -0
  52. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +1 -0
  53. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  54. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  55. package/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.d.ts +10 -5
  56. package/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.d.ts.map +1 -1
  57. package/libs/feature/map/src/lib/map-context/map-context.model.d.ts +1 -0
  58. package/libs/feature/map/src/lib/map-context/map-context.model.d.ts.map +1 -1
  59. package/libs/feature/map/src/lib/map-context/map-context.service.d.ts.map +1 -1
  60. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  61. package/libs/feature/search/src/index.d.ts +1 -0
  62. package/libs/feature/search/src/index.d.ts.map +1 -1
  63. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts +3 -3
  64. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
  65. package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts.map +1 -1
  66. package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts +3 -1
  67. package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts.map +1 -1
  68. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts +22 -4
  69. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
  70. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +29 -30
  71. package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
  72. package/libs/ui/inputs/src/index.d.ts +1 -0
  73. package/libs/ui/inputs/src/index.d.ts.map +1 -1
  74. package/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.d.ts +1 -1
  75. package/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.d.ts.map +1 -1
  76. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts +2 -1
  77. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts.map +1 -1
  78. package/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.d.ts +12 -0
  79. package/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.d.ts.map +1 -0
  80. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts +2 -1
  81. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts.map +1 -1
  82. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +27 -27
  83. package/libs/ui/layout/src/index.d.ts +1 -0
  84. package/libs/ui/layout/src/index.d.ts.map +1 -1
  85. package/libs/ui/layout/src/lib/block-list/block-list.component.d.ts +25 -0
  86. package/libs/ui/layout/src/lib/block-list/block-list.component.d.ts.map +1 -0
  87. package/libs/ui/layout/src/lib/carousel/carousel.component.d.ts +13 -6
  88. package/libs/ui/layout/src/lib/carousel/carousel.component.d.ts.map +1 -1
  89. package/libs/ui/layout/src/lib/ui-layout.module.d.ts +4 -5
  90. package/libs/ui/layout/src/lib/ui-layout.module.d.ts.map +1 -1
  91. package/package.json +2 -2
  92. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +1 -1
  93. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +1 -4
  94. package/src/libs/common/fixtures/src/lib/link.fixtures.ts +8 -0
  95. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +2 -19
  96. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.css +0 -0
  97. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +14 -0
  98. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +143 -0
  99. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +5 -0
  100. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +5 -0
  101. package/src/libs/feature/editor/src/lib/fields.config.ts +7 -0
  102. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.css +7 -0
  103. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.html +32 -18
  104. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.ts +72 -17
  105. package/src/libs/feature/map/src/lib/map-context/map-context.model.ts +1 -0
  106. package/src/libs/feature/map/src/lib/map-context/map-context.service.ts +26 -8
  107. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +0 -1
  108. package/src/libs/feature/search/src/index.ts +1 -0
  109. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +2 -2
  110. package/src/libs/ui/elements/src/lib/api-card/api-card.component.ts +2 -1
  111. package/src/libs/ui/elements/src/lib/downloads-list/downloads-list.component.ts +1 -1
  112. package/src/libs/ui/elements/src/lib/link-card/link-card.component.html +38 -20
  113. package/src/libs/ui/elements/src/lib/link-card/link-card.component.ts +12 -0
  114. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +25 -9
  115. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +117 -57
  116. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +0 -2
  117. package/src/libs/ui/inputs/src/index.ts +1 -0
  118. package/src/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts +3 -0
  119. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +1 -0
  120. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts +1 -0
  121. package/src/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css +6 -0
  122. package/src/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html +26 -0
  123. package/src/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.ts +32 -0
  124. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +1 -0
  125. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +1 -0
  126. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +1 -1
  127. package/src/libs/ui/layout/src/index.ts +1 -0
  128. package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +23 -0
  129. package/src/libs/ui/layout/src/lib/block-list/block-list.component.html +20 -0
  130. package/src/libs/ui/layout/src/lib/block-list/block-list.component.ts +84 -0
  131. package/src/libs/ui/layout/src/lib/carousel/carousel.component.css +8 -4
  132. package/src/libs/ui/layout/src/lib/carousel/carousel.component.html +4 -4
  133. package/src/libs/ui/layout/src/lib/carousel/carousel.component.ts +45 -15
  134. package/src/libs/ui/layout/src/lib/ui-layout.module.ts +0 -2
  135. package/translations/de.json +11 -14
  136. package/translations/en.json +11 -14
  137. package/translations/es.json +11 -14
  138. package/translations/fr.json +11 -14
  139. package/translations/it.json +11 -14
  140. package/translations/nl.json +11 -14
  141. package/translations/pt.json +11 -14
  142. package/translations/sk.json +11 -14
@@ -25,6 +25,10 @@ import WMTS from 'ol/source/WMTS'
25
25
  import { Geometry } from 'ol/geom'
26
26
  import Feature from 'ol/Feature'
27
27
  import { WfsEndpoint, WmtsEndpoint } from '@camptocamp/ogc-client'
28
+ import OGCVectorTile from 'ol/source/OGCVectorTile.js'
29
+ import { MVT } from 'ol/format'
30
+ import VectorTileLayer from 'ol/layer/VectorTile'
31
+ import OGCMapTile from 'ol/source/OGCMapTile.js'
28
32
 
29
33
  export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerXyzModel = {
30
34
  type: MapContextLayerTypeEnum.XYZ,
@@ -78,14 +82,28 @@ export class MapContextService {
78
82
  const style = this.styleService.styles.default
79
83
  switch (type) {
80
84
  case MapContextLayerTypeEnum.OGCAPI:
81
- return new VectorLayer({
82
- source: new VectorSource({
83
- format: new GeoJSON(),
84
- url: layerModel.url,
85
- }),
86
- style,
87
- })
88
-
85
+ if (layerModel.layerType === 'vectorTiles') {
86
+ return new VectorTileLayer({
87
+ source: new OGCVectorTile({
88
+ url: layerModel.url,
89
+ format: new MVT(),
90
+ }),
91
+ })
92
+ } else if (layerModel.layerType === 'mapTiles') {
93
+ return new TileLayer({
94
+ source: new OGCMapTile({
95
+ url: layerModel.url,
96
+ }),
97
+ })
98
+ } else {
99
+ return new VectorLayer({
100
+ source: new VectorSource({
101
+ format: new GeoJSON(),
102
+ url: layerModel.url,
103
+ }),
104
+ style,
105
+ })
106
+ }
89
107
  case MapContextLayerTypeEnum.XYZ:
90
108
  return new TileLayer({
91
109
  source: new XYZ({
@@ -8,7 +8,6 @@ import { DatavizConfigurationModel } from '../../../../../../libs/common/domain/
8
8
  import {
9
9
  CatalogRecord,
10
10
  UserFeedback,
11
- UserFeedbackViewModel,
12
11
  } from '../../../../../../libs/common/domain/src/lib/model/record'
13
12
  import { AvatarServiceInterface } from '../../../../../../libs/api/repository/src'
14
13
 
@@ -8,6 +8,7 @@ export * from './lib/state/effects'
8
8
  export * from './lib/state/reducer'
9
9
  export * from './lib/utils/service/search.service'
10
10
  export * from './lib/utils/service/fields.service'
11
+ export * from './lib/utils/service/fields'
11
12
  export * from './lib/results-list/results-list.container.component'
12
13
  export * from './lib/filter-dropdown/filter-dropdown.component'
13
14
  export * from './lib/constants'
@@ -36,7 +36,7 @@ marker('search.filters.contact')
36
36
  providedIn: 'root',
37
37
  })
38
38
  export class FieldsService {
39
- private fields = {
39
+ protected fields = {
40
40
  publisher: new OrganizationSearchField(this.injector),
41
41
  format: new SimpleSearchField('format', this.injector, 'asc'),
42
42
  resourceType: new TranslatedSearchField(
@@ -76,7 +76,7 @@ export class FieldsService {
76
76
  return Object.keys(this.fields)
77
77
  }
78
78
 
79
- constructor(private injector: Injector) {}
79
+ constructor(protected injector: Injector) {}
80
80
 
81
81
  getAvailableValues(fieldName: string) {
82
82
  if (this.supportedFields.indexOf(fieldName) === -1)
@@ -26,7 +26,8 @@ export class ApiCardComponent implements OnInit, OnChanges {
26
26
 
27
27
  ngOnInit() {
28
28
  this.displayApiFormButton =
29
- this.link.accessServiceProtocol === 'ogcFeatures' ? true : false
29
+ this.link.accessServiceProtocol === 'ogcFeatures' ||
30
+ this.link.accessServiceProtocol === 'wfs'
30
31
  }
31
32
 
32
33
  ngOnChanges(changes: SimpleChanges) {
@@ -95,6 +95,6 @@ export class DownloadsListComponent {
95
95
  }
96
96
 
97
97
  isFromWfs(link: DatasetDistribution) {
98
- return link.type === 'service' && link.accessServiceProtocol === 'wfs'
98
+ return link.type === 'download' && link.accessServiceProtocol === 'wfs'
99
99
  }
100
100
  }
@@ -1,25 +1,43 @@
1
1
  <a
2
2
  [href]="link.url"
3
3
  target="_blank"
4
- class="flex flex-col justify-between group h-40 grow py-5 px-5 bg-white rounded border-gray-300 filter card-shadow overflow-hidden lg:w-80"
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 }"
6
+ [title]="title"
5
7
  >
6
- <div class="max-h-24 overflow-hidden text-ellipsis">
7
- <p
8
- class="font-title font-medium text-21 text-black break-words mb-1 line-clamp-2"
9
- >
10
- {{ link.name }}
11
- </p>
12
- <p class="font-medium text-sm break-words">
13
- {{ link.description }}
14
- </p>
15
- <p
16
- *ngIf="!link.name && !link.description"
17
- class="font-medium text-sm break-words truncate"
18
- >
19
- {{ link.url }}
20
- </p>
21
- </div>
22
- <div>
23
- <mat-icon class="material-symbols-outlined card-icon">open_in_new</mat-icon>
24
- </div>
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>
24
+ </div>
25
+ <div>
26
+ <mat-icon class="material-symbols-outlined card-icon"
27
+ >open_in_new</mat-icon
28
+ >
29
+ </div>
30
+ </ng-container>
31
+ <ng-template #compactTpl>
32
+ <div class="flex items-center justify-between gap-4">
33
+ <p
34
+ class="overflow-hidden font-title font-medium text-21 text-black text-ellipsis whitespace-nowrap"
35
+ >
36
+ {{ link.name || link.description }}
37
+ </p>
38
+ <mat-icon class="material-symbols-outlined card-icon flex-shrink-0"
39
+ >open_in_new</mat-icon
40
+ >
41
+ </div>
42
+ </ng-template>
25
43
  </a>
@@ -1,12 +1,24 @@
1
1
  import { Component, ChangeDetectionStrategy, Input } from '@angular/core'
2
2
  import { DatasetDistribution } from '../../../../../../libs/common/domain/src/lib/model/record'
3
+ import { MatIconModule } from '@angular/material/icon'
4
+ import { CommonModule } from '@angular/common'
3
5
 
4
6
  @Component({
5
7
  selector: 'gn-ui-link-card',
6
8
  templateUrl: './link-card.component.html',
7
9
  styleUrls: ['./link-card.component.css'],
8
10
  changeDetection: ChangeDetectionStrategy.OnPush,
11
+ standalone: true,
12
+ imports: [CommonModule, MatIconModule],
9
13
  })
10
14
  export class LinkCardComponent {
11
15
  @Input() link: DatasetDistribution
16
+ @Input() compact = false
17
+
18
+ get title() {
19
+ if (this.link.name && this.link.description) {
20
+ return `${this.link.name} | ${this.link.description}`
21
+ }
22
+ return this.link.name || this.link.description || ''
23
+ }
12
24
  }
@@ -37,15 +37,31 @@
37
37
  </div>
38
38
  </div>
39
39
  </div>
40
- <div class="flex flex-col gap-3">
41
- <p class="text-sm" translate>record.metadata.api.form.offset</p>
42
- <gn-ui-text-input
43
- class="w-20"
44
- [value]="offset$ | async"
45
- (valueChange)="setOffset($event)"
46
- hint=""
47
- >
48
- </gn-ui-text-input>
40
+ <div class="flex flex-col gap-3 relative">
41
+ <p class="text-sm" [class.text-gray-600]="!supportOffset" translate>
42
+ record.metadata.api.form.offset
43
+ </p>
44
+ <div class="flex items-center">
45
+ <gn-ui-text-input
46
+ class="w-20"
47
+ [value]="offset$ | async"
48
+ [disabled]="!supportOffset"
49
+ (valueChange)="supportOffset ? setOffset($event) : null"
50
+ hint=""
51
+ >
52
+ </gn-ui-text-input>
53
+ <div
54
+ *ngIf="!supportOffset"
55
+ class="flex items-center gap-2 text-orange-500 z-10 ml-3"
56
+ >
57
+ <span
58
+ class="material-symbols-outlined"
59
+ matTooltip="Not supported on this service"
60
+ >
61
+ warning
62
+ </span>
63
+ </div>
64
+ </div>
49
65
  </div>
50
66
  <div class="flex flex-col gap-3">
51
67
  <p class="text-sm" translate>record.metadata.api.form.type</p>
@@ -1,14 +1,23 @@
1
1
  import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
- import { OgcApiEndpoint } from '@camptocamp/ogc-client'
3
- import { DatasetServiceDistribution } from '../../../../../../libs/common/domain/src/lib/model/record'
2
+ import { OgcApiEndpoint, WfsEndpoint } from '@camptocamp/ogc-client'
3
+ import {
4
+ DatasetServiceDistribution,
5
+ ServiceProtocol,
6
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
4
7
  import { mimeTypeToFormat } from '../../../../../../libs/util/shared/src'
5
- import { BehaviorSubject, combineLatest, map } from 'rxjs'
8
+ import { BehaviorSubject, combineLatest, map, switchMap } from 'rxjs'
6
9
 
7
10
  const DEFAULT_PARAMS = {
8
11
  OFFSET: '',
9
12
  LIMIT: '-1',
10
13
  FORMAT: 'json',
11
14
  }
15
+
16
+ interface OutputFormats {
17
+ itemFormats?: any[]
18
+ outputFormats?: any[]
19
+ }
20
+
12
21
  @Component({
13
22
  selector: 'gn-ui-record-api-form',
14
23
  templateUrl: './record-api-form.component.html',
@@ -17,38 +26,44 @@ const DEFAULT_PARAMS = {
17
26
  })
18
27
  export class RecordApiFormComponent {
19
28
  @Input() set apiLink(value: DatasetServiceDistribution) {
20
- this.apiBaseUrl = value ? value.url.href : undefined
21
29
  this.outputFormats = [{ value: 'json', label: 'JSON' }]
22
- this.parseOutputFormats()
30
+ this.accessServiceProtocol = value ? value.accessServiceProtocol : undefined
31
+ this.apiFeatureType = value ? value.name : undefined
32
+ if (value) {
33
+ this.apiBaseUrl = value.url.href
34
+ this.createEndpoint().then(() => this.parseOutputFormats())
35
+ }
23
36
  this.resetUrl()
24
37
  }
25
- offset$ = new BehaviorSubject('')
26
- limit$ = new BehaviorSubject('')
27
- format$ = new BehaviorSubject('')
38
+
39
+ offset$ = new BehaviorSubject(DEFAULT_PARAMS.OFFSET)
40
+ limit$ = new BehaviorSubject(DEFAULT_PARAMS.LIMIT)
41
+ format$ = new BehaviorSubject(DEFAULT_PARAMS.FORMAT)
42
+ endpoint$ = new BehaviorSubject<WfsEndpoint | OgcApiEndpoint | undefined>(
43
+ undefined
44
+ )
28
45
  apiBaseUrl: string
46
+ apiFeatureType: string
47
+ supportOffset = true
48
+ accessServiceProtocol: ServiceProtocol | undefined
29
49
  outputFormats = [{ value: 'json', label: 'JSON' }]
30
- apiQueryUrl$ = combineLatest([this.offset$, this.limit$, this.format$]).pipe(
31
- map(([offset, limit, format]) => {
32
- let outputUrl
33
- if (this.apiBaseUrl) {
34
- const url = new URL(this.apiBaseUrl)
35
- const params = { offset: offset, limit: limit, f: format }
36
- for (const [key, value] of Object.entries(params)) {
37
- if (value && value !== '0') {
38
- url.searchParams.set(key, value)
39
- } else {
40
- url.searchParams.delete(key)
41
- }
42
- }
43
- outputUrl = url.toString()
44
- }
45
- return outputUrl
46
- })
50
+ endpoint: WfsEndpoint | OgcApiEndpoint | undefined
51
+ firstCollection: string | undefined
52
+
53
+ apiQueryUrl$ = combineLatest([
54
+ this.offset$,
55
+ this.limit$,
56
+ this.format$,
57
+ this.endpoint$,
58
+ ]).pipe(
59
+ switchMap(([offset, limit, format]) =>
60
+ this.generateApiQueryUrl(offset, limit, format)
61
+ )
47
62
  )
63
+
48
64
  noLimitChecked$ = this.limit$.pipe(
49
65
  map((limit) => limit === '-1' || limit === '')
50
66
  )
51
-
52
67
  displayLimit$ = this.limit$.pipe(
53
68
  map((limit) => (limit !== '-1' ? limit : ''))
54
69
  )
@@ -58,8 +73,7 @@ export class RecordApiFormComponent {
58
73
  }
59
74
 
60
75
  setLimit(value: string) {
61
- const newLimit = value === '' ? '-1' : value
62
- this.limit$.next(newLimit)
76
+ this.limit$.next(value === '' ? '-1' : value)
63
77
  }
64
78
 
65
79
  setFormat(value: string | unknown) {
@@ -72,38 +86,84 @@ export class RecordApiFormComponent {
72
86
  this.format$.next(DEFAULT_PARAMS.FORMAT)
73
87
  }
74
88
 
75
- parseOutputFormats() {
76
- const apiUrl =
77
- this.apiBaseUrl.slice(-1) === '?'
78
- ? this.apiBaseUrl.slice(0, -1)
79
- : this.apiBaseUrl
80
-
81
- this.getOutputFormats(apiUrl).then((outputFormats) => {
82
- const formatsList = outputFormats.itemFormats.map((format) => {
83
- const normalizedFormat = mimeTypeToFormat(format)
84
- if (normalizedFormat) {
85
- return {
86
- label: normalizedFormat?.toUpperCase(),
87
- value: normalizedFormat,
88
- }
89
- }
90
- return null
91
- })
92
- this.outputFormats = this.outputFormats.concat(
93
- formatsList.filter(Boolean)
89
+ async parseOutputFormats() {
90
+ if (!this.endpoint) return
91
+ const apiUrl = this.apiBaseUrl.endsWith('?')
92
+ ? this.apiBaseUrl.slice(0, -1)
93
+ : this.apiBaseUrl
94
+ const outputFormats = await this.getOutputFormats(apiUrl)
95
+
96
+ const formatsList = outputFormats.itemFormats
97
+ ? this.mapFormats(outputFormats.itemFormats)
98
+ : this.mapFormats(outputFormats.outputFormats || [])
99
+
100
+ this.outputFormats = this.outputFormats
101
+ .concat(formatsList.filter(Boolean))
102
+ .filter(
103
+ (format, index, self) =>
104
+ index === self.findIndex((t) => t.value === format.value)
94
105
  )
95
- this.outputFormats = this.outputFormats
96
- .filter(
97
- (format, index, self) =>
98
- index === self.findIndex((t) => t.value === format.value)
99
- )
100
- .sort((a, b) => a.label.localeCompare(b.label))
106
+ .sort((a, b) => a.label.localeCompare(b.label))
107
+ }
108
+
109
+ mapFormats(formats: any[]) {
110
+ return formats.map((format) => {
111
+ const normalizedFormat = mimeTypeToFormat(format)
112
+ return normalizedFormat
113
+ ? { label: normalizedFormat.toUpperCase(), value: normalizedFormat }
114
+ : null
101
115
  })
102
116
  }
103
117
 
104
- async getOutputFormats(url) {
105
- const endpoint = await new OgcApiEndpoint(url)
106
- const firstCollection = (await endpoint.featureCollections)[0]
107
- return endpoint.getCollectionInfo(firstCollection)
118
+ async getOutputFormats(url: string): Promise<OutputFormats> {
119
+ if (!this.endpoint) return {}
120
+ if (this.endpoint instanceof WfsEndpoint) {
121
+ this.supportOffset = this.endpoint.supportsStartIndex()
122
+ return this.endpoint.getServiceInfo() as OutputFormats
123
+ } else {
124
+ {
125
+ return (await this.endpoint.getCollectionInfo(
126
+ this.firstCollection
127
+ )) as OutputFormats
128
+ }
129
+ }
130
+ }
131
+
132
+ async createEndpoint() {
133
+ if (!this.apiBaseUrl || !this.accessServiceProtocol) return
134
+ if (this.accessServiceProtocol === 'wfs') {
135
+ this.endpoint = new WfsEndpoint(this.apiBaseUrl)
136
+ await (this.endpoint as WfsEndpoint).isReady()
137
+ } else {
138
+ this.endpoint = new OgcApiEndpoint(this.apiBaseUrl)
139
+ this.firstCollection = (await this.endpoint.featureCollections)[0]
140
+ }
141
+ this.endpoint$.next(this.endpoint)
142
+ }
143
+
144
+ async generateApiQueryUrl(
145
+ offset: string,
146
+ limit: string,
147
+ format: string
148
+ ): Promise<string> {
149
+ if (!this.apiBaseUrl || !this.endpoint || !this.apiFeatureType) return ''
150
+
151
+ const options = {
152
+ outputFormat: format,
153
+ startIndex: offset ? Number(offset) : undefined,
154
+ maxFeatures: limit !== '-1' ? Number(limit) : undefined,
155
+ limit: limit !== '-1' ? Number(limit) : limit === '-1' ? -1 : undefined,
156
+ offset: offset !== '' ? Number(offset) : undefined,
157
+ }
158
+
159
+ if (this.endpoint instanceof WfsEndpoint) {
160
+ options.maxFeatures = limit !== '-1' ? Number(limit) : undefined
161
+ return this.endpoint.getFeatureUrl(this.apiFeatureType, options)
162
+ } else {
163
+ return await this.endpoint.getCollectionItemsUrl(
164
+ this.firstCollection,
165
+ options
166
+ )
167
+ }
108
168
  }
109
169
  }
@@ -57,7 +57,6 @@ import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
57
57
  DownloadItemComponent,
58
58
  DownloadsListComponent,
59
59
  ApiCardComponent,
60
- LinkCardComponent,
61
60
  RelatedRecordCardComponent,
62
61
  MetadataContactComponent,
63
62
  MetadataCatalogComponent,
@@ -80,7 +79,6 @@ import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
80
79
  DownloadItemComponent,
81
80
  DownloadsListComponent,
82
81
  ApiCardComponent,
83
- LinkCardComponent,
84
82
  RelatedRecordCardComponent,
85
83
  MetadataContactComponent,
86
84
  MetadataCatalogComponent,
@@ -19,3 +19,4 @@ export * from './lib/text-area/text-area.component'
19
19
  export * from './lib/text-input/text-input.component'
20
20
  export * from './lib/ui-inputs.module'
21
21
  export * from './lib/viewport-intersector/viewport-intersector.component'
22
+ export * from './lib/previous-next-buttons/previous-next-buttons.component'
@@ -5,12 +5,15 @@ import {
5
5
  Input,
6
6
  Output,
7
7
  } from '@angular/core'
8
+ import { FormsModule } from '@angular/forms'
8
9
 
9
10
  @Component({
10
11
  selector: 'gn-ui-check-toggle',
11
12
  templateUrl: './check-toggle.component.html',
12
13
  styleUrls: ['./check-toggle.component.css'],
13
14
  changeDetection: ChangeDetectionStrategy.OnPush,
15
+ standalone: true,
16
+ imports: [FormsModule],
14
17
  })
15
18
  export class CheckToggleComponent {
16
19
  @Input() title: string
@@ -18,6 +18,7 @@
18
18
  cdkOverlayOrigin
19
19
  #overlayOrigin="cdkOverlayOrigin"
20
20
  (keydown)="handleTriggerKeydown($event)"
21
+ [disabled]="disabled"
21
22
  >
22
23
  <div class="grow font-medium truncate py-1 mr-2 text-left">
23
24
  {{ getChoiceLabel() | translate }}
@@ -48,6 +48,7 @@ export class DropdownSelectorComponent implements OnInit {
48
48
  @Input() maxRows: number
49
49
  @Input() extraBtnClass = ''
50
50
  @Input() minWidth = ''
51
+ @Input() disabled: boolean
51
52
  @Output() selectValue = new EventEmitter<DropdownChoice['value']>()
52
53
  @ViewChild('overlayOrigin') overlayOrigin: CdkOverlayOrigin
53
54
  @ViewChild(CdkConnectedOverlay) overlay: CdkConnectedOverlay
@@ -0,0 +1,6 @@
1
+ :host {
2
+ --gn-ui-button-rounded: 100%;
3
+ --gn-ui-button-width: 8px;
4
+ --gn-ui-button-height: 8px;
5
+ --gn-ui-button-padding: 12px;
6
+ }
@@ -0,0 +1,26 @@
1
+ <div class="flex flex-row gap-x-4 items-center">
2
+ <gn-ui-button
3
+ data-test="previousButton"
4
+ [type]="isFirst ? 'default' : 'outline'"
5
+ [disabled]="isFirst"
6
+ (buttonClick)="previousButtonClicked()"
7
+ >
8
+ <mat-icon
9
+ class="material-symbols-outlined text-[14px] text-center pt-[5px]"
10
+ >
11
+ arrow_back
12
+ </mat-icon>
13
+ </gn-ui-button>
14
+ <gn-ui-button
15
+ data-test="nextButton"
16
+ [type]="isLast ? 'default' : 'outline'"
17
+ [disabled]="isLast"
18
+ (buttonClick)="nextButtonClicked()"
19
+ >
20
+ <mat-icon
21
+ class="material-symbols-outlined text-[14px] text-center pt-[5px]"
22
+ >
23
+ arrow_forward
24
+ </mat-icon>
25
+ </gn-ui-button>
26
+ </div>
@@ -0,0 +1,32 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ EventEmitter,
5
+ Input,
6
+ Output,
7
+ } from '@angular/core'
8
+ import { ButtonComponent } from '../button/button.component'
9
+ import { MatIconModule } from '@angular/material/icon'
10
+
11
+ @Component({
12
+ selector: 'gn-ui-previous-next-buttons',
13
+ templateUrl: './previous-next-buttons.component.html',
14
+ styleUrls: ['./previous-next-buttons.component.css'],
15
+ changeDetection: ChangeDetectionStrategy.OnPush,
16
+ standalone: true,
17
+ imports: [ButtonComponent, MatIconModule],
18
+ })
19
+ export class PreviousNextButtonsComponent {
20
+ @Input() isFirst: boolean
21
+ @Input() isLast: boolean
22
+
23
+ @Output() directionButtonClicked: EventEmitter<string> = new EventEmitter()
24
+
25
+ previousButtonClicked() {
26
+ this.directionButtonClicked.next('previous')
27
+ }
28
+
29
+ nextButtonClicked() {
30
+ this.directionButtonClicked.next('next')
31
+ }
32
+ }
@@ -8,4 +8,5 @@
8
8
  [placeholder]="hint"
9
9
  [attr.aria-label]="hint"
10
10
  [attr.required]="required || null"
11
+ [disabled]="disabled"
11
12
  />
@@ -29,6 +29,7 @@ export class TextInputComponent implements AfterViewInit {
29
29
  @Input() extraClass = ''
30
30
  @Input() hint: string
31
31
  @Input() required = false
32
+ @Input() disabled: boolean
32
33
  rawChange = new Subject<string>()
33
34
  @Output() valueChange = this.rawChange.pipe(distinctUntilChanged())
34
35
  @ViewChild('input') input
@@ -44,7 +44,6 @@ import { ImageInputComponent } from './image-input/image-input.component'
44
44
  StarToggleComponent,
45
45
  DropdownMultiselectComponent,
46
46
  ViewportIntersectorComponent,
47
- CheckToggleComponent,
48
47
  CopyTextButtonComponent,
49
48
  CheckboxComponent,
50
49
  SearchInputComponent,
@@ -73,6 +72,7 @@ import { ImageInputComponent } from './image-input/image-input.component'
73
72
  ImageInputComponent,
74
73
  DropdownSelectorComponent,
75
74
  DateRangePickerComponent,
75
+ CheckToggleComponent,
76
76
  ],
77
77
  exports: [
78
78
  DropdownSelectorComponent,
@@ -6,4 +6,5 @@ export * from './lib/form-field-wrapper/form-field-wrapper.component'
6
6
  export * from './lib/interactive-table/interactive-table-column/interactive-table-column.component'
7
7
  export * from './lib/interactive-table/interactive-table.component'
8
8
  export * from './lib/sticky-header/sticky-header.component'
9
+ export * from './lib/block-list/block-list.component'
9
10
  export * from './lib/ui-layout.module'
@@ -0,0 +1,23 @@
1
+ :host .block-list-container ::ng-deep > * {
2
+ flex-shrink: 0;
3
+ }
4
+
5
+ :host {
6
+ position: relative;
7
+ }
8
+
9
+ .list-page-dot {
10
+ width: 6px;
11
+ height: 6px;
12
+ border-radius: 6px;
13
+ position: relative;
14
+ }
15
+
16
+ .list-page-dot:after {
17
+ content: '';
18
+ position: absolute;
19
+ left: -7px;
20
+ top: -7px;
21
+ width: 20px;
22
+ height: 20px;
23
+ }