geonetwork-ui 2.8.0-dev.398701d7f → 2.8.0-dev.50da356b9

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 (108) hide show
  1. package/esm2022/index.mjs +2 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/common/distribution.mapper.mjs +5 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +3 -1
  4. package/esm2022/libs/api/repository/src/lib/gn4/auth/auth.service.mjs +2 -2
  5. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.mjs +7 -3
  6. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +10 -10
  7. package/esm2022/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.mjs +3 -2
  8. package/esm2022/libs/common/domain/src/index.mjs +3 -0
  9. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +3 -1
  10. package/esm2022/libs/common/domain/src/lib/model/search/sort-by.model.mjs +6 -1
  11. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  12. package/esm2022/libs/data-access/gn4/src/openapi/model/user.api.model.mjs +1 -1
  13. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +3 -1
  14. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +2 -1
  15. package/esm2022/libs/feature/router/src/lib/default/router.service.mjs +5 -1
  16. package/esm2022/libs/feature/router/src/lib/default/state/router.effects.mjs +9 -7
  17. package/esm2022/libs/feature/search/src/lib/sort-by/sort-by.component.mjs +8 -12
  18. package/esm2022/libs/ui/elements/src/lib/error/error.component.mjs +3 -3
  19. package/esm2022/libs/ui/elements/src/lib/external-link-card/external-link-card.component.mjs +11 -4
  20. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +3 -3
  21. package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +2 -3
  22. package/esm2022/libs/util/shared/src/lib/links/link-classifier.service.mjs +5 -1
  23. package/esm2022/libs/util/shared/src/lib/links/link-utils.mjs +12 -1
  24. package/esm2022/libs/util/shared/src/lib/services/proxy.service.mjs +9 -11
  25. package/esm2022/libs/util/shared/src/lib/utils/sort-by.mjs +9 -6
  26. package/esm2022/translations/de.json +7 -2
  27. package/esm2022/translations/en.json +8 -4
  28. package/esm2022/translations/es.json +7 -2
  29. package/esm2022/translations/fr.json +8 -3
  30. package/esm2022/translations/it.json +8 -3
  31. package/esm2022/translations/nl.json +7 -2
  32. package/esm2022/translations/pt.json +7 -2
  33. package/esm2022/translations/sk.json +7 -2
  34. package/fesm2022/geonetwork-ui.mjs +150 -70
  35. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  36. package/index.d.ts +1 -0
  37. package/index.d.ts.map +1 -1
  38. package/index.ts +1 -0
  39. package/libs/api/metadata-converter/src/lib/common/distribution.mapper.d.ts.map +1 -1
  40. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  41. package/libs/api/repository/src/lib/gn4/auth/auth.service.d.ts.map +1 -1
  42. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts.map +1 -1
  43. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +7 -7
  44. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  45. package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts.map +1 -1
  46. package/libs/common/domain/src/index.d.ts +3 -0
  47. package/libs/common/domain/src/index.d.ts.map +1 -0
  48. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +1 -1
  49. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  50. package/libs/common/domain/src/lib/model/search/sort-by.model.d.ts.map +1 -1
  51. package/libs/common/domain/src/lib/platform.service.interface.d.ts +1 -1
  52. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  53. package/libs/data-access/gn4/src/openapi/model/user.api.model.d.ts +1 -1
  54. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts.map +1 -1
  55. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  56. package/libs/feature/router/src/lib/default/router.service.d.ts +2 -0
  57. package/libs/feature/router/src/lib/default/router.service.d.ts.map +1 -1
  58. package/libs/feature/router/src/lib/default/state/router.effects.d.ts +3 -1
  59. package/libs/feature/router/src/lib/default/state/router.effects.d.ts.map +1 -1
  60. package/libs/feature/search/src/lib/sort-by/sort-by.component.d.ts +4 -3
  61. package/libs/feature/search/src/lib/sort-by/sort-by.component.d.ts.map +1 -1
  62. package/libs/ui/elements/src/lib/downloads-list/downloads-list.component.d.ts +1 -1
  63. package/libs/ui/elements/src/lib/external-link-card/external-link-card.component.d.ts +3 -2
  64. package/libs/ui/elements/src/lib/external-link-card/external-link-card.component.d.ts.map +1 -1
  65. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts.map +1 -1
  66. package/libs/util/shared/src/lib/links/link-classifier.service.d.ts.map +1 -1
  67. package/libs/util/shared/src/lib/links/link-utils.d.ts +6 -0
  68. package/libs/util/shared/src/lib/links/link-utils.d.ts.map +1 -1
  69. package/libs/util/shared/src/lib/services/proxy.service.d.ts +5 -4
  70. package/libs/util/shared/src/lib/services/proxy.service.d.ts.map +1 -1
  71. package/libs/util/shared/src/lib/utils/sort-by.d.ts.map +1 -1
  72. package/package.json +2 -2
  73. package/src/libs/api/metadata-converter/src/lib/common/distribution.mapper.ts +2 -0
  74. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -0
  75. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +4 -1
  76. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +12 -4
  77. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +37 -36
  78. package/src/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.ts +3 -2
  79. package/src/libs/common/domain/src/index.ts +2 -0
  80. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -0
  81. package/src/libs/common/domain/src/lib/model/search/sort-by.model.ts +5 -0
  82. package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -1
  83. package/src/libs/common/fixtures/src/lib/elasticsearch/metadata-links.fixtures.ts +5 -0
  84. package/src/libs/common/fixtures/src/lib/link.fixtures.ts +19 -0
  85. package/src/libs/data-access/gn4/src/openapi/model/user.api.model.ts +1 -1
  86. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +1 -0
  87. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +1 -0
  88. package/src/libs/feature/router/src/lib/default/router.service.ts +8 -0
  89. package/src/libs/feature/router/src/lib/default/state/router.effects.ts +6 -7
  90. package/src/libs/feature/search/src/lib/sort-by/sort-by.component.ts +8 -12
  91. package/src/libs/ui/elements/src/lib/error/error.component.html +5 -1
  92. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +43 -22
  93. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +12 -3
  94. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +2 -2
  95. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts +4 -2
  96. package/src/libs/util/shared/src/lib/links/link-classifier.service.ts +4 -0
  97. package/src/libs/util/shared/src/lib/links/link-utils.ts +11 -0
  98. package/src/libs/util/shared/src/lib/services/proxy.service.ts +6 -2
  99. package/src/libs/util/shared/src/lib/utils/sort-by.ts +8 -5
  100. package/translations/de.json +7 -2
  101. package/translations/en.json +8 -4
  102. package/translations/es.json +7 -2
  103. package/translations/fr.json +8 -3
  104. package/translations/it.json +8 -3
  105. package/translations/nl.json +7 -2
  106. package/translations/pt.json +7 -2
  107. package/translations/sk.json +7 -2
  108. package/src/libs/common/domain/src/lib/index.ts +0 -2
@@ -1,12 +1,21 @@
1
+ import { HttpClient, HttpEventType } from '@angular/common/http'
1
2
  import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'
2
3
  import {
3
- catchError,
4
- filter,
5
- map,
6
- mergeMap,
7
- shareReplay,
8
- tap,
9
- } from 'rxjs/operators'
4
+ KeywordApiResponse,
5
+ ThesaurusApiResponse,
6
+ } from '../../../../../../../libs/api/metadata-converter/src'
7
+ import {
8
+ CatalogRecord,
9
+ Keyword,
10
+ Organization,
11
+ UserFeedback,
12
+ } from '../../../../../../../libs/common/domain/src/lib/model/record'
13
+ import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
14
+ import { UserModel } from '../../../../../../../libs/common/domain/src/lib/model/user/user.model'
15
+ import {
16
+ PlatformServiceInterface,
17
+ UploadEvent,
18
+ } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
10
19
  import {
11
20
  MeApiService,
12
21
  RecordsApiService,
@@ -15,26 +24,9 @@ import {
15
24
  UserfeedbackApiService,
16
25
  UsersApiService,
17
26
  } from '../../../../../../../libs/data-access/gn4/src'
18
- import {
19
- PlatformServiceInterface,
20
- UploadEvent,
21
- } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
22
- import { UserModel } from '../../../../../../../libs/common/domain/src/lib/model/user/user.model'
23
- import {
24
- CatalogRecord,
25
- Keyword,
26
- Organization,
27
- UserFeedback,
28
- } from '../../../../../../../libs/common/domain/src/lib/model/record'
29
- import { Gn4PlatformMapper } from './gn4-platform.mapper'
30
- import { ltr } from 'semver'
31
- import { HttpClient, HttpEventType } from '@angular/common/http'
32
- import {
33
- KeywordApiResponse,
34
- ThesaurusApiResponse,
35
- } from '../../../../../../../libs/api/metadata-converter/src'
36
- import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
27
+ import { toLang3 } from '../../../../../../../libs/util/i18n/src'
37
28
  import { noDuplicateFileName } from '../../../../../../../libs/util/shared/src'
29
+ import { TranslateService } from '@ngx-translate/core'
38
30
  import {
39
31
  combineLatest,
40
32
  forkJoin,
@@ -43,9 +35,17 @@ import {
43
35
  switchMap,
44
36
  throwError,
45
37
  } from 'rxjs'
46
- import { TranslateService } from '@ngx-translate/core'
47
- import { toLang3 } from '../../../../../../../libs/util/i18n/src'
38
+ import {
39
+ catchError,
40
+ filter,
41
+ map,
42
+ mergeMap,
43
+ shareReplay,
44
+ tap,
45
+ } from 'rxjs/operators'
46
+ import { ltr } from 'semver'
48
47
  import { Gn4SettingsService } from '../settings/gn4-settings.service'
48
+ import { Gn4PlatformMapper } from './gn4-platform.mapper'
49
49
 
50
50
  const minApiVersion = '4.2.2'
51
51
 
@@ -56,7 +56,6 @@ export const DISABLE_AUTH = new InjectionToken<boolean>('gnDisableAuth', {
56
56
  @Injectable()
57
57
  export class Gn4PlatformService implements PlatformServiceInterface {
58
58
  private readonly type = 'GeoNetwork'
59
- private readonly me$: Observable<UserModel>
60
59
  private readonly users$: Observable<UserModel[]>
61
60
  private readonly isUserAnonymous$: Observable<boolean>
62
61
  private readonly gnParseVersion = '4.2.5'
@@ -70,6 +69,15 @@ export class Gn4PlatformService implements PlatformServiceInterface {
70
69
  }),
71
70
  shareReplay(1)
72
71
  )
72
+
73
+ private me$ = this.disableAuth
74
+ ? of(null)
75
+ : of(true).pipe(
76
+ switchMap(() => this.meApi.getMe()),
77
+ switchMap((apiUser) => this.mapper.userFromMeApi(apiUser)),
78
+ shareReplay({ bufferSize: 1, refCount: true })
79
+ )
80
+
73
81
  /**
74
82
  * A map of already loaded thesauri (groups of keywords); the key is a URI
75
83
  * @private
@@ -93,13 +101,6 @@ export class Gn4PlatformService implements PlatformServiceInterface {
93
101
  private settingsService: Gn4SettingsService,
94
102
  @Inject(DISABLE_AUTH) @Optional() private disableAuth: boolean
95
103
  ) {
96
- this.me$ = this.disableAuth
97
- ? of(null)
98
- : this.meApi.getMe().pipe(
99
- switchMap((apiUser) => this.mapper.userFromMeApi(apiUser)),
100
- shareReplay({ bufferSize: 1, refCount: true })
101
- )
102
-
103
104
  this.isUserAnonymous$ = this.me$.pipe(
104
105
  map((user) => !user || !('id' in user))
105
106
  )
@@ -1,7 +1,7 @@
1
1
  import { Injectable } from '@angular/core'
2
2
  import { SiteApiService } from '../../../../../../../libs/data-access/gn4/src'
3
+ import { Observable, of, switchMap } from 'rxjs'
3
4
  import { map, shareReplay } from 'rxjs/operators'
4
- import { Observable } from 'rxjs'
5
5
 
6
6
  @Injectable({
7
7
  providedIn: 'root',
@@ -25,7 +25,8 @@ export class Gn4SettingsService {
25
25
  constructor(private siteApiService: SiteApiService) {}
26
26
 
27
27
  private getSettingsSetValueByKey(key: string) {
28
- return this.siteApiService.getSettingsSet(null, [key]).pipe(
28
+ return of(true).pipe(
29
+ switchMap(() => this.siteApiService.getSettingsSet(null, [key])),
29
30
  map((v) => v[key]),
30
31
  shareReplay({ bufferSize: 1, refCount: true })
31
32
  )
@@ -0,0 +1,2 @@
1
+ export * from './lib/organizations.service.interface'
2
+ export * from './lib/platform.service.interface'
@@ -163,6 +163,8 @@ export type ServiceProtocol =
163
163
  | 'GPFDL'
164
164
  | 'tms'
165
165
  | 'maplibre-style'
166
+ | 'postgis'
167
+ | 'stac'
166
168
  | 'other'
167
169
 
168
170
  marker('record.metadata.api.accessServiceProtocol.wms')
@@ -174,6 +176,8 @@ marker('record.metadata.api.accessServiceProtocol.ogcFeatures')
174
176
  marker('record.metadata.api.accessServiceProtocol.GPFDL')
175
177
  marker('record.metadata.api.accessServiceProtocol.tms')
176
178
  marker('record.metadata.api.accessServiceProtocol.maplibre-style')
179
+ marker('record.metadata.api.accessServiceProtocol.postgis')
180
+ marker('record.metadata.api.accessServiceProtocol.stac')
177
181
  marker('record.metadata.api.accessServiceProtocol.other')
178
182
 
179
183
  export type OnlineResourceType = 'service' | 'download' | 'link' | 'endpoint'
@@ -6,4 +6,9 @@ export const SortByEnum: Record<string, SortByField> = {
6
6
  RELEVANCY: ['desc', '_score'],
7
7
  QUALITY_SCORE: ['desc', 'qualityScore'],
8
8
  CHANGE_DATE: ['desc', 'changeDate'],
9
+ RESOURCE_DATES: [
10
+ ['desc', 'revisionDateForResource'],
11
+ ['desc', 'publicationDateForResource'],
12
+ ['desc', 'creationDateForResource'],
13
+ ],
9
14
  }
@@ -45,6 +45,7 @@ export abstract class PlatformServiceInterface {
45
45
  thesaurusId: string
46
46
  ): Observable<Keyword[]>
47
47
 
48
+ abstract getFeedbacksAllowed(): Observable<boolean>
48
49
  abstract getUserFeedbacks(recordUuid: string): Observable<UserFeedback[]>
49
50
  abstract postUserFeedbacks(recordUuid: UserFeedback): Observable<void>
50
51
 
@@ -58,5 +59,4 @@ export abstract class PlatformServiceInterface {
58
59
  removeDuplicate?: boolean
59
60
  ): Observable<UploadEvent>
60
61
  abstract getFileContent(url: URL): Observable<any>
61
- abstract getFeedbacksAllowed(): Observable<boolean>
62
62
  }
@@ -154,4 +154,9 @@ export const elasticLinkFixture = (): Record<string, unknown> => ({
154
154
  name: 'myothertmslayer',
155
155
  url: 'https://my.tms.server/MapServer',
156
156
  },
157
+ stacItems: {
158
+ accessServiceProtocol: 'STAC:Items',
159
+ name: 'stac layer',
160
+ url: ' https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/lidarhd/items',
161
+ },
157
162
  })
@@ -259,4 +259,23 @@ export const aSetOfLinksFixture = () => ({
259
259
  accessServiceProtocol: 'wms',
260
260
  type: 'endpoint',
261
261
  }) as ServiceEndpoint,
262
+ postgisLink: () =>
263
+ ({
264
+ name: 'France_Regions',
265
+ description:
266
+ 'Boundaries for the administrative regions of metropolitan France.',
267
+ url: new URL('http://geo.local:5432/france_demo'),
268
+ type: 'service',
269
+ accessServiceProtocol: 'postgis',
270
+ }) as DatasetServiceDistribution,
271
+ stacLink: () =>
272
+ ({
273
+ name: 'Lidar HD point cloud (COPC)',
274
+ description: 'Lidar HD classified point clouds from IGN',
275
+ url: new URL(
276
+ 'https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/lidarhd/items'
277
+ ),
278
+ type: 'service',
279
+ accessServiceProtocol: 'stac',
280
+ }) as DatasetServiceDistribution,
262
281
  })
@@ -21,7 +21,7 @@ export interface UserApiModel {
21
21
  emailAddresses?: Set<string>
22
22
  addresses?: Set<AddressApiModel>
23
23
  primaryAddress?: AddressApiModel
24
- organization?: string
24
+ organisation?: string
25
25
  kind?: string
26
26
  lastLoginDate?: string
27
27
  authorities?: Array<GrantedAuthorityApiModel>
@@ -108,6 +108,7 @@ export class ChartViewComponent {
108
108
  chartType$ = new BehaviorSubject<InputChartType>('bar')
109
109
 
110
110
  @Input() set userChartConfig(config: DatavizChartConfigModel) {
111
+ if (!config) return
111
112
  this.aggregation$.next(config.aggregation)
112
113
  this.xProperty$.next(config.xProperty)
113
114
  this.yProperty$.next(config.yProperty)
@@ -114,6 +114,7 @@ export class MapViewComponent implements AfterViewInit {
114
114
  _styleFromConfig = null
115
115
 
116
116
  linkMap: Map<string, DatasetOnlineResource> = new Map()
117
+ // FIXME the map view component should not need a selectedView
117
118
  @Input() set selectedView(value: string) {
118
119
  this.selectedView$.next(value)
119
120
  }
@@ -8,6 +8,10 @@ import {
8
8
  } from '.'
9
9
  import { Router, Routes } from '@angular/router'
10
10
  import { ROUTER_CONFIG, RouterConfigModel } from './router.config'
11
+ import {
12
+ SortByEnum,
13
+ SortByField,
14
+ } from '../../../../../../libs/common/domain/src/lib/model/search'
11
15
 
12
16
  @Injectable({
13
17
  providedIn: 'root',
@@ -58,4 +62,8 @@ export class RouterService {
58
62
  getOrganizationPageRoute(): string {
59
63
  return ROUTER_ROUTE_ORGANIZATION
60
64
  }
65
+
66
+ getDefaultSort(): SortByField {
67
+ return SortByEnum.RESOURCE_DATES
68
+ }
61
69
  }
@@ -9,10 +9,7 @@ import {
9
9
  SetFilters,
10
10
  SetSortBy,
11
11
  } from '../../../../../../../libs/feature/search/src'
12
- import {
13
- FieldFilters,
14
- SortByEnum,
15
- } from '../../../../../../../libs/common/domain/src/lib/model/search'
12
+ import { FieldFilters } from '../../../../../../../libs/common/domain/src/lib/model/search'
16
13
  import { Actions, createEffect, ofType } from '@ngrx/effects'
17
14
  import { navigation } from '@ngrx/router-store/data-persistence'
18
15
  import { of, pairwise, startWith } from 'rxjs'
@@ -22,6 +19,7 @@ import { RouterFacade } from './router.facade'
22
19
  import { ROUTE_PARAMS } from '../constants'
23
20
  import { sortByFromString } from '../../../../../../../libs/util/shared/src'
24
21
  import { ROUTER_CONFIG, RouterConfigModel } from '../router.config'
22
+ import { RouterService } from '../router.service'
25
23
 
26
24
  @Injectable()
27
25
  export class RouterEffects {
@@ -31,7 +29,8 @@ export class RouterEffects {
31
29
  private _location: Location,
32
30
  private facade: RouterFacade,
33
31
  @Inject(ROUTER_CONFIG) private routerConfig: RouterConfigModel,
34
- private fieldsService: FieldsService
32
+ private fieldsService: FieldsService,
33
+ private routerService: RouterService
35
34
  ) {}
36
35
 
37
36
  navigate$ = createEffect(
@@ -61,7 +60,7 @@ export class RouterEffects {
61
60
  let sortBy =
62
61
  ROUTE_PARAMS.SORT in newParams
63
62
  ? sortByFromString(newParams[ROUTE_PARAMS.SORT])
64
- : SortByEnum.CHANGE_DATE
63
+ : this.routerService.getDefaultSort()
65
64
  let pageNumber =
66
65
  ROUTE_PARAMS.PAGE in newParams
67
66
  ? parseInt(newParams[ROUTE_PARAMS.PAGE])
@@ -70,7 +69,7 @@ export class RouterEffects {
70
69
  const oldSort =
71
70
  ROUTE_PARAMS.SORT in oldParams
72
71
  ? sortByFromString(oldParams[ROUTE_PARAMS.SORT])
73
- : SortByEnum.CHANGE_DATE
72
+ : this.routerService.getDefaultSort()
74
73
  if (JSON.stringify(sortBy) === JSON.stringify(oldSort)) {
75
74
  sortBy = null
76
75
  }
@@ -13,7 +13,7 @@ import { TranslatePipe } from '@ngx-translate/core'
13
13
 
14
14
  interface SortChoice {
15
15
  label: string
16
- value: string
16
+ value: SortByField
17
17
  }
18
18
 
19
19
  @Component({
@@ -27,24 +27,20 @@ export class SortByComponent implements OnInit {
27
27
  choices: SortChoice[] = [
28
28
  {
29
29
  label: marker('results.sortBy.relevancy'),
30
- value: SortByEnum.RELEVANCY.join(','),
30
+ value: SortByEnum.RELEVANCY,
31
31
  },
32
32
  {
33
33
  label: marker('results.sortBy.dateStamp'),
34
- value: SortByEnum.CREATE_DATE.join(','),
35
- },
36
- {
37
- label: marker('results.sortBy.changeDate'),
38
- value: SortByEnum.CHANGE_DATE.join(','),
34
+ value: SortByEnum.RESOURCE_DATES,
39
35
  },
40
36
  {
41
37
  label: marker('results.sortBy.popularity'),
42
- value: SortByEnum.POPULARITY.join(','),
38
+ value: SortByEnum.POPULARITY,
43
39
  },
44
40
  ]
45
41
  currentSortBy$ = this.facade.sortBy$.pipe(
46
42
  filter((sortBy) => !!sortBy),
47
- map((sortBy) => sortBy.join(','))
43
+ map((sortBy) => sortBy)
48
44
  )
49
45
 
50
46
  constructor(
@@ -56,12 +52,12 @@ export class SortByComponent implements OnInit {
56
52
  if (this.isQualitySortable) {
57
53
  this.choices.push({
58
54
  label: marker('results.sortBy.qualityScore'),
59
- value: SortByEnum.QUALITY_SCORE.join(','),
55
+ value: SortByEnum.QUALITY_SCORE,
60
56
  })
61
57
  }
62
58
  }
63
59
 
64
- changeSortBy(criteriaAsString: string) {
65
- this.searchService.setSortBy(criteriaAsString.split(',') as SortByField)
60
+ changeSortBy(criteria: SortByField): void {
61
+ this.searchService.setSortBy(criteria)
66
62
  }
67
63
  }
@@ -1,5 +1,9 @@
1
1
  <div
2
- class="p-[1.7em] bg-red-50 text-red-800 text-[1.5em] text-center rounded-lg"
2
+ class="p-[1.7em] text-[1.5em] text-center rounded-lg"
3
+ [ngClass]="{
4
+ 'bg-red-50 text-red-800': type !== types.DATASET_HAS_NO_LINK,
5
+ 'bg-gray-100 text-black': type === types.DATASET_HAS_NO_LINK,
6
+ }"
3
7
  >
4
8
  <div
5
9
  *ngIf="type === types.COULD_NOT_REACH_API"
@@ -1,15 +1,48 @@
1
- <a
2
- [href]="link.url"
3
- target="_blank"
4
- class="group flex flex-row justify-between card-shadow cursor-pointer rounded overflow-hidden"
5
- [ngClass]="cardClass"
6
- [title]="title"
7
- >
1
+ <ng-container *ngIf="isDatabase; else clickableLink">
2
+ <div [ngClass]="cardClass" [title]="title">
3
+ <ng-container *ngTemplateOutlet="cardContent"></ng-container>
4
+ <div
5
+ class="flex min-w-[32px]"
6
+ [ngClass]="size === 'S' ? 'items-end' : 'items-center'"
7
+ >
8
+ <div
9
+ class="gn-ui-card-icon"
10
+ [title]="'record.metadata.link.postgis.tooltip' | translate"
11
+ >
12
+ <ng-icon
13
+ class="inline-block card-icon align-middle"
14
+ name="iconoirDatabase"
15
+ ></ng-icon>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </ng-container>
20
+
21
+ <ng-template #clickableLink>
22
+ <a [href]="link.url" target="_blank" [ngClass]="cardClass" [title]="title">
23
+ <ng-container *ngTemplateOutlet="cardContent"></ng-container>
24
+ <div
25
+ class="flex min-w-[32px]"
26
+ [ngClass]="size === 'S' ? 'items-end' : 'items-center'"
27
+ >
28
+ <div class="gn-ui-card-icon">
29
+ <ng-icon
30
+ class="inline-block card-icon align-middle"
31
+ name="matOpenInNew"
32
+ ></ng-icon>
33
+ </div>
34
+ </div>
35
+ </a>
36
+ </ng-template>
37
+ <ng-template #cardContent>
8
38
  <div class="flex flex-col justify-between flex-1 min-w-0">
9
39
  <div class="gn-ui-card-title">
10
40
  {{ link.description || link.name }}
11
41
  </div>
12
42
  <div class="gn-ui-card-detail">
43
+ <ng-container *ngIf="isDatabase">
44
+ {{ 'record.metadata.link.postgis.table' | translate }}
45
+ </ng-container>
13
46
  {{ link.name }}
14
47
  </div>
15
48
  <p *ngIf="!link.name && !link.description" class="gn-ui-card-title">
@@ -20,21 +53,9 @@
20
53
  class="inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded transition-opacity opacity-70 group-hover:opacity-100"
21
54
  [style.background-color]="getLinkColor(link)"
22
55
  data-cy="download-format"
23
- >{{
24
- getLinkFormat(link) || ('downloads.format.unknown' | translate)
25
- }}</span
26
56
  >
57
+ {{ getLinkFormat(link) || ('downloads.format.unknown' | translate) }}
58
+ </span>
27
59
  </div>
28
60
  </div>
29
- <div
30
- class="flex min-w-[32px]"
31
- [ngClass]="size === 'S' ? 'items-end' : 'items-center'"
32
- >
33
- <div class="gn-ui-card-icon">
34
- <ng-icon
35
- class="inline-block card-icon align-middle"
36
- name="matOpenInNew"
37
- ></ng-icon>
38
- </div>
39
- </div>
40
- </a>
61
+ </ng-template>
@@ -7,6 +7,7 @@ import {
7
7
  provideNgIconsConfig,
8
8
  } from '@ng-icons/core'
9
9
  import { matOpenInNew } from '@ng-icons/material-icons/baseline'
10
+ import { iconoirDatabase } from '@ng-icons/iconoir'
10
11
  import { getBadgeColor, getFileFormat } from '../../../../../../libs/util/shared/src'
11
12
  import { TranslatePipe } from '@ngx-translate/core'
12
13
 
@@ -21,6 +22,7 @@ type CardSize = 'L' | 'M' | 'S' | 'XS'
21
22
  providers: [
22
23
  provideIcons({
23
24
  matOpenInNew,
25
+ iconoirDatabase,
24
26
  }),
25
27
  provideNgIconsConfig({ size: '1.5em' }),
26
28
  ],
@@ -37,7 +39,7 @@ export class ExternalLinkCardComponent {
37
39
 
38
40
  @Input() set size(value: CardSize) {
39
41
  this._size = value
40
- this.cardClass = this.sizeClassMap[value]
42
+ this.cardClass = `group flex flex-row justify-between card-shadow rounded overflow-hidden ${this.sizeClassMap[value]}`
41
43
  }
42
44
  get size(): CardSize {
43
45
  return this._size
@@ -51,11 +53,18 @@ export class ExternalLinkCardComponent {
51
53
  return this.link.name || this.link.description || ''
52
54
  }
53
55
 
54
- getLinkFormat(link: any) {
56
+ get isDatabase(): boolean {
57
+ return (
58
+ this.link.type === 'service' &&
59
+ this.link.accessServiceProtocol === 'postgis'
60
+ )
61
+ }
62
+
63
+ getLinkFormat(link: DatasetOnlineResource): string {
55
64
  return getFileFormat(link)
56
65
  }
57
66
 
58
- getLinkColor(link: any) {
67
+ getLinkColor(link: DatasetOnlineResource): string {
59
68
  return getBadgeColor(getFileFormat(link))
60
69
  }
61
70
  }
@@ -24,7 +24,7 @@
24
24
  ghostClass="h-[31px] w-3/4"
25
25
  [showContent]="fieldReady('keywords')"
26
26
  >
27
- <div *ngIf="metadata.keywords?.length">
27
+ <gn-ui-max-lines [maxLines]="7" *ngIf="metadata.keywords?.length">
28
28
  <div class="metadata-info-keywords sm:pb-4 flex flex-wrap gap-2">
29
29
  <gn-ui-badge
30
30
  class="inline-block lowercase"
@@ -34,7 +34,7 @@
34
34
  >{{ keyword.label }}</gn-ui-badge
35
35
  >
36
36
  </div>
37
- </div>
37
+ </gn-ui-max-lines>
38
38
  </gn-ui-content-ghost>
39
39
  </div>
40
40
 
@@ -90,8 +90,10 @@ export class DropdownSelectorComponent implements OnInit {
90
90
 
91
91
  get selectedChoice(): DropdownChoice {
92
92
  return (
93
- this.choices.find((choice) => choice.value === this.selected) ??
94
- this.choices[0]
93
+ this.choices.find(
94
+ (choice) =>
95
+ JSON.stringify(choice.value) === JSON.stringify(this.selected)
96
+ ) ?? this.choices[0]
95
97
  )
96
98
  }
97
99
 
@@ -39,6 +39,10 @@ export class LinkClassifierService {
39
39
  return [LinkUsage.API, LinkUsage.DOWNLOAD, LinkUsage.GEODATA]
40
40
  case 'GPFDL':
41
41
  return [LinkUsage.API]
42
+ case 'postgis':
43
+ return [LinkUsage.UNKNOWN]
44
+ case 'stac':
45
+ return [LinkUsage.API]
42
46
  default:
43
47
  return [LinkUsage.UNKNOWN]
44
48
  }
@@ -150,6 +150,12 @@ export const FORMATS = {
150
150
  color: '#5A9E6F',
151
151
  mimeTypes: ['image/webp'],
152
152
  },
153
+ postgis: {
154
+ extensions: ['postgis'],
155
+ priority: 18,
156
+ color: '#336791',
157
+ mimeTypes: [],
158
+ },
153
159
  } as const
154
160
 
155
161
  export type FileFormat = keyof typeof FORMATS
@@ -195,6 +201,11 @@ export function getFileFormatFromServiceOutput(
195
201
  export function getFileFormat(
196
202
  link: DatasetOnlineResource | ServiceOnlineResource
197
203
  ): FileFormat {
204
+ if ('accessServiceProtocol' in link) {
205
+ if (link.accessServiceProtocol in FORMATS) {
206
+ return link.accessServiceProtocol as FileFormat
207
+ }
208
+ }
198
209
  if ('mimeType' in link) {
199
210
  const mimeTypeFormat = mimeTypeToFormat(link.mimeType)
200
211
  if (mimeTypeFormat !== null) {
@@ -1,4 +1,4 @@
1
- import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'
1
+ import { Injectable, InjectionToken, Injector } from '@angular/core'
2
2
  import { Location } from '@angular/common'
3
3
 
4
4
  export const PROXY_PATH = new InjectionToken<string>('proxyPath')
@@ -7,8 +7,12 @@ export const PROXY_PATH = new InjectionToken<string>('proxyPath')
7
7
  providedIn: 'root',
8
8
  })
9
9
  export class ProxyService {
10
+ private get proxyPath(): string | null {
11
+ return this.injector.get(PROXY_PATH, null)
12
+ }
13
+
10
14
  constructor(
11
- @Optional() @Inject(PROXY_PATH) private proxyPath: string,
15
+ private injector: Injector,
12
16
  private location: Location
13
17
  ) {}
14
18
 
@@ -6,12 +6,15 @@ export function sortByToStrings(sortBy: SortByField): string[] {
6
6
  }
7
7
 
8
8
  export function sortByToString(sortBy: SortByField): string {
9
- return sortByToStrings(sortBy)[0]
9
+ return sortByToStrings(sortBy).join(',')
10
10
  }
11
11
 
12
12
  export function sortByFromString(sortByString: string): SortByField {
13
- return [
14
- sortByString.startsWith('-') ? 'desc' : 'asc',
15
- sortByString.startsWith('-') ? sortByString.substring(1) : sortByString,
16
- ]
13
+ const fields = sortByString
14
+ .split(',')
15
+ .map((field) => [
16
+ field.startsWith('-') ? 'desc' : 'asc',
17
+ field.startsWith('-') ? field.substring(1) : field,
18
+ ]) as SortByField
19
+ return fields.length > 1 ? fields : (fields[0] as SortByField)
17
20
  }
@@ -418,6 +418,8 @@
418
418
  "record.metadata.api.accessServiceProtocol.maplibre-style": "",
419
419
  "record.metadata.api.accessServiceProtocol.ogcFeatures": "",
420
420
  "record.metadata.api.accessServiceProtocol.other": "",
421
+ "record.metadata.api.accessServiceProtocol.postgis": "",
422
+ "record.metadata.api.accessServiceProtocol.stac": "",
421
423
  "record.metadata.api.accessServiceProtocol.tms": "",
422
424
  "record.metadata.api.accessServiceProtocol.wfs": "",
423
425
  "record.metadata.api.accessServiceProtocol.wms": "",
@@ -465,7 +467,8 @@
465
467
  "record.metadata.isGeographical": "Geographischer Datensatz",
466
468
  "record.metadata.keywords": "Stichworte",
467
469
  "record.metadata.languages": "Sprachen",
468
- "record.metadata.lastUpdate": "Zuletzt aktualisiert am {date}",
470
+ "record.metadata.link.postgis.table": "",
471
+ "record.metadata.link.postgis.tooltip": "",
469
472
  "record.metadata.linked.datasets": "Verknüpfte Datensätze",
470
473
  "record.metadata.linked.records": "Verknüpfte Inhalte",
471
474
  "record.metadata.linked.reuses": "Verknüpfte Wiederverwendungen",
@@ -506,6 +509,9 @@
506
509
  "record.metadata.quality.updateFrequency.failed": "Aktualisierungsfrequenz nicht angegeben",
507
510
  "record.metadata.quality.updateFrequency.success": "Aktualisierungsfrequenz angegeben",
508
511
  "record.metadata.related": "Entdecken Sie den Katalog",
512
+ "record.metadata.resourceCreated": "Erstellt am {date}",
513
+ "record.metadata.resourcePublished": "Veröffentlicht am {date}",
514
+ "record.metadata.resourceUpdated": "Zuletzt aktualisiert am {date}",
509
515
  "record.metadata.ressources.and.links": "Ressourcen und Links",
510
516
  "record.metadata.sheet": "Weitere Informationen verfügbar unter:",
511
517
  "record.metadata.status": "Status",
@@ -542,7 +548,6 @@
542
548
  "results.records.hits.found": "{hits, plural, =0{Keine Ressource entsprechen der angegebenen Suche.} one{1 Ressource gefunden.} other{{hits} Ressourcen gefunden.}}",
543
549
  "results.records.hits.selected": "{ amount } ausgewählt",
544
550
  "results.showMore": "Mehr Ergebnisse anzeigen...",
545
- "results.sortBy.changeDate": "",
546
551
  "results.sortBy.dateStamp": "Neueste",
547
552
  "results.sortBy.popularity": "Beliebtheit",
548
553
  "results.sortBy.qualityScore": "Fertigstellungsanzeige",