geonetwork-ui 2.9.0-dev.d504391c5 → 2.9.0-dev.ec873d387

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 (41) hide show
  1. package/fesm2022/geonetwork-ui.mjs +144 -66
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +13 -4
  4. package/index.d.ts.map +1 -1
  5. package/package.json +6 -6
  6. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.html +8 -10
  7. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +13 -3
  8. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +2 -2
  9. package/src/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.html +4 -4
  10. package/src/libs/feature/record/src/lib/map-view/map-view.component.html +9 -18
  11. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +64 -8
  12. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -1
  13. package/src/libs/feature/router/src/lib/default/router.module.ts +3 -3
  14. package/src/libs/feature/router/src/lib/default/router.service.ts +2 -2
  15. package/src/libs/feature/router/src/lib/default/services/router-search.service.ts +15 -3
  16. package/src/libs/feature/router/src/lib/default/state/router.effects.ts +40 -4
  17. package/src/libs/feature/router/src/lib/default/state/router.facade.ts +2 -0
  18. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +1 -0
  19. package/src/libs/feature/search/src/lib/state/reducer.ts +4 -0
  20. package/src/libs/feature/search/src/lib/utils/service/search.service.ts +2 -0
  21. package/src/libs/ui/elements/src/lib/api-card/api-card.component.html +2 -2
  22. package/src/libs/ui/elements/src/lib/application-banner/application-banner.component.ts +2 -3
  23. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.html +1 -1
  24. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.ts +3 -3
  25. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +1 -1
  26. package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.html +1 -1
  27. package/src/libs/ui/map/src/lib/map-utils.ts +1 -1
  28. package/src/libs/util/app-config/src/lib/app-config.ts +8 -2
  29. package/src/libs/util/app-config/src/lib/fixtures.ts +1 -0
  30. package/src/libs/util/app-config/src/lib/model.ts +1 -0
  31. package/src/libs/util/shared/src/lib/gn-ui-version.ts +5 -4
  32. package/src/libs/util/shared/src/lib/services/theme.service.ts +9 -23
  33. package/tailwind.base.config.js +3 -2
  34. package/translations/de.json +3 -2
  35. package/translations/en.json +2 -1
  36. package/translations/es.json +1 -0
  37. package/translations/fr.json +2 -1
  38. package/translations/it.json +2 -1
  39. package/translations/nl.json +1 -0
  40. package/translations/pt.json +1 -0
  41. package/translations/sk.json +2 -1
@@ -12,7 +12,7 @@
12
12
  </h2>
13
13
  <button
14
14
  (click)="resetUrl()"
15
- class="bg-primary-opacity-50 inline-flex items-center justify-center px-4 py-2 text-white rounded hover:bg-primary transition"
15
+ class="bg-primary/50 inline-flex items-center justify-center px-4 py-2 text-white rounded hover:bg-primary transition"
16
16
  [attr.title]="'record.metadata.api.form.resetTooltip' | translate"
17
17
  [attr.aria-label]="'record.metadata.api.form.resetTooltip' | translate"
18
18
  >
@@ -97,7 +97,7 @@
97
97
  'px-4 py-2 text-white rounded transition ' +
98
98
  ((page$ | async) <= 1
99
99
  ? 'bg-gray-400 cursor-not-allowed '
100
- : 'bg-primary-opacity-50 hover:bg-primary')
100
+ : 'bg-primary/50 hover:bg-primary')
101
101
  "
102
102
  [attr.title]="'record.metadata.api.form.previousPageTooltip' | translate"
103
103
  [attr.aria-label]="
@@ -117,10 +117,10 @@
117
117
  <button
118
118
  (click)="moreResult()"
119
119
  [class]="
120
- 'bg-primary-opacity-50 px-4 py-2 text-white rounded transition ' +
120
+ 'bg-primary/50 px-4 py-2 text-white rounded transition ' +
121
121
  ((page$ | async) >= (pageMax$ | async)
122
122
  ? 'bg-gray-400 cursor-not-allowed '
123
- : 'bg-primary-opacity-50 hover:bg-primary')
123
+ : 'bg-primary/50 hover:bg-primary')
124
124
  "
125
125
  [attr.title]="'record.metadata.api.form.nextPageTooltip' | translate"
126
126
  [attr.aria-label]="'record.metadata.api.form.nextPageTooltip' | translate"
@@ -13,24 +13,15 @@
13
13
  ></gn-ui-dropdown-selector>
14
14
  }
15
15
 
16
- @if ((styleLinks$ | async)?.length > 0) {
17
- <gn-ui-dropdown-selector
18
- class="w-full md:flex-1 md:min-w-0"
19
- extraBtnClass="font-sans font-bold"
20
- [title]="'map.select.style' | translate"
21
- [choices]="styleDropdownChoices$ | async"
22
- [selected]="_styleFromConfig"
23
- (selectValue)="selectStyleToDisplay($event)"
24
- ></gn-ui-dropdown-selector>
25
- } @else {
26
- <gn-ui-dropdown-selector
27
- class="w-full md:flex-1 md:min-w-0 text-gray-400"
28
- extraBtnClass="font-sans font-bold text-gray-400"
29
- [title]="'map.select.style' | translate"
30
- [choices]="styleDropdownChoices$ | async"
31
- [disabled]="true"
32
- ></gn-ui-dropdown-selector>
33
- }
16
+ <gn-ui-dropdown-selector
17
+ class="w-full md:flex-1 md:min-w-0"
18
+ extraBtnClass="font-sans font-bold"
19
+ [title]="'map.select.style' | translate"
20
+ [choices]="styleDropdownChoices$ | async"
21
+ [selected]="selectedStyleId$ | async"
22
+ [disabled]="(styleDropdownChoices$ | async)?.length <= 1"
23
+ (selectValue)="selectStyleToDisplay($event)"
24
+ ></gn-ui-dropdown-selector>
34
25
 
35
26
  <div class="self-end md:ml-2">
36
27
  <gn-ui-external-viewer-button
@@ -11,6 +11,7 @@ import {
11
11
  } from '@angular/core'
12
12
  import { MapUtilsService } from '../../../../../../libs/feature/map/src'
13
13
  import { getLinkId, getLinkLabel } from '../../../../../../libs/util/shared/src'
14
+ import { WmsEndpoint, LayerStyle } from '@camptocamp/ogc-client'
14
15
  import {
15
16
  BehaviorSubject,
16
17
  combineLatest,
@@ -40,6 +41,7 @@ import {
40
41
  createViewFromLayer,
41
42
  MapContext,
42
43
  MapContextLayer,
44
+ MapContextLayerWms,
43
45
  SourceLoadErrorEvent,
44
46
  } from '@geospatial-sdk/core'
45
47
  import {
@@ -77,6 +79,7 @@ marker('map.dropdown.placeholder')
77
79
  marker('wfs.feature.limit')
78
80
  marker('dataset.error.restrictedAccess')
79
81
  marker('map.select.style')
82
+ marker('map.style.default')
80
83
 
81
84
  @Component({
82
85
  selector: 'gn-ui-map-view',
@@ -231,6 +234,14 @@ export class MapViewComponent implements AfterViewInit {
231
234
  })
232
235
  )
233
236
 
237
+ isWmsStyleMode$ = this.selectedSourceLink$.pipe(
238
+ map(
239
+ (src) => src?.type === 'service' && src?.accessServiceProtocol === 'wms'
240
+ ),
241
+ distinctUntilChanged(),
242
+ shareReplay(1)
243
+ )
244
+
234
245
  styleLinks$ = this.selectedSourceLink$.pipe(
235
246
  switchMap((src) => {
236
247
  if (
@@ -262,6 +273,22 @@ export class MapViewComponent implements AfterViewInit {
262
273
  })
263
274
  )
264
275
  }
276
+ if (
277
+ src &&
278
+ src.type === 'service' &&
279
+ src.accessServiceProtocol === 'wms'
280
+ ) {
281
+ return from(new WmsEndpoint(src.url.toString()).isReady()).pipe(
282
+ map((endpoint) => {
283
+ const layer = endpoint.getLayerByName(src.name)
284
+ return layer?.styles || []
285
+ }),
286
+ catchError((error) => {
287
+ this.handleError(error)
288
+ return of([])
289
+ })
290
+ )
291
+ }
265
292
  return of([])
266
293
  }),
267
294
  tap((styles) => {
@@ -274,33 +301,57 @@ export class MapViewComponent implements AfterViewInit {
274
301
  shareReplay(1)
275
302
  )
276
303
 
277
- styleDropdownChoices$ = this.styleLinks$.pipe(
278
- map((links) =>
304
+ styleDropdownChoices$ = combineLatest([
305
+ this.styleLinks$,
306
+ this.isWmsStyleMode$,
307
+ ]).pipe(
308
+ map(([links, isWmsStyleMode]) =>
279
309
  links.length
280
310
  ? links.map((link, index) => ({
281
- label: getLinkLabel(link),
311
+ label: isWmsStyleMode
312
+ ? (link as LayerStyle).title || (link as LayerStyle).name
313
+ : getLinkLabel(link as DatasetOnlineResource),
282
314
  value: index,
283
315
  }))
284
316
  : [
285
317
  {
286
- label: '\u00A0\u00A0\u00A0\u00A0',
318
+ label: this.translateService.instant('map.style.default'),
287
319
  value: 0,
288
320
  },
289
321
  ]
290
322
  )
291
323
  )
292
324
 
325
+ selectedWmsStyleName$ = combineLatest([
326
+ this.styleLinks$,
327
+ this.isWmsStyleMode$,
328
+ this.selectedStyleId$.pipe(distinctUntilChanged()),
329
+ ]).pipe(
330
+ map(([styles, isWmsStyleMode, styleIdx]) =>
331
+ isWmsStyleMode && Array.isArray(styles)
332
+ ? (styles[styleIdx] as LayerStyle)?.name
333
+ : undefined
334
+ )
335
+ )
336
+
293
337
  selectedLink$ = combineLatest([
294
338
  this.selectedSourceLink$,
295
339
  this.styleLinks$,
296
340
  this.selectedStyleId$.pipe(distinctUntilChanged()),
341
+ this.isWmsStyleMode$,
297
342
  ]).pipe(
298
- map(([src, styles, styleIdx]) => (styles.length ? styles[styleIdx] : src)),
343
+ map(([src, styles, styleIdx, isWmsStyleMode]) =>
344
+ !isWmsStyleMode && styles.length ? styles[styleIdx] : src
345
+ ),
299
346
  shareReplay(1)
300
347
  )
301
348
 
302
- currentLayers$ = combineLatest([this.selectedLink$, this.excludeWfs$]).pipe(
303
- switchMap(([link, excludeWfs]) => {
349
+ currentLayers$ = combineLatest([
350
+ this.selectedLink$,
351
+ this.excludeWfs$,
352
+ this.selectedWmsStyleName$,
353
+ ]).pipe(
354
+ switchMap(([link, excludeWfs, wmsStyleName]) => {
304
355
  if (!link) {
305
356
  return of([])
306
357
  }
@@ -315,6 +366,11 @@ export class MapViewComponent implements AfterViewInit {
315
366
  return of([])
316
367
  }
317
368
  return this.getLayerFromLink(link).pipe(
369
+ map((layer) =>
370
+ wmsStyleName && layer.type === 'wms'
371
+ ? { ...layer, style: wmsStyleName }
372
+ : layer
373
+ ),
318
374
  map((layer) => [layer]),
319
375
  catchError((e) => {
320
376
  this.handleError(e)
@@ -394,7 +450,7 @@ export class MapViewComponent implements AfterViewInit {
394
450
  url: link.url.toString(),
395
451
  type: 'wms',
396
452
  name: link.name,
397
- })
453
+ } as MapContextLayerWms)
398
454
  } else if (
399
455
  link.type === 'service' &&
400
456
  link.accessServiceProtocol === 'tms'
@@ -164,7 +164,7 @@ export class MdViewFacade {
164
164
  link.accessServiceProtocol === 'ogcFeatures'
165
165
  ) {
166
166
  return from(
167
- this.dataService.getItemsFromOgcApi(link.url.href)
167
+ this.dataService.getItemsFromOgcApi(link.url.href, 1)
168
168
  ).pipe(
169
169
  map((collectionRecords: OgcApiRecord[]) => {
170
170
  return collectionRecords &&
@@ -1,6 +1,5 @@
1
- import { ModuleWithProviders, NgModule, inject } from '@angular/core'
1
+ import { inject, ModuleWithProviders, NgModule } from '@angular/core'
2
2
  import { RouteReuseStrategy } from '@angular/router'
3
- import { EffectsModule } from '@ngrx/effects'
4
3
  import {
5
4
  FullRouterStateSerializer,
6
5
  routerReducer,
@@ -11,8 +10,9 @@ import { ROUTER_STATE_KEY } from './constants'
11
10
  import { RouterService } from './router.service'
12
11
  import { SearchRouteReuseStrategy } from './SearchRouteReuseStrategy'
13
12
  import { RouterFacade } from './state/router.facade'
14
- import { RouterEffects } from './state/router.effects'
15
13
  import { ROUTER_CONFIG, RouterConfigModel } from './router.config'
14
+ import { RouterEffects } from './state/router.effects'
15
+ import { EffectsModule } from '@ngrx/effects'
16
16
 
17
17
  @NgModule({
18
18
  imports: [
@@ -1,10 +1,10 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import {
3
3
  ROUTER_ROUTE_DATASET,
4
4
  ROUTER_ROUTE_ORGANIZATION,
5
+ ROUTER_ROUTE_REUSE,
5
6
  ROUTER_ROUTE_SEARCH,
6
7
  ROUTER_ROUTE_SERVICE,
7
- ROUTER_ROUTE_REUSE,
8
8
  } from '.'
9
9
  import { Router, Routes } from '@angular/router'
10
10
  import { ROUTER_CONFIG, RouterConfigModel } from './router.config'
@@ -1,4 +1,4 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import {
3
3
  FieldsService,
4
4
  SearchFacade,
@@ -6,6 +6,7 @@ import {
6
6
  } from '../../../../../../../libs/feature/search/src'
7
7
  import {
8
8
  FieldFilters,
9
+ SortByEnum,
9
10
  SortByField,
10
11
  } from '../../../../../../../libs/common/domain/src/lib/model/search'
11
12
  import { ROUTE_PARAMS, SearchRouteParams } from '../constants'
@@ -20,6 +21,7 @@ export class RouterSearchService implements SearchServiceI {
20
21
  private fieldsService = inject(FieldsService)
21
22
 
22
23
  setSortAndFilters(filters: FieldFilters, sortBy: SortByField) {
24
+ console.log('RouterSearchService - setSortAndFilters', { filters, sortBy })
23
25
  this.fieldsService
24
26
  .readFieldValuesFromFilters(filters)
25
27
  .subscribe((values) => {
@@ -31,10 +33,12 @@ export class RouterSearchService implements SearchServiceI {
31
33
  }
32
34
 
33
35
  async setFilters(newFilters: FieldFilters) {
34
- const sortBy = await firstValueFrom(this.searchFacade.sortBy$)
36
+ let sortBy = await firstValueFrom(this.searchFacade.sortBy$)
35
37
  const fieldSearchParams = await firstValueFrom(
36
38
  this.fieldsService.readFieldValuesFromFilters(newFilters)
37
39
  )
40
+ // apply relevancy sort if a full text criteria is given
41
+ sortBy = newFilters['any'] ? SortByEnum.RELEVANCY : sortBy
38
42
  this.facade.setSearch({
39
43
  ...fieldSearchParams,
40
44
  [ROUTE_PARAMS.SORT]: sortBy ? sortByToString(sortBy) : undefined,
@@ -42,13 +46,21 @@ export class RouterSearchService implements SearchServiceI {
42
46
  }
43
47
 
44
48
  async updateFilters(newFilters: FieldFilters) {
49
+ console.log('RouterSearchService - updateFilters', newFilters)
45
50
  const currentFilters = await firstValueFrom(
46
51
  this.searchFacade.searchFilters$
47
52
  )
48
53
  const updatedFilters = { ...currentFilters, ...newFilters }
49
- const newParams = await firstValueFrom(
54
+ let newParams = await firstValueFrom(
50
55
  this.fieldsService.readFieldValuesFromFilters(updatedFilters)
51
56
  )
57
+ if (newFilters['any']) {
58
+ newParams = {
59
+ ...newParams,
60
+ [ROUTE_PARAMS.SORT]: sortByToString(SortByEnum.RELEVANCY),
61
+ }
62
+ }
63
+ console.log('RouterSearchService - updateFilters - newParams', newParams)
52
64
  this.facade.updateSearch(newParams as SearchRouteParams)
53
65
  }
54
66
 
@@ -1,5 +1,5 @@
1
1
  import { Location } from '@angular/common'
2
- import { Injectable, inject } from '@angular/core'
2
+ import { inject, Injectable } from '@angular/core'
3
3
  import { ActivatedRouteSnapshot, Router } from '@angular/router'
4
4
  import { MdViewActions } from '../../../../../../../libs/feature/record/src'
5
5
  import {
@@ -9,15 +9,18 @@ import {
9
9
  SetFilters,
10
10
  SetSortBy,
11
11
  } from '../../../../../../../libs/feature/search/src'
12
- import { FieldFilters } from '../../../../../../../libs/common/domain/src/lib/model/search'
12
+ import {
13
+ FieldFilters,
14
+ SortByEnum,
15
+ } from '../../../../../../../libs/common/domain/src/lib/model/search'
13
16
  import { Actions, createEffect, ofType } from '@ngrx/effects'
14
17
  import { navigation } from '@ngrx/router-store/data-persistence'
15
18
  import { of, pairwise, startWith } from 'rxjs'
16
- import { map, mergeMap, tap } from 'rxjs/operators'
19
+ import { map, mergeMap, take, tap } from 'rxjs/operators'
17
20
  import * as RouterActions from './router.actions'
18
21
  import { RouterFacade } from './router.facade'
19
22
  import { ROUTE_PARAMS } from '../constants'
20
- import { sortByFromString } from '../../../../../../../libs/util/shared/src'
23
+ import { sortByFromString, sortByToString } from '../../../../../../../libs/util/shared/src'
21
24
  import { ROUTER_CONFIG, RouterConfigModel } from '../router.config'
22
25
  import { RouterService } from '../router.service'
23
26
 
@@ -55,6 +58,12 @@ export class RouterEffects {
55
58
  startWith([null, {}] as [Record<string, string>, FieldFilters]),
56
59
  pairwise(),
57
60
  map(([[oldParams, oldFilters], [newParams, newFilters]]) => {
61
+ console.log('RouterEffects - syncSearchState', {
62
+ oldParams,
63
+ newParams,
64
+ oldFilters,
65
+ newFilters,
66
+ })
58
67
  let sortBy =
59
68
  ROUTE_PARAMS.SORT in newParams
60
69
  ? sortByFromString(newParams[ROUTE_PARAMS.SORT])
@@ -103,6 +112,33 @@ export class RouterEffects {
103
112
  )
104
113
  )
105
114
 
115
+ /**
116
+ * This effect is needed because on the page load, the search params from the URL are
117
+ * directly applied to the underlying search facade; this means that it doesn't go
118
+ * through the RouterSearchService which makes sure that a relevancy sort is applied
119
+ * whenever there's a full text search criteria set.
120
+ */
121
+ applyInitialRelevancySort$ = createEffect(
122
+ () =>
123
+ this.facade.searchParams$.pipe(
124
+ take(1),
125
+ tap((filters) => {
126
+ const relevancySort = sortByToString(SortByEnum.RELEVANCY)
127
+ if (
128
+ filters['q'] &&
129
+ (!Array.isArray(filters['q']) || filters['q'].length > 0) &&
130
+ !filters[ROUTE_PARAMS.SORT]
131
+ ) {
132
+ this.facade.updateSearch({
133
+ ...filters,
134
+ [ROUTE_PARAMS.SORT]: relevancySort,
135
+ })
136
+ }
137
+ })
138
+ ),
139
+ { dispatch: false }
140
+ )
141
+
106
142
  /**
107
143
  * This effect will load the metadata when a navigation to
108
144
  * a metadata record happens
@@ -70,6 +70,7 @@ export class RouterFacade {
70
70
  }
71
71
 
72
72
  updateSearch(query?: SearchRouteParams) {
73
+ console.log('RouterFacade - updateSearch', query)
73
74
  this.go({
74
75
  path: this.routerService.getSearchRoute(),
75
76
  ...(query && { query: flattenQueryParams(query) }),
@@ -78,6 +79,7 @@ export class RouterFacade {
78
79
  }
79
80
 
80
81
  setSearch(query?: SearchRouteParams) {
82
+ console.log('RouterFacade - setSearch', query)
81
83
  this.go({
82
84
  path: this.routerService.getSearchRoute(),
83
85
  ...(query && { query: flattenQueryParams(query) }),
@@ -79,6 +79,7 @@ export class FuzzySearchComponent implements OnInit {
79
79
  if (this.inputSubmitted.observers.length > 0) {
80
80
  this.inputSubmitted.emit(any)
81
81
  } else {
82
+ console.log('FuzzySearchComponent - handleInputSubmission', any)
82
83
  this.searchService.updateFilters({ any })
83
84
  }
84
85
  }
@@ -111,7 +111,10 @@ export function reducerSearch(
111
111
  },
112
112
  }
113
113
  }
114
+ // From router.effects
115
+ // From home - fuzzy-search - search.service
114
116
  case fromActions.SET_FILTERS: {
117
+ console.log('reducerSearch - SET_FILTERS', action.payload)
115
118
  return {
116
119
  ...state,
117
120
  params: {
@@ -132,6 +135,7 @@ export function reducerSearch(
132
135
  },
133
136
  }
134
137
  }
138
+ // From results WC
135
139
  case fromActions.SET_SEARCH: {
136
140
  return {
137
141
  ...state,
@@ -19,11 +19,13 @@ export class SearchService implements SearchServiceI {
19
19
  private facade = inject(SearchFacade)
20
20
 
21
21
  setSortAndFilters(filters: FieldFilters, sort: SortByField) {
22
+ console.log('SearchService - setSortAndFilters', { filters, sort })
22
23
  this.setFilters(filters)
23
24
  this.setSortBy(sort)
24
25
  }
25
26
 
26
27
  updateFilters(params: FieldFilters) {
28
+ console.log('SearchService - updateFilters', params)
27
29
  this.facade.searchFilters$
28
30
  .pipe(
29
31
  first(),
@@ -64,7 +64,7 @@
64
64
  <div class="flex flex-row gap-2.5 items-center pt-1">
65
65
  @if (link.accessServiceProtocol !== 'GPFDL') {
66
66
  <span
67
- 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"
67
+ class="bg-primary/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"
68
68
  [ngClass]="{
69
69
  '!bg-primary': currentlyActive,
70
70
  }"
@@ -76,7 +76,7 @@
76
76
  }
77
77
  @if (link.accessServiceProtocol === 'GPFDL') {
78
78
  <span
79
- 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"
79
+ class="bg-primary/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"
80
80
  [ngClass]="{
81
81
  '!bg-primary': currentlyActive,
82
82
  }"
@@ -45,13 +45,12 @@ export class ApplicationBannerComponent {
45
45
  this.icon = 'matWarning'
46
46
  break
47
47
  case 'light':
48
- this.msgClass =
49
- 'bg-primary-opacity-10 border-primary-lightest text-black'
48
+ this.msgClass = 'bg-primary/10 border-primary-lightest text-black'
50
49
  this.icon = 'matInfoOutline'
51
50
  break
52
51
  case 'secondary':
53
52
  default:
54
- this.msgClass = 'bg-primary-opacity-50 border-primary-darker text-black'
53
+ this.msgClass = 'bg-primary/50 border-primary-darker text-black'
55
54
  this.icon = 'matWarningAmberOutline'
56
55
  break
57
56
  }
@@ -85,7 +85,7 @@
85
85
  class="!w-5 !h-5 !text-[20px] opacity-75 shrink-0"
86
86
  name="matPersonOutline"
87
87
  ></ng-icon>
88
- <div class="flex flex-col ml-2">
88
+ <div class="flex flex-col ml-2" data-cy="contact-full-name">
89
89
  <p class="text-sm">
90
90
  {{ contacts[0]?.firstName || '' }}
91
91
  {{ contacts[0]?.lastName || '' }}
@@ -52,9 +52,9 @@ export class MetadataContactComponent {
52
52
 
53
53
  get contacts() {
54
54
  return (
55
- (this.metadata.kind === 'dataset'
56
- ? this.metadata.contactsForResource
57
- : this.metadata.contacts) || []
55
+ (this.metadata.kind === 'service'
56
+ ? this.metadata.contacts
57
+ : this.metadata.contactsForResource) || []
58
58
  )
59
59
  }
60
60
 
@@ -6,7 +6,7 @@
6
6
  </div>
7
7
  <button
8
8
  (click)="resetUrl()"
9
- class="bg-primary-opacity-50 inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded capitalize text-primary-lightest hover:bg-primary transition-colors"
9
+ class="bg-primary/50 inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded capitalize text-primary-lightest hover:bg-primary transition-colors"
10
10
  >
11
11
  <p class="text-[13px] uppercase" translate>
12
12
  record.metadata.api.form.reset
@@ -1,6 +1,6 @@
1
1
  @if (apiLinks.length > 0) {
2
2
  <div style="height: 652px" id="preview">
3
- <div class="bg-primary-opacity-10 overflow-visible" style="height: 420px">
3
+ <div class="bg-primary/10 overflow-visible" style="height: 420px">
4
4
  <div class="container-lg px-4 lg:mx-auto">
5
5
  <div>
6
6
  <div class="gn-ui-section-title mb-6" translate>
@@ -50,7 +50,7 @@ export function dragPanCondition(
50
50
 
51
51
  export function mouseWheelZoomCondition(
52
52
  this: MouseWheelZoom,
53
- event: MapBrowserEvent<UIEvent>
53
+ event: MapBrowserEvent<WheelEvent>
54
54
  ) {
55
55
  if (!platformModifierKeyOnly(event) && event.type === 'wheel') {
56
56
  this.getMap().dispatchEvent('mapmuted')
@@ -70,8 +70,11 @@ export function getCustomTranslations(langCode: string): CustomTranslations {
70
70
 
71
71
  let appConfigLoaded = false
72
72
 
73
- export function loadAppConfig() {
74
- return fetch('assets/configuration/default.toml')
73
+ export function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
74
+ console.log(
75
+ `[geonetwork-ui] Loading application configuration from ${configUrl}`
76
+ )
77
+ return fetch(configUrl)
75
78
  .then((resp) => {
76
79
  if (!resp.ok) throw new Error('Configuration file could not be loaded')
77
80
  return resp.text()
@@ -229,6 +232,7 @@ export function loadAppConfig() {
229
232
  'record_kind_quick_filter',
230
233
  'filter_geometry_data',
231
234
  'filter_geometry_url',
235
+ 'do_not_use_default_search_preset',
232
236
  'search_preset',
233
237
  'advanced_filters',
234
238
  'limit',
@@ -252,6 +256,8 @@ export function loadAppConfig() {
252
256
  parsedSearchSection.record_kind_quick_filter,
253
257
  FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
254
258
  FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
259
+ DO_NOT_USE_DEFAULT_SEARCH_PRESET:
260
+ !!parsedSearchSection.do_not_use_default_search_preset,
255
261
  SEARCH_PRESET: parsedSearchParams.map((param) => ({
256
262
  sort: param.sort,
257
263
  name: param.name,
@@ -40,6 +40,7 @@ fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
40
40
  [search]
41
41
  record_kind_quick_filter = false
42
42
  filter_geometry_url = 'https://my.domain.org/geom.json'
43
+ do_not_use_default_search_preset = false
43
44
  advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license']
44
45
 
45
46
  [[search_preset]]
@@ -58,6 +58,7 @@ export interface SearchConfig {
58
58
  RECORD_KIND_QUICK_FILTER?: boolean
59
59
  FILTER_GEOMETRY_URL?: string
60
60
  FILTER_GEOMETRY_DATA?: string
61
+ DO_NOT_USE_DEFAULT_SEARCH_PRESET?: boolean
61
62
  SEARCH_PRESET?: SearchPreset[]
62
63
  ADVANCED_FILTERS?: []
63
64
  LIMIT?: number
@@ -2,7 +2,8 @@ import packageJson from '../../../../../package.json'
2
2
 
3
3
  export const GEONETWORK_UI_VERSION = packageJson.version
4
4
 
5
- export const GEONETWORK_UI_TAG_NAME =
6
- GEONETWORK_UI_VERSION.split('-')[1] === 'dev'
7
- ? 'main'
8
- : `v${packageJson.version}`
5
+ export const GEONETWORK_UI_TAG_NAME = GEONETWORK_UI_VERSION.split(
6
+ '-'
7
+ )[1]?.startsWith('dev')
8
+ ? 'main'
9
+ : `v${packageJson.version}`
@@ -10,26 +10,6 @@ export class ThemeService {
10
10
  return document.documentElement.style.getPropertyValue(`--color-${name}`)
11
11
  }
12
12
 
13
- static generateBgOpacityClasses(
14
- colorName,
15
- colorValue,
16
- opacities = [0, 10, 25, 50, 75]
17
- ) {
18
- const color = chroma(colorValue)
19
- const styleElement = document.createElement('style')
20
- styleElement.innerHTML = opacities.reduce((cssRules, opacity) => {
21
- cssRules += `.bg-${colorName}-opacity-${opacity}{background-color:${color
22
- .alpha(opacity / 100)
23
- .css()};}`
24
-
25
- cssRules += `.hover-bg-${colorName}-opacity-${opacity}:hover {background-color:${color
26
- .alpha(opacity / 100)
27
- .css()};}`
28
- return cssRules
29
- }, '')
30
- document.getElementsByTagName('head')[0].appendChild(styleElement)
31
- }
32
-
33
13
  static applyCssVariables(
34
14
  primaryColor: string,
35
15
  secondaryColor: string,
@@ -39,13 +19,19 @@ export class ThemeService {
39
19
  titleFont?: string,
40
20
  fontsStylesheetUrl?: string
41
21
  ) {
42
- const applyColor = (name: string, color) => {
22
+ const applyColor = (name: string, color, includeRawValues?: boolean) => {
43
23
  document.documentElement.style.setProperty(`--color-${name}`, color.css())
24
+ if (includeRawValues) {
25
+ document.documentElement.style.setProperty(
26
+ `--color-raw-${name}`,
27
+ color.css().replace(/^rgba?\((.*)\)/, '$1')
28
+ )
29
+ }
44
30
  }
45
31
 
46
32
  const black = chroma('black')
47
33
  const white = chroma('white')
48
- applyColor('primary', chroma(primaryColor))
34
+ applyColor('primary', chroma(primaryColor), true)
49
35
  applyColor(
50
36
  'primary-lighter',
51
37
  chroma.scale([primaryColor, white]).mode('lab')(0.3)
@@ -70,7 +56,7 @@ export class ThemeService {
70
56
  'primary-black',
71
57
  chroma.scale([primaryColor, black]).mode('lab')(0.85)
72
58
  )
73
- applyColor('secondary', chroma(secondaryColor))
59
+ applyColor('secondary', chroma(secondaryColor), true)
74
60
  applyColor(
75
61
  'secondary-lighter',
76
62
  chroma.scale([secondaryColor, white]).mode('lab')(0.3)