geonetwork-ui 2.4.0-dev.6c8dcba0 → 2.4.0-dev.9c5250ea

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 (195) 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 +14 -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/record/src/lib/state/mdview.facade.mjs +4 -11
  30. package/esm2022/libs/feature/search/src/index.mjs +2 -2
  31. package/esm2022/libs/feature/search/src/lib/feature-search.module.mjs +7 -4
  32. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
  33. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +49 -0
  34. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +4 -4
  35. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +3 -3
  36. package/esm2022/libs/ui/inputs/src/index.mjs +2 -1
  37. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +59 -26
  38. package/esm2022/libs/ui/inputs/src/lib/badge/badge.component.mjs +28 -0
  39. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +11 -10
  40. package/esm2022/libs/ui/search/src/index.mjs +2 -1
  41. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +120 -0
  42. package/esm2022/libs/ui/widgets/src/index.mjs +1 -2
  43. package/esm2022/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.mjs +5 -3
  44. package/esm2022/libs/ui/widgets/src/lib/ui-widgets.module.mjs +1 -6
  45. package/esm2022/translations/de.json +8 -1
  46. package/esm2022/translations/en.json +8 -1
  47. package/esm2022/translations/es.json +8 -1
  48. package/esm2022/translations/fr.json +8 -1
  49. package/esm2022/translations/it.json +8 -1
  50. package/esm2022/translations/nl.json +8 -1
  51. package/esm2022/translations/pt.json +8 -1
  52. package/fesm2022/geonetwork-ui.mjs +702 -494
  53. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  54. package/libs/api/metadata-converter/src/lib/gn4/types/index.d.ts +1 -0
  55. package/libs/api/metadata-converter/src/lib/gn4/types/index.d.ts.map +1 -1
  56. package/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.d.ts +31 -0
  57. package/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.d.ts.map +1 -0
  58. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +3 -2
  59. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  60. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts +1 -1
  61. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts.map +1 -1
  62. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +3 -2
  63. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  64. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +1 -0
  65. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  66. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts +3 -3
  67. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts.map +1 -1
  68. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +8 -5
  69. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  70. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +4 -7
  71. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  72. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts +12 -5
  73. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts.map +1 -1
  74. package/libs/common/domain/src/lib/platform.service.interface.d.ts +3 -3
  75. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  76. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +3 -1
  77. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  78. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts +2 -1
  79. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts.map +1 -1
  80. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts +1 -0
  81. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts.map +1 -1
  82. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts +1 -1
  83. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts.map +1 -1
  84. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts +1 -0
  85. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts.map +1 -1
  86. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts +25 -0
  87. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts.map +1 -0
  88. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts +6 -6
  89. 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
  90. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +6 -10
  91. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  92. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts +1 -0
  93. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts.map +1 -1
  94. package/libs/feature/editor/src/lib/feature-editor.module.d.ts.map +1 -1
  95. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  96. package/libs/feature/editor/src/lib/services/editor.service.d.ts +1 -1
  97. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  98. package/libs/feature/record/src/lib/feature-record.module.d.ts +2 -1
  99. package/libs/feature/record/src/lib/feature-record.module.d.ts.map +1 -1
  100. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  101. package/libs/feature/search/src/index.d.ts +1 -1
  102. package/libs/feature/search/src/index.d.ts.map +1 -1
  103. package/libs/feature/search/src/lib/feature-search.module.d.ts +2 -1
  104. package/libs/feature/search/src/lib/feature-search.module.d.ts.map +1 -1
  105. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
  106. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +25 -0
  107. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -0
  108. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +1 -1
  109. package/libs/ui/inputs/src/index.d.ts +1 -0
  110. package/libs/ui/inputs/src/index.d.ts.map +1 -1
  111. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +7 -4
  112. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  113. package/libs/ui/inputs/src/lib/badge/badge.component.d.ts +11 -0
  114. package/libs/ui/inputs/src/lib/badge/badge.component.d.ts.map +1 -0
  115. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +35 -35
  116. package/libs/ui/search/src/index.d.ts +1 -0
  117. package/libs/ui/search/src/index.d.ts.map +1 -1
  118. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +30 -0
  119. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -0
  120. package/libs/ui/widgets/src/index.d.ts +0 -1
  121. package/libs/ui/widgets/src/index.d.ts.map +1 -1
  122. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts +1 -1
  123. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts.map +1 -1
  124. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts +10 -11
  125. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts.map +1 -1
  126. package/package.json +1 -1
  127. package/src/libs/api/metadata-converter/src/lib/gn4/types/index.ts +1 -0
  128. package/src/libs/api/metadata-converter/src/lib/gn4/types/keywords.model.ts +31 -0
  129. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +2 -2
  130. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.ts +1 -1
  131. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +2 -2
  132. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +21 -8
  133. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +24 -3
  134. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +70 -21
  135. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -9
  136. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +13 -6
  137. package/src/libs/common/domain/src/lib/platform.service.interface.ts +3 -3
  138. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +4 -1
  139. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +8 -0
  140. package/src/libs/feature/dataviz/src/lib/feature-dataviz.module.ts +2 -1
  141. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +2 -0
  142. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +35 -29
  143. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +1 -0
  144. package/src/libs/feature/editor/src/lib/+state/editor.selectors.ts +1 -1
  145. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +19 -0
  146. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.ts +77 -0
  147. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +95 -86
  148. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +7 -22
  149. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +16 -44
  150. package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -1
  151. package/src/libs/feature/editor/src/lib/feature-editor.module.ts +2 -1
  152. package/src/libs/feature/editor/src/lib/fields.config.ts +7 -0
  153. package/src/libs/feature/editor/src/lib/services/editor.service.ts +20 -6
  154. package/src/libs/feature/record/src/lib/feature-record.module.ts +3 -2
  155. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +38 -31
  156. package/src/libs/feature/search/src/index.ts +1 -1
  157. package/src/libs/feature/search/src/lib/feature-search.module.ts +2 -1
  158. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +2 -2
  159. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +9 -0
  160. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +49 -0
  161. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +2 -2
  162. package/src/libs/ui/inputs/src/index.ts +1 -0
  163. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -1
  164. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +23 -19
  165. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +79 -27
  166. package/src/libs/ui/inputs/src/lib/badge/badge.component.css +0 -0
  167. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +18 -0
  168. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +27 -0
  169. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +3 -3
  170. package/src/libs/ui/search/src/index.ts +1 -0
  171. package/src/libs/ui/search/src/lib/results-table/results-table.component.css +0 -0
  172. package/src/libs/{feature → ui}/search/src/lib/results-table/results-table.component.html +8 -8
  173. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +138 -0
  174. package/src/libs/ui/widgets/src/index.ts +0 -1
  175. package/src/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.ts +4 -0
  176. package/src/libs/ui/widgets/src/lib/ui-widgets.module.ts +0 -3
  177. package/translations/de.json +8 -1
  178. package/translations/en.json +8 -1
  179. package/translations/es.json +8 -1
  180. package/translations/fr.json +8 -1
  181. package/translations/it.json +8 -1
  182. package/translations/nl.json +8 -1
  183. package/translations/pt.json +8 -1
  184. package/translations/sk.json +8 -1
  185. package/esm2022/libs/feature/search/src/lib/results-table/results-table.component.mjs +0 -136
  186. package/esm2022/libs/ui/widgets/src/lib/badge/badge.component.mjs +0 -18
  187. package/libs/feature/search/src/lib/results-table/results-table.component.d.ts +0 -36
  188. package/libs/feature/search/src/lib/results-table/results-table.component.d.ts.map +0 -1
  189. package/libs/ui/widgets/src/lib/badge/badge.component.d.ts +0 -7
  190. package/libs/ui/widgets/src/lib/badge/badge.component.d.ts.map +0 -1
  191. package/src/libs/feature/search/src/lib/results-table/results-table.component.ts +0 -172
  192. package/src/libs/ui/widgets/src/lib/badge/badge.component.html +0 -10
  193. package/src/libs/ui/widgets/src/lib/badge/badge.component.ts +0 -14
  194. /package/src/libs/feature/{search/src/lib/results-table/results-table.component.css → editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.css} +0 -0
  195. /package/src/libs/{ui/widgets/src/lib/badge/badge.component.css → feature/search/src/lib/results-table/results-table-container.component.css} +0 -0
@@ -8,11 +8,16 @@ import { Injectable } from '@angular/core'
8
8
  import { AvatarServiceInterface } from '../auth'
9
9
  import { map } from 'rxjs/operators'
10
10
  import { Observable, of } from 'rxjs'
11
- import { ThesaurusModel } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus/thesaurus.model'
12
11
  import {
12
+ Keyword,
13
13
  UserFeedback,
14
14
  UserFeedbackViewModel,
15
15
  } from '../../../../../../../libs/common/domain/src/lib/model/record'
16
+ import {
17
+ KeywordApiResponse,
18
+ ThesaurusApiResponse,
19
+ } from '../../../../../../../libs/api/metadata-converter/src'
20
+ import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
16
21
 
17
22
  @Injectable()
18
23
  export class Gn4PlatformMapper {
@@ -52,8 +57,12 @@ export class Gn4PlatformMapper {
52
57
  return { ...apiUser, id: id.toString() } as UserModel
53
58
  }
54
59
 
55
- thesaurusFromApi(thesaurus: any[], lang3?: string): ThesaurusModel {
56
- return thesaurus.map((keyword) => {
60
+ keywordsFromApi(
61
+ keywords: KeywordApiResponse[],
62
+ thesaurus: ThesaurusApiResponse[],
63
+ lang3?: string
64
+ ): Keyword[] {
65
+ return keywords.map((keyword): Keyword => {
57
66
  let key = keyword.uri
58
67
  // sometines GN can prefix an URI with an "all thesaurus" URI; only keep the last one
59
68
  if (key.indexOf('@@@') > -1) {
@@ -65,10 +74,22 @@ export class Gn4PlatformMapper {
65
74
  lang3 && lang3 in keyword.definitions
66
75
  ? keyword.definitions[lang3]
67
76
  : keyword.definition
77
+
78
+ const matchedThesaurus = thesaurus.find(
79
+ (thes) => keyword.thesaurusKey === thes.key
80
+ )
81
+
68
82
  return {
69
83
  key,
70
84
  label,
71
85
  description,
86
+ type: matchedThesaurus?.dname as KeywordType,
87
+ thesaurus: {
88
+ id: matchedThesaurus?.key,
89
+ name: matchedThesaurus?.title,
90
+ url: new URL(matchedThesaurus?.url),
91
+ type: matchedThesaurus?.dname as KeywordType,
92
+ },
72
93
  }
73
94
  })
74
95
  }
@@ -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,
@@ -52,4 +52,7 @@ export abstract class RecordsRepositoryInterface {
52
52
 
53
53
  abstract clearRecordDraft(uniqueIdentifier: string): void
54
54
  abstract recordHasDraft(uniqueIdentifier: string): boolean
55
+
56
+ /** will return all pending drafts, both published and not published */
57
+ abstract getAllDrafts(): Observable<CatalogRecord[]>
55
58
  }
@@ -233,6 +233,14 @@ Malgré l'attention portée à la création de ces données, il est rappelé que
233
233
  description: 'Téléchargement du fichier',
234
234
  mimeType: 'x-gis/x-shapefile',
235
235
  },
236
+ {
237
+ type: 'service',
238
+ url: new URL('https://my-org.net/ogc'),
239
+ accessServiceProtocol: 'ogcFeatures',
240
+ name: 'ogcFeaturesSecondRecord',
241
+ description: 'This OGC service is the second part of the download',
242
+ identifierInService: 'my:featuretype',
243
+ },
236
244
  ],
237
245
  lineage: `Document d’urbanisme numérisé conformément aux prescriptions nationales du CNIG par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.
238
246
  Ce lot de données produit en 2019, a été numérisé à partir du PCI Vecteur de 2019 et contrôlé par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.`,
@@ -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
+ }