geonetwork-ui 2.3.0-dev.c4b41b40 → 2.3.0-dev.cc25794c

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 (129) 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/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +9 -7
  4. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +1 -1
  5. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +5 -23
  6. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.mjs +1 -1
  7. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.mjs +104 -0
  8. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +8 -3
  9. package/esm2022/libs/feature/editor/src/lib/components/wizard-field/wizard-field.component.mjs +1 -1
  10. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +8 -1
  11. package/esm2022/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.mjs +73 -20
  12. package/esm2022/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.mjs +1 -1
  13. package/esm2022/libs/feature/map/src/lib/add-layer-from-wms/add-layer-from-wms.component.mjs +1 -1
  14. package/esm2022/libs/feature/map/src/lib/map-context/map-context.model.mjs +1 -1
  15. package/esm2022/libs/feature/map/src/lib/map-context/map-context.service.mjs +58 -17
  16. package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +6 -2
  17. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +1 -1
  18. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +5 -3
  19. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +1 -3
  20. package/esm2022/libs/feature/search/src/index.mjs +2 -1
  21. package/esm2022/libs/feature/search/src/lib/results-layout/results-layout.component.mjs +1 -1
  22. package/esm2022/libs/feature/search/src/lib/sort-by/sort-by.component.mjs +1 -1
  23. package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +1 -1
  24. package/esm2022/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.mjs +1 -1
  25. package/esm2022/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.mjs +1 -1
  26. package/esm2022/libs/ui/elements/src/lib/api-card/api-card.component.mjs +3 -2
  27. package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +2 -2
  28. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +89 -54
  29. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.mjs +3 -5
  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/text-input/text-input.component.mjs +5 -3
  33. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +6 -5
  34. package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
  35. package/esm2022/libs/util/app-config/src/lib/app-config.mjs +3 -1
  36. package/esm2022/libs/util/app-config/src/lib/fixtures.mjs +2 -1
  37. package/esm2022/libs/util/app-config/src/lib/model.mjs +1 -1
  38. package/esm2022/translations/de.json +11 -14
  39. package/esm2022/translations/en.json +11 -14
  40. package/esm2022/translations/es.json +11 -14
  41. package/esm2022/translations/fr.json +11 -14
  42. package/esm2022/translations/it.json +11 -14
  43. package/esm2022/translations/nl.json +11 -14
  44. package/esm2022/translations/pt.json +11 -14
  45. package/fesm2022/geonetwork-ui.mjs +474 -266
  46. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  47. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  48. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.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 +7 -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 +1 -1
  60. package/libs/feature/map/src/lib/map-context/map-context.service.d.ts.map +1 -1
  61. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
  62. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  63. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts.map +1 -1
  64. package/libs/feature/search/src/index.d.ts +1 -0
  65. package/libs/feature/search/src/index.d.ts.map +1 -1
  66. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts +3 -3
  67. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
  68. package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts.map +1 -1
  69. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts +22 -4
  70. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
  71. package/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.d.ts +1 -2
  72. package/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.d.ts.map +1 -1
  73. package/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.d.ts +1 -1
  74. package/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.d.ts.map +1 -1
  75. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts +2 -1
  76. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts.map +1 -1
  77. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts +2 -1
  78. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts.map +1 -1
  79. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +27 -27
  80. package/libs/util/app-config/src/lib/app-config.d.ts.map +1 -1
  81. package/libs/util/app-config/src/lib/fixtures.d.ts.map +1 -1
  82. package/libs/util/app-config/src/lib/model.d.ts +1 -0
  83. package/libs/util/app-config/src/lib/model.d.ts.map +1 -1
  84. package/package.json +2 -2
  85. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +1 -1
  86. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +1 -4
  87. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +16 -10
  88. package/src/libs/common/fixtures/src/lib/link.fixtures.ts +8 -0
  89. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +4 -21
  90. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.css +0 -0
  91. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +14 -0
  92. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +143 -0
  93. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +5 -0
  94. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +5 -0
  95. package/src/libs/feature/editor/src/lib/fields.config.ts +7 -0
  96. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.css +7 -0
  97. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.html +32 -18
  98. package/src/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.ts +72 -17
  99. package/src/libs/feature/map/src/lib/map-context/map-context.model.ts +7 -0
  100. package/src/libs/feature/map/src/lib/map-context/map-context.service.ts +57 -17
  101. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +5 -1
  102. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +4 -4
  103. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +0 -2
  104. package/src/libs/feature/search/src/index.ts +1 -0
  105. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +2 -2
  106. package/src/libs/ui/elements/src/lib/api-card/api-card.component.ts +2 -1
  107. package/src/libs/ui/elements/src/lib/downloads-list/downloads-list.component.ts +1 -1
  108. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +25 -9
  109. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +116 -57
  110. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.html +1 -1
  111. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.ts +0 -1
  112. package/src/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts +3 -0
  113. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +1 -0
  114. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts +1 -0
  115. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +1 -0
  116. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +1 -0
  117. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +1 -1
  118. package/src/libs/ui/layout/src/lib/carousel/carousel.component.css +1 -0
  119. package/src/libs/util/app-config/src/lib/app-config.ts +2 -0
  120. package/src/libs/util/app-config/src/lib/fixtures.ts +1 -0
  121. package/src/libs/util/app-config/src/lib/model.ts +1 -0
  122. package/translations/de.json +11 -14
  123. package/translations/en.json +11 -14
  124. package/translations/es.json +11 -14
  125. package/translations/fr.json +11 -14
  126. package/translations/it.json +11 -14
  127. package/translations/nl.json +11 -14
  128. package/translations/pt.json +11 -14
  129. package/translations/sk.json +11 -14
@@ -25,6 +25,12 @@ 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'
32
+ import ImageLayer from 'ol/layer/Image'
33
+ import ImageWMS from 'ol/source/ImageWMS'
28
34
 
29
35
  export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerXyzModel = {
30
36
  type: MapContextLayerTypeEnum.XYZ,
@@ -33,6 +39,7 @@ export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerXyzModel = {
33
39
  `https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png`,
34
40
  `https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png`,
35
41
  ],
42
+ attributions: `<span>© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="https://carto.com/">Carto</a></span>`,
36
43
  }
37
44
 
38
45
  export const DEFAULT_VIEW: MapContextViewModel = {
@@ -69,38 +76,69 @@ export class MapContextService {
69
76
  }
70
77
  map.setView(this.createView(mapContext.view, map))
71
78
  map.getLayers().clear()
72
- mapContext.layers.forEach((layer) => map.addLayer(this.createLayer(layer)))
79
+ mapContext.layers.forEach((layer) =>
80
+ map.addLayer(this.createLayer(layer, mapConfig))
81
+ )
73
82
  return map
74
83
  }
75
84
 
76
- createLayer(layerModel: MapContextLayerModel): Layer {
85
+ createLayer(layerModel: MapContextLayerModel, mapConfig?: MapConfig): Layer {
77
86
  const { type } = layerModel
78
87
  const style = this.styleService.styles.default
79
88
  switch (type) {
80
89
  case MapContextLayerTypeEnum.OGCAPI:
81
- return new VectorLayer({
82
- source: new VectorSource({
83
- format: new GeoJSON(),
84
- url: layerModel.url,
85
- }),
86
- style,
87
- })
88
-
90
+ if (layerModel.layerType === 'vectorTiles') {
91
+ return new VectorTileLayer({
92
+ source: new OGCVectorTile({
93
+ url: layerModel.url,
94
+ format: new MVT(),
95
+ attributions: layerModel.attributions,
96
+ }),
97
+ })
98
+ } else if (layerModel.layerType === 'mapTiles') {
99
+ return new TileLayer({
100
+ source: new OGCMapTile({
101
+ url: layerModel.url,
102
+ attributions: layerModel.attributions,
103
+ }),
104
+ })
105
+ } else {
106
+ return new VectorLayer({
107
+ source: new VectorSource({
108
+ format: new GeoJSON(),
109
+ url: layerModel.url,
110
+ attributions: layerModel.attributions,
111
+ }),
112
+ style,
113
+ })
114
+ }
89
115
  case MapContextLayerTypeEnum.XYZ:
90
116
  return new TileLayer({
91
117
  source: new XYZ({
92
118
  url: 'url' in layerModel ? layerModel.url : undefined,
93
119
  urls: 'urls' in layerModel ? layerModel.urls : undefined,
120
+ attributions: layerModel.attributions,
94
121
  }),
95
122
  })
96
123
  case MapContextLayerTypeEnum.WMS:
97
- return new TileLayer({
98
- source: new TileWMS({
99
- url: layerModel.url,
100
- params: { LAYERS: layerModel.name },
101
- gutter: 20,
102
- }),
103
- })
124
+ if (mapConfig?.DO_NOT_TILE_WMS) {
125
+ return new ImageLayer({
126
+ source: new ImageWMS({
127
+ url: layerModel.url,
128
+ params: { LAYERS: layerModel.name },
129
+ attributions: layerModel.attributions,
130
+ }),
131
+ })
132
+ } else {
133
+ return new TileLayer({
134
+ source: new TileWMS({
135
+ url: layerModel.url,
136
+ params: { LAYERS: layerModel.name, TILED: true },
137
+ attributions: layerModel.attributions,
138
+ }),
139
+ })
140
+ }
141
+
104
142
  case MapContextLayerTypeEnum.WMTS: {
105
143
  // TODO: isolate this in utils service
106
144
  const olLayer = new TileLayer({})
@@ -123,6 +161,7 @@ export class MapContextService {
123
161
  tileGrid,
124
162
  projection: matrixSet.crs,
125
163
  dimensions,
164
+ attributions: layerModel.attributions,
126
165
  })
127
166
  )
128
167
  })
@@ -148,6 +187,7 @@ export class MapContextService {
148
187
  })
149
188
  },
150
189
  strategy: bboxStrategy,
190
+ attributions: layerModel.attributions,
151
191
  })
152
192
  )
153
193
  })
@@ -26,6 +26,7 @@ import {
26
26
  MapContextLayerWmsModel,
27
27
  } from '../map-context/map-context.model'
28
28
  import Collection from 'ol/Collection'
29
+ import { defaults as defaultControls } from 'ol/control.js'
29
30
  import MapBrowserEvent from 'ol/MapBrowserEvent'
30
31
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
31
32
  import { ProxyService } from '../../../../../../libs/util/shared/src'
@@ -47,7 +48,10 @@ export class MapUtilsService {
47
48
 
48
49
  createEmptyMap(): Map {
49
50
  return new Map({
50
- controls: [],
51
+ controls: defaultControls({
52
+ attribution: true,
53
+ attributionOptions: { collapsible: false },
54
+ }),
51
55
  pixelRatio: 1,
52
56
  })
53
57
  }
@@ -15,7 +15,7 @@ import {
15
15
  MapUtilsService,
16
16
  } from '../../../../../../libs/feature/map/src'
17
17
  import { getOptionalMapConfig, MapConfig } from '../../../../../../libs/util/app-config/src'
18
- import { getLinkLabel, ProxyService } from '../../../../../../libs/util/shared/src'
18
+ import { getLinkLabel } from '../../../../../../libs/util/shared/src'
19
19
  import Feature from 'ol/Feature'
20
20
  import { Geometry } from 'ol/geom'
21
21
  import { StyleLike } from 'ol/style/Style'
@@ -23,10 +23,8 @@ import {
23
23
  BehaviorSubject,
24
24
  combineLatest,
25
25
  from,
26
- lastValueFrom,
27
26
  Observable,
28
27
  of,
29
- startWith,
30
28
  Subscription,
31
29
  throwError,
32
30
  withLatestFrom,
@@ -117,7 +115,9 @@ export class MapViewComponent implements OnInit, OnDestroy {
117
115
  },
118
116
  } as MapContextModel)
119
117
  ),
120
- tap(() => this.resetSelection())
118
+ tap((res) => {
119
+ this.resetSelection()
120
+ })
121
121
  )
122
122
  ),
123
123
  withLatestFrom(this.mdViewFacade.metadata$),
@@ -82,7 +82,6 @@ const metadataViewReducer = createReducer(
82
82
  */
83
83
  on(MetadataViewActions.loadUserFeedbacks, (state) => ({
84
84
  ...state,
85
- error: null,
86
85
  allUserFeedbacksLoading: true,
87
86
  })),
88
87
  on(MetadataViewActions.addUserFeedback, (state) => ({
@@ -93,7 +92,6 @@ const metadataViewReducer = createReducer(
93
92
  MetadataViewActions.loadUserFeedbacksSuccess,
94
93
  (state, { userFeedbacks }) => ({
95
94
  ...state,
96
- error: null,
97
95
  userFeedbacks: userFeedbacks,
98
96
  addUserFeedbackLoading: false,
99
97
  allUserFeedbacksLoading: false,
@@ -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
  }
@@ -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, filter, 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,45 @@ 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
+ // only compute the url if the endpoint was created
58
+ this.endpoint$.pipe(filter((endpoint) => !!endpoint)),
59
+ ]).pipe(
60
+ switchMap(([offset, limit, format]) =>
61
+ this.generateApiQueryUrl(offset, limit, format)
62
+ )
47
63
  )
64
+
48
65
  noLimitChecked$ = this.limit$.pipe(
49
66
  map((limit) => limit === '-1' || limit === '')
50
67
  )
51
-
52
68
  displayLimit$ = this.limit$.pipe(
53
69
  map((limit) => (limit !== '-1' ? limit : ''))
54
70
  )
@@ -58,8 +74,7 @@ export class RecordApiFormComponent {
58
74
  }
59
75
 
60
76
  setLimit(value: string) {
61
- const newLimit = value === '' ? '-1' : value
62
- this.limit$.next(newLimit)
77
+ this.limit$.next(value === '' ? '-1' : value)
63
78
  }
64
79
 
65
80
  setFormat(value: string | unknown) {
@@ -72,38 +87,82 @@ export class RecordApiFormComponent {
72
87
  this.format$.next(DEFAULT_PARAMS.FORMAT)
73
88
  }
74
89
 
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)
90
+ async parseOutputFormats() {
91
+ if (!this.endpoint) return
92
+ const apiUrl = this.apiBaseUrl.endsWith('?')
93
+ ? this.apiBaseUrl.slice(0, -1)
94
+ : this.apiBaseUrl
95
+ const outputFormats = await this.getOutputFormats(apiUrl)
96
+
97
+ const formatsList = outputFormats.itemFormats
98
+ ? this.mapFormats(outputFormats.itemFormats)
99
+ : this.mapFormats(outputFormats.outputFormats || [])
100
+
101
+ this.outputFormats = this.outputFormats
102
+ .concat(formatsList.filter(Boolean))
103
+ .filter(
104
+ (format, index, self) =>
105
+ index === self.findIndex((t) => t.value === format.value)
94
106
  )
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))
107
+ .sort((a, b) => a.label.localeCompare(b.label))
108
+ }
109
+
110
+ mapFormats(formats: any[]) {
111
+ return formats.map((format) => {
112
+ const normalizedFormat = mimeTypeToFormat(format)
113
+ return normalizedFormat
114
+ ? { label: normalizedFormat.toUpperCase(), value: normalizedFormat }
115
+ : null
101
116
  })
102
117
  }
103
118
 
104
- async getOutputFormats(url) {
105
- const endpoint = await new OgcApiEndpoint(url)
106
- const firstCollection = (await endpoint.featureCollections)[0]
107
- return endpoint.getCollectionInfo(firstCollection)
119
+ async getOutputFormats(url: string): Promise<OutputFormats> {
120
+ if (!this.endpoint) return {}
121
+ if (this.endpoint instanceof WfsEndpoint) {
122
+ this.supportOffset = this.endpoint.supportsStartIndex()
123
+ return this.endpoint.getServiceInfo() as OutputFormats
124
+ } else {
125
+ return (await this.endpoint.getCollectionInfo(
126
+ this.firstCollection
127
+ )) as OutputFormats
128
+ }
129
+ }
130
+
131
+ async createEndpoint() {
132
+ if (!this.apiBaseUrl || !this.accessServiceProtocol) return
133
+ if (this.accessServiceProtocol === 'wfs') {
134
+ this.endpoint = new WfsEndpoint(this.apiBaseUrl)
135
+ await (this.endpoint as WfsEndpoint).isReady()
136
+ } else {
137
+ this.endpoint = new OgcApiEndpoint(this.apiBaseUrl)
138
+ this.firstCollection = (await this.endpoint.allCollections)[0].name
139
+ }
140
+ this.endpoint$.next(this.endpoint)
141
+ }
142
+
143
+ async generateApiQueryUrl(
144
+ offset: string,
145
+ limit: string,
146
+ format: string
147
+ ): Promise<string> {
148
+ if (!this.apiBaseUrl || !this.endpoint || !this.apiFeatureType) return ''
149
+
150
+ const options = {
151
+ outputFormat: format,
152
+ startIndex: offset ? Number(offset) : undefined,
153
+ maxFeatures: limit !== '-1' ? Number(limit) : undefined,
154
+ limit: limit !== '-1' ? Number(limit) : limit === '-1' ? -1 : undefined,
155
+ offset: offset !== '' ? Number(offset) : undefined,
156
+ }
157
+
158
+ if (this.endpoint instanceof WfsEndpoint) {
159
+ options.maxFeatures = limit !== '-1' ? Number(limit) : undefined
160
+ return this.endpoint.getFeatureUrl(this.apiFeatureType, options)
161
+ } else {
162
+ return await this.endpoint.getCollectionItemsUrl(
163
+ this.firstCollection,
164
+ options
165
+ )
166
+ }
108
167
  }
109
168
  }
@@ -30,7 +30,7 @@
30
30
  ></gn-ui-user-feedback-item>
31
31
  </div>
32
32
 
33
- <div *ngIf="isActiveUserEditor" class="mt-2 flex flex-col">
33
+ <div *ngIf="activeUser" class="mt-2 flex flex-col">
34
34
  <hr class="-mx-4 my-4" />
35
35
  <div
36
36
  id="new-comment-buttons"
@@ -21,7 +21,6 @@ import { UserModel } from '../../../../../../libs/common/domain/src/lib/model/us
21
21
  export class UserFeedbackItemComponent implements OnInit {
22
22
  @Input() userFeedbackParent: UserFeedbackViewModel
23
23
  @Input() userFeedBacksAnswers: UserFeedbackViewModel[]
24
- @Input() isActiveUserEditor: boolean
25
24
  @Input() activeUser: UserModel
26
25
  @Input() isLastComment: boolean
27
26
  @Input() isAddUserFeedbackLoading: boolean
@@ -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
@@ -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,
@@ -4,6 +4,7 @@
4
4
 
5
5
  :host {
6
6
  position: relative;
7
+ display: block;
7
8
  }
8
9
 
9
10
  .carousel-step-dot {
@@ -144,6 +144,7 @@ export function loadAppConfig() {
144
144
  [],
145
145
  [
146
146
  'max_zoom',
147
+ 'do_not_tile_wms',
147
148
  'max_extent',
148
149
  'baselayer',
149
150
  'do_not_use_default_basemap',
@@ -158,6 +159,7 @@ export function loadAppConfig() {
158
159
  ? null
159
160
  : ({
160
161
  MAX_ZOOM: parsedMapSection.max_zoom,
162
+ DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
161
163
  MAX_EXTENT: parsedMapSection.max_extent,
162
164
  EXTERNAL_VIEWER_URL_TEMPLATE:
163
165
  parsedMapSection.external_viewer_url_template,
@@ -81,6 +81,7 @@ export const MAP_CONFIG_FIXTURE: MapConfig = {
81
81
  MAX_ZOOM: 10,
82
82
  MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
83
83
  DO_NOT_USE_DEFAULT_BASEMAP: false,
84
+ DO_NOT_TILE_WMS: false,
84
85
  EXTERNAL_VIEWER_URL_TEMPLATE:
85
86
  'https://example.com/myviewer/#/?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["${layer_name}"],"sources":[{"url":"${service_url}","type":"${service_type}"}]}]',
86
87
  EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
@@ -20,6 +20,7 @@ export interface LayerConfig {
20
20
 
21
21
  export interface MapConfig {
22
22
  MAX_ZOOM?: number
23
+ DO_NOT_TILE_WMS: boolean
23
24
  MAX_EXTENT?: [number, number, number, number] // Expressed as [minx, miny, maxx, maxy]
24
25
  EXTERNAL_VIEWER_URL_TEMPLATE?: string
25
26
  EXTERNAL_VIEWER_OPEN_NEW_TAB?: boolean