geonetwork-ui 2.4.0-dev.6c8dcba0 → 2.4.0-dev.8f04e899

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 (153) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/index.mjs +2 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.mjs +2 -0
  3. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +1 -1
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.mjs +1 -1
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +1 -1
  6. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +5 -5
  7. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.mjs +11 -3
  8. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +34 -14
  9. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  10. package/esm2022/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.mjs +1 -1
  11. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  12. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  13. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +4 -4
  14. package/esm2022/libs/feature/dataviz/src/lib/feature-dataviz.module.mjs +7 -4
  15. package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +1 -1
  16. package/esm2022/libs/feature/editor/src/lib/+state/editor.actions.mjs +2 -1
  17. package/esm2022/libs/feature/editor/src/lib/+state/editor.effects.mjs +6 -4
  18. package/esm2022/libs/feature/editor/src/lib/+state/editor.facade.mjs +2 -1
  19. package/esm2022/libs/feature/editor/src/lib/+state/editor.selectors.mjs +2 -2
  20. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.mjs +57 -0
  21. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.mjs +64 -50
  22. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +17 -35
  23. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/index.mjs +2 -1
  24. package/esm2022/libs/feature/editor/src/lib/feature-editor.module.mjs +4 -3
  25. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +8 -1
  26. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +12 -6
  27. package/esm2022/libs/feature/record/src/lib/feature-record.module.mjs +7 -4
  28. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +3 -3
  29. package/esm2022/libs/feature/search/src/lib/feature-search.module.mjs +7 -4
  30. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
  31. package/esm2022/libs/feature/search/src/lib/results-table/results-table.component.mjs +6 -6
  32. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +4 -4
  33. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +3 -3
  34. package/esm2022/libs/ui/inputs/src/index.mjs +2 -1
  35. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +59 -26
  36. package/esm2022/libs/ui/inputs/src/lib/badge/badge.component.mjs +28 -0
  37. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +11 -10
  38. package/esm2022/libs/ui/widgets/src/index.mjs +1 -2
  39. package/esm2022/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.mjs +5 -3
  40. package/esm2022/libs/ui/widgets/src/lib/ui-widgets.module.mjs +1 -6
  41. package/fesm2022/geonetwork-ui.mjs +520 -393
  42. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  43. package/libs/api/metadata-converter/src/lib/gn4/types/index.d.ts +1 -0
  44. package/libs/api/metadata-converter/src/lib/gn4/types/index.d.ts.map +1 -1
  45. package/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.d.ts +31 -0
  46. package/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.d.ts.map +1 -0
  47. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +3 -2
  48. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  49. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts +1 -1
  50. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts.map +1 -1
  51. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +3 -2
  52. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  53. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  54. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts +3 -3
  55. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts.map +1 -1
  56. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +8 -5
  57. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  58. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +4 -7
  59. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  60. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts +12 -5
  61. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts.map +1 -1
  62. package/libs/common/domain/src/lib/platform.service.interface.d.ts +3 -3
  63. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  64. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +1 -1
  65. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts +2 -1
  66. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts.map +1 -1
  67. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts +1 -0
  68. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts.map +1 -1
  69. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts +1 -1
  70. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts.map +1 -1
  71. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts +1 -0
  72. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts.map +1 -1
  73. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts +25 -0
  74. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts.map +1 -0
  75. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts +6 -6
  76. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts.map +1 -1
  77. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +6 -10
  78. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  79. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts +1 -0
  80. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts.map +1 -1
  81. package/libs/feature/editor/src/lib/feature-editor.module.d.ts.map +1 -1
  82. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  83. package/libs/feature/editor/src/lib/services/editor.service.d.ts +1 -1
  84. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  85. package/libs/feature/record/src/lib/feature-record.module.d.ts +2 -1
  86. package/libs/feature/record/src/lib/feature-record.module.d.ts.map +1 -1
  87. package/libs/feature/search/src/lib/feature-search.module.d.ts +2 -1
  88. package/libs/feature/search/src/lib/feature-search.module.d.ts.map +1 -1
  89. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
  90. package/libs/feature/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  91. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +1 -1
  92. package/libs/ui/inputs/src/index.d.ts +1 -0
  93. package/libs/ui/inputs/src/index.d.ts.map +1 -1
  94. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +7 -4
  95. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  96. package/libs/ui/inputs/src/lib/badge/badge.component.d.ts +11 -0
  97. package/libs/ui/inputs/src/lib/badge/badge.component.d.ts.map +1 -0
  98. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +35 -35
  99. package/libs/ui/widgets/src/index.d.ts +0 -1
  100. package/libs/ui/widgets/src/index.d.ts.map +1 -1
  101. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts +1 -1
  102. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts.map +1 -1
  103. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts +10 -11
  104. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts.map +1 -1
  105. package/package.json +1 -1
  106. package/src/libs/api/metadata-converter/src/lib/gn4/types/index.ts +1 -0
  107. package/src/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.ts +31 -0
  108. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +2 -2
  109. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.ts +1 -1
  110. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +2 -2
  111. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +7 -8
  112. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +24 -3
  113. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +70 -21
  114. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -9
  115. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +13 -6
  116. package/src/libs/common/domain/src/lib/platform.service.interface.ts +3 -3
  117. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +1 -1
  118. package/src/libs/feature/dataviz/src/lib/feature-dataviz.module.ts +2 -1
  119. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +2 -0
  120. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +35 -29
  121. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +1 -0
  122. package/src/libs/feature/editor/src/lib/+state/editor.selectors.ts +1 -1
  123. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +19 -0
  124. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.ts +77 -0
  125. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +95 -86
  126. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +7 -22
  127. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +16 -44
  128. package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -1
  129. package/src/libs/feature/editor/src/lib/feature-editor.module.ts +2 -1
  130. package/src/libs/feature/editor/src/lib/fields.config.ts +7 -0
  131. package/src/libs/feature/editor/src/lib/services/editor.service.ts +20 -6
  132. package/src/libs/feature/record/src/lib/feature-record.module.ts +3 -2
  133. package/src/libs/feature/search/src/lib/feature-search.module.ts +2 -1
  134. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +2 -2
  135. package/src/libs/feature/search/src/lib/results-table/results-table.component.ts +1 -2
  136. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +2 -2
  137. package/src/libs/ui/inputs/src/index.ts +1 -0
  138. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -1
  139. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +23 -19
  140. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +79 -27
  141. package/src/libs/ui/inputs/src/lib/badge/badge.component.css +0 -0
  142. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +18 -0
  143. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +27 -0
  144. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +3 -3
  145. package/src/libs/ui/widgets/src/index.ts +0 -1
  146. package/src/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.ts +4 -0
  147. package/src/libs/ui/widgets/src/lib/ui-widgets.module.ts +0 -3
  148. package/esm2022/libs/ui/widgets/src/lib/badge/badge.component.mjs +0 -18
  149. package/libs/ui/widgets/src/lib/badge/badge.component.d.ts +0 -7
  150. package/libs/ui/widgets/src/lib/badge/badge.component.d.ts.map +0 -1
  151. package/src/libs/ui/widgets/src/lib/badge/badge.component.html +0 -10
  152. package/src/libs/ui/widgets/src/lib/badge/badge.component.ts +0 -14
  153. /package/src/libs/{ui/widgets/src/lib/badge/badge.component.css → feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.css} +0 -0
@@ -1,10 +1,11 @@
1
1
  import { Injectable } from '@angular/core'
2
- import { Observable, of, switchMap } from 'rxjs'
2
+ import { Observable, combineLatest, of, switchMap } from 'rxjs'
3
3
  import { catchError, map, shareReplay, tap } from 'rxjs/operators'
4
4
  import {
5
5
  MeApiService,
6
6
  RegistriesApiService,
7
7
  SiteApiService,
8
+ ThesaurusInfoApiModel,
8
9
  ToolsApiService,
9
10
  UserfeedbackApiService,
10
11
  UsersApiService,
@@ -12,13 +13,18 @@ import {
12
13
  import { PlatformServiceInterface } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
13
14
  import { UserModel } from '../../../../../../../libs/common/domain/src/lib/model/user/user.model'
14
15
  import {
16
+ Keyword,
15
17
  Organization,
16
18
  UserFeedback,
17
19
  } from '../../../../../../../libs/common/domain/src/lib/model/record'
18
20
  import { Gn4PlatformMapper } from './gn4-platform.mapper'
19
21
  import { ltr } from 'semver'
20
- import { ThesaurusModel } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus/thesaurus.model'
21
22
  import { LangService } from '../../../../../../../libs/util/i18n/src'
23
+ import { HttpClient } from '@angular/common/http'
24
+ import {
25
+ KeywordApiResponse,
26
+ ThesaurusApiResponse,
27
+ } from '../../../../../../../libs/api/metadata-converter/src'
22
28
 
23
29
  const minApiVersion = '4.2.2'
24
30
 
@@ -60,7 +66,7 @@ export class Gn4PlatformService implements PlatformServiceInterface {
60
66
  * A map of already loaded thesauri (groups of keywords); the key is a URI
61
67
  * @private
62
68
  */
63
- private thesauri: Record<string, Observable<ThesaurusModel>> = {}
69
+ private keywordsByThesauri: Record<string, Observable<Keyword[]>> = {}
64
70
 
65
71
  constructor(
66
72
  private siteApiService: SiteApiService,
@@ -70,7 +76,8 @@ export class Gn4PlatformService implements PlatformServiceInterface {
70
76
  private toolsApiService: ToolsApiService,
71
77
  private registriesApiService: RegistriesApiService,
72
78
  private langService: LangService,
73
- private userfeedbackApiService: UserfeedbackApiService
79
+ private userfeedbackApiService: UserfeedbackApiService,
80
+ private httpClient: HttpClient
74
81
  ) {
75
82
  this.me$ = this.meApi.getMe().pipe(
76
83
  switchMap((apiUser) => this.mapper.userFromMeApi(apiUser)),
@@ -121,7 +128,7 @@ export class Gn4PlatformService implements PlatformServiceInterface {
121
128
  // the thesaurus URI is inferred by removing a part of the keyword URI
122
129
  // this is not exact science but it's OK, we'll still end up loading a bunch of keywords at once anyway
123
130
  const thesaurusUri = key.replace(/\/([^/]+)$/, '/')
124
- return this.getThesaurusByUri(thesaurusUri).pipe(
131
+ return this.getKeywordsByUri(thesaurusUri).pipe(
125
132
  map((thesaurus) => {
126
133
  for (const item of thesaurus) {
127
134
  if (item.key === key) return item.label
@@ -133,12 +140,49 @@ export class Gn4PlatformService implements PlatformServiceInterface {
133
140
  return this.keyTranslations$.pipe(map((translations) => translations[key]))
134
141
  }
135
142
 
136
- getThesaurusByUri(uri: string): Observable<ThesaurusModel> {
137
- if (this.thesauri[uri]) {
138
- return this.thesauri[uri]
143
+ private allThesaurus$ = this.httpClient
144
+ .get(
145
+ `${this.registriesApiService.configuration.basePath}/thesaurus?_content_type=json`
146
+ )
147
+ .pipe(
148
+ map((thesaurus) => {
149
+ // FIXME: find a better way to exclude place keywords
150
+ // thesaurus[0].filter((thes) => thes.dname !== 'place')
151
+ return thesaurus[0] as ThesaurusApiResponse[]
152
+ }),
153
+ shareReplay(1)
154
+ )
155
+
156
+ searchKeywords(query: string): Observable<Keyword[]> {
157
+ const keywords$: Observable<KeywordApiResponse[]> =
158
+ this.registriesApiService.searchKeywords(
159
+ query,
160
+ this.langService.iso3,
161
+ 10,
162
+ 0,
163
+ null,
164
+ null,
165
+ null,
166
+ `*${query}*`
167
+ ) as Observable<KeywordApiResponse[]>
168
+
169
+ return combineLatest([keywords$, this.allThesaurus$]).pipe(
170
+ map(([keywords, thesaurus]) => {
171
+ return this.mapper.keywordsFromApi(
172
+ keywords,
173
+ thesaurus,
174
+ this.langService.iso3
175
+ )
176
+ })
177
+ )
178
+ }
179
+
180
+ getKeywordsByUri(uri: string): Observable<Keyword[]> {
181
+ if (this.keywordsByThesauri[uri]) {
182
+ return this.keywordsByThesauri[uri]
139
183
  }
140
- this.thesauri[uri] = this.registriesApiService
141
- .searchKeywords(
184
+ const keywords$: Observable<KeywordApiResponse[]> =
185
+ this.registriesApiService.searchKeywords(
142
186
  null,
143
187
  this.langService.iso3,
144
188
  1000,
@@ -147,18 +191,23 @@ export class Gn4PlatformService implements PlatformServiceInterface {
147
191
  null,
148
192
  null,
149
193
  `${uri}*`
150
- )
151
- .pipe(
152
- map((thesaurus) =>
153
- this.mapper.thesaurusFromApi(
154
- thesaurus as any[],
155
- this.langService.iso3
156
- )
157
- ),
158
- shareReplay(1)
159
- )
194
+ ) as Observable<KeywordApiResponse[]>
195
+
196
+ this.keywordsByThesauri[uri] = combineLatest([
197
+ keywords$,
198
+ this.allThesaurus$,
199
+ ]).pipe(
200
+ map(([keywords, thesaurus]) => {
201
+ return this.mapper.keywordsFromApi(
202
+ keywords,
203
+ thesaurus,
204
+ this.langService.iso3
205
+ )
206
+ }),
207
+ shareReplay(1)
208
+ )
160
209
 
161
- return this.thesauri[uri]
210
+ return this.keywordsByThesauri[uri]
162
211
  }
163
212
 
164
213
  getUserFeedbacks(uuid: string): Observable<UserFeedback[]> {
@@ -2,6 +2,7 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
2
2
  import type { Individual } from './contact.model'
3
3
  import type { Organization } from './organization.model'
4
4
  import type { Geometry } from 'geojson'
5
+ import { KeywordType, ThesaurusModel } from '../thesaurus'
5
6
 
6
7
  type Uuid = string
7
8
 
@@ -60,18 +61,12 @@ export type SpatialRepresentationType =
60
61
  | 'table'
61
62
  | 'point'
62
63
 
63
- export type KeywordType = 'place' | 'temporal' | 'theme' | 'other'
64
-
65
- export type KeywordThesaurus = {
66
- id: string
67
- name?: string
68
- url?: URL
69
- }
70
-
71
64
  export interface Keyword {
65
+ key?: string
72
66
  label: string
67
+ description?: string
73
68
  type: KeywordType
74
- thesaurus?: KeywordThesaurus
69
+ thesaurus?: ThesaurusModel
75
70
  }
76
71
  // languages should be expressed using two-letters ISO 639-1 codes
77
72
  export type LanguageCode = string
@@ -1,7 +1,14 @@
1
- export interface ThesaurusItemModel {
2
- key: string
3
- label: string
4
- description?: string
5
- }
1
+ export type KeywordType = 'place' | 'temporal' | 'theme' | 'other'
6
2
 
7
- export type ThesaurusModel = ThesaurusItemModel[]
3
+ export interface ThesaurusModel {
4
+ id: string
5
+ name?: string
6
+ url?: URL
7
+ thesaurusKey?: string
8
+ definition?: string
9
+ definitions?: object
10
+ uri?: string
11
+ value?: string
12
+ values?: object
13
+ type?: KeywordType
14
+ }
@@ -1,8 +1,7 @@
1
1
  import type { Observable } from 'rxjs'
2
2
  import type { UserModel } from './model/user/user.model'
3
3
  import type { Organization } from './model/record/organization.model'
4
- import type { ThesaurusModel } from './model/thesaurus/'
5
- import { UserFeedback } from './model/record'
4
+ import { Keyword, UserFeedback } from './model/record'
6
5
 
7
6
  export abstract class PlatformServiceInterface {
8
7
  abstract getType(): string
@@ -16,7 +15,8 @@ export abstract class PlatformServiceInterface {
16
15
  ): Observable<UserModel[]>
17
16
  abstract getOrganizations(): Observable<Organization[]>
18
17
  abstract translateKey(key: string): Observable<string>
19
- abstract getThesaurusByUri(uri: string): Observable<ThesaurusModel>
18
+ abstract searchKeywords(query: string): Observable<Keyword[]>
19
+ abstract getKeywordsByUri(uri: string): Observable<Keyword[]>
20
20
  abstract getUserFeedbacks(recordUuid: string): Observable<UserFeedback[]>
21
21
  abstract postUserFeedbacks(recordUuid: UserFeedback): Observable<void>
22
22
  }
@@ -33,7 +33,7 @@ export abstract class RecordsRepositoryInterface {
33
33
  /**
34
34
  * @param record
35
35
  * @param referenceRecordSource
36
- * @returns Observable<string> Returns the source of the record as it was serialized when saved
36
+ * @returns Observable<string> Returns the unique identifier of the record as it was when saved
37
37
  */
38
38
  abstract saveRecord(
39
39
  record: CatalogRecord,
@@ -12,7 +12,7 @@ import {
12
12
  import { TableViewComponent } from './table-view/table-view.component'
13
13
  import { ChartViewComponent } from './chart-view/chart-view.component'
14
14
  import { TranslateModule } from '@ngx-translate/core'
15
- import { UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
15
+ import { PopupAlertComponent, UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
16
16
  import { UiInputsModule } from '../../../../../libs/ui/inputs/src'
17
17
 
18
18
  @NgModule({
@@ -26,6 +26,7 @@ import { UiInputsModule } from '../../../../../libs/ui/inputs/src'
26
26
  TranslateModule,
27
27
  ChartComponent,
28
28
  UiInputsModule,
29
+ PopupAlertComponent,
29
30
  ],
30
31
  declarations: [
31
32
  GeoTableViewComponent,
@@ -26,3 +26,5 @@ export const saveRecordFailure = createAction(
26
26
  '[Editor] Save record failure',
27
27
  props<{ error: SaveRecordError }>()
28
28
  )
29
+
30
+ export const draftSaveSuccess = createAction('[Editor] Draft save success')
@@ -5,7 +5,11 @@ import { catchError, map, switchMap } from 'rxjs/operators'
5
5
  import * as EditorActions from './editor.actions'
6
6
  import { EditorService } from '../services/editor.service'
7
7
  import { Store } from '@ngrx/store'
8
- import { selectRecord, selectRecordFieldsConfig } from './editor.selectors'
8
+ import {
9
+ selectRecord,
10
+ selectRecordAlreadySavedOnce,
11
+ selectRecordFieldsConfig,
12
+ } from './editor.selectors'
9
13
  import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
10
14
 
11
15
  @Injectable()
@@ -20,28 +24,31 @@ export class EditorEffects {
20
24
  ofType(EditorActions.saveRecord),
21
25
  withLatestFrom(
22
26
  this.store.select(selectRecord),
23
- this.store.select(selectRecordFieldsConfig)
27
+ this.store.select(selectRecordFieldsConfig),
28
+ this.store.select(selectRecordAlreadySavedOnce)
24
29
  ),
25
- switchMap(([, record, fieldsConfig]) =>
26
- this.editorService.saveRecord(record, fieldsConfig).pipe(
27
- switchMap(([record, recordSource]) =>
28
- of(
29
- EditorActions.saveRecordSuccess(),
30
- EditorActions.openRecord({
31
- record,
32
- alreadySavedOnce: true,
33
- recordSource,
34
- })
35
- )
36
- ),
37
- catchError((error) =>
38
- of(
39
- EditorActions.saveRecordFailure({
40
- error: error.message,
41
- })
30
+ switchMap(([, record, fieldsConfig, alreadySavedOnce]) =>
31
+ this.editorService
32
+ .saveRecord(record, fieldsConfig, !alreadySavedOnce)
33
+ .pipe(
34
+ switchMap(([record, recordSource]) =>
35
+ of(
36
+ EditorActions.saveRecordSuccess(),
37
+ EditorActions.openRecord({
38
+ record,
39
+ alreadySavedOnce: true,
40
+ recordSource,
41
+ })
42
+ )
43
+ ),
44
+ catchError((error) =>
45
+ of(
46
+ EditorActions.saveRecordFailure({
47
+ error: error.message,
48
+ })
49
+ )
42
50
  )
43
51
  )
44
- )
45
52
  )
46
53
  )
47
54
  )
@@ -53,15 +60,14 @@ export class EditorEffects {
53
60
  )
54
61
  )
55
62
 
56
- saveRecordDraft$ = createEffect(
57
- () =>
58
- this.actions$.pipe(
59
- ofType(EditorActions.updateRecordField),
60
- debounceTime(1000),
61
- withLatestFrom(this.store.select(selectRecord)),
62
- switchMap(([, record]) => this.editorService.saveRecordAsDraft(record))
63
- ),
64
- { dispatch: false }
63
+ saveRecordDraft$ = createEffect(() =>
64
+ this.actions$.pipe(
65
+ ofType(EditorActions.updateRecordField),
66
+ debounceTime(1000),
67
+ withLatestFrom(this.store.select(selectRecord)),
68
+ switchMap(([, record]) => this.editorService.saveRecordAsDraft(record)),
69
+ map(() => EditorActions.draftSaveSuccess())
70
+ )
65
71
  )
66
72
 
67
73
  checkHasChangesOnOpen$ = createEffect(() =>
@@ -26,6 +26,7 @@ export class EditorFacade {
26
26
  select(EditorSelectors.selectRecordChangedSinceSave)
27
27
  )
28
28
  recordFields$ = this.store.pipe(select(EditorSelectors.selectRecordFields))
29
+ draftSaveSuccess$ = this.actions$.pipe(ofType(EditorActions.draftSaveSuccess))
29
30
 
30
31
  openRecord(
31
32
  record: CatalogRecord,
@@ -44,6 +44,6 @@ export const selectRecordFields = createSelector(
44
44
  (state: EditorState) =>
45
45
  state.fieldsConfig.map((fieldConfig) => ({
46
46
  config: fieldConfig,
47
- value: state.record?.[fieldConfig.model] || null,
47
+ value: state.record?.[fieldConfig.model] ?? null,
48
48
  }))
49
49
  )
@@ -0,0 +1,19 @@
1
+ <div class="flex flex-col gap-3">
2
+ <gn-ui-autocomplete
3
+ [placeholder]="'Search for keywords in all thesaurus'"
4
+ [displayWithFn]="displayWithFn"
5
+ [action]="autoCompleteAction"
6
+ (itemSelected)="handleItemSelection($event)"
7
+ [clearOnSelection]="true"
8
+ [minCharacterCount]="0"
9
+ [allowSubmit]="false"
10
+ ></gn-ui-autocomplete>
11
+ <div class="flex gap-2 flex-wrap">
12
+ <gn-ui-badge
13
+ *ngFor="let keyword of control.value; let index = index"
14
+ [removable]="true"
15
+ (badgeRemoveClicked)="removeKeyword(index)"
16
+ >{{ keyword.label }}</gn-ui-badge
17
+ >
18
+ </div>
19
+ </div>
@@ -0,0 +1,77 @@
1
+ import { CommonModule } from '@angular/common'
2
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
3
+ import { FormControl } from '@angular/forms'
4
+ import { PlatformServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/platform.service.interface'
5
+ import {
6
+ AutocompleteComponent,
7
+ DropdownSelectorComponent,
8
+ UiInputsModule,
9
+ } from '../../../../../../../../../libs/ui/inputs/src'
10
+ import { UiWidgetsModule } from '../../../../../../../../../libs/ui/widgets/src'
11
+ import { map } from 'rxjs'
12
+ import { Keyword } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
13
+
14
+ type AutocompleteItem = { title: string; value: Keyword }
15
+
16
+ @Component({
17
+ selector: 'gn-ui-form-field-keywords',
18
+ templateUrl: './form-field-keywords.component.html',
19
+ styleUrls: ['./form-field-keywords.component.css'],
20
+ changeDetection: ChangeDetectionStrategy.OnPush,
21
+ standalone: true,
22
+ imports: [
23
+ DropdownSelectorComponent,
24
+ UiInputsModule,
25
+ CommonModule,
26
+ UiWidgetsModule,
27
+ AutocompleteComponent,
28
+ ],
29
+ })
30
+ export class FormFieldKeywordsComponent {
31
+ @Input() control: FormControl<Keyword[]>
32
+
33
+ displayWithFn = (item: AutocompleteItem) => {
34
+ return `${item.title} (${item.value.thesaurus?.name})`
35
+ }
36
+
37
+ autoCompleteAction = (query: string) => {
38
+ return this.platformService.searchKeywords(query).pipe(
39
+ map((keywords) =>
40
+ keywords.map((keyword) => {
41
+ return { title: keyword.label, value: keyword }
42
+ })
43
+ )
44
+ )
45
+ }
46
+
47
+ constructor(private platformService: PlatformServiceInterface) {}
48
+
49
+ handleItemSelection(item: AutocompleteItem) {
50
+ this.addKeyword(item.value)
51
+ }
52
+
53
+ addKeyword(keyword: Keyword) {
54
+ const addedKeywords = [...this.control.value, keyword]
55
+
56
+ // remove duplicates from keyword
57
+ const filteredKeywords = addedKeywords.filter((value, index, self) => {
58
+ return (
59
+ index ===
60
+ self.findIndex(
61
+ (t) =>
62
+ t?.label === value?.label &&
63
+ t?.thesaurus?.id === value?.thesaurus?.id &&
64
+ t?.type === value?.type
65
+ )
66
+ )
67
+ })
68
+
69
+ this.control.setValue(filteredKeywords)
70
+ }
71
+
72
+ removeKeyword(index: number) {
73
+ const removeKeywords = this.control.value.filter((_, i) => i !== index)
74
+
75
+ this.control.setValue(removeKeywords)
76
+ }
77
+ }