geonetwork-ui 2.3.0-dev.a288b23a → 2.3.0-dev.bc5d77f0

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 (150) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +3 -3
  2. package/esm2022/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.mjs +1 -1
  3. package/esm2022/libs/api/repository/src/lib/gn4/auth/gravatar.service.mjs +12 -1
  4. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.mjs +36 -3
  5. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +19 -7
  6. package/esm2022/libs/common/domain/src/lib/model/record/index.mjs +2 -1
  7. package/esm2022/libs/common/domain/src/lib/model/record/user-feedbacks.model.mjs +2 -0
  8. package/esm2022/libs/common/domain/src/lib/model/user/index.mjs +2 -0
  9. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  10. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.mjs +64 -0
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.mjs +15 -0
  12. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +20 -6
  13. package/esm2022/libs/feature/editor/src/lib/components/wizard-field/wizard-field.component.mjs +1 -1
  14. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +16 -1
  15. package/esm2022/libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.mjs +1 -1
  16. package/esm2022/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.mjs +1 -1
  17. package/esm2022/libs/feature/map/src/lib/add-layer-from-wms/add-layer-from-wms.component.mjs +1 -1
  18. package/esm2022/libs/feature/record/src/lib/feature-record.module.mjs +4 -4
  19. package/esm2022/libs/feature/record/src/lib/state/mdview.actions.mjs +22 -4
  20. package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +37 -10
  21. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +22 -7
  22. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +52 -17
  23. package/esm2022/libs/feature/record/src/lib/state/mdview.selectors.mjs +18 -3
  24. package/esm2022/libs/feature/router/src/lib/default/state/router.effects.mjs +2 -2
  25. package/esm2022/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.mjs +2 -2
  26. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +1 -1
  27. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -2
  28. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.mjs +59 -0
  29. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.mjs +62 -0
  30. package/esm2022/libs/ui/inputs/src/index.mjs +15 -15
  31. package/esm2022/libs/ui/inputs/src/lib/date-picker/date-picker.component.mjs +22 -0
  32. package/esm2022/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.mjs +7 -5
  33. package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +17 -8
  34. package/esm2022/libs/ui/inputs/src/lib/text-area/text-area.component.mjs +27 -4
  35. package/esm2022/libs/ui/inputs/src/lib/text-input/text-input.component.mjs +19 -3
  36. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +11 -9
  37. package/esm2022/translations/de.json +26 -0
  38. package/esm2022/translations/en.json +26 -0
  39. package/esm2022/translations/es.json +26 -0
  40. package/esm2022/translations/fr.json +26 -0
  41. package/esm2022/translations/it.json +26 -0
  42. package/esm2022/translations/nl.json +26 -0
  43. package/esm2022/translations/pt.json +26 -0
  44. package/fesm2022/geonetwork-ui.mjs +1333 -712
  45. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  46. package/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.d.ts +1 -0
  47. package/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.d.ts.map +1 -1
  48. package/libs/api/repository/src/lib/gn4/auth/gravatar.service.d.ts +1 -0
  49. package/libs/api/repository/src/lib/gn4/auth/gravatar.service.d.ts.map +1 -1
  50. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts +6 -2
  51. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts.map +1 -1
  52. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +9 -6
  53. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  54. package/libs/common/domain/src/lib/model/record/index.d.ts +1 -0
  55. package/libs/common/domain/src/lib/model/record/index.d.ts.map +1 -1
  56. package/libs/common/domain/src/lib/model/record/user-feedbacks.model.d.ts +15 -0
  57. package/libs/common/domain/src/lib/model/record/user-feedbacks.model.d.ts.map +1 -0
  58. package/libs/common/domain/src/lib/model/user/index.d.ts +2 -0
  59. package/libs/common/domain/src/lib/model/user/index.d.ts.map +1 -0
  60. package/libs/common/domain/src/lib/platform.service.interface.d.ts +3 -0
  61. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  62. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.d.ts +39 -0
  63. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.d.ts.map +1 -0
  64. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.d.ts +8 -0
  65. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.d.ts.map +1 -0
  66. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +4 -1
  67. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  68. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  69. package/libs/feature/record/src/lib/feature-record.module.d.ts.map +1 -1
  70. package/libs/feature/record/src/lib/state/mdview.actions.d.ts +40 -6
  71. package/libs/feature/record/src/lib/state/mdview.actions.d.ts.map +1 -1
  72. package/libs/feature/record/src/lib/state/mdview.effects.d.ts +24 -4
  73. package/libs/feature/record/src/lib/state/mdview.effects.d.ts.map +1 -1
  74. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +14 -4
  75. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  76. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts +8 -5
  77. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts.map +1 -1
  78. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts +12 -9
  79. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts.map +1 -1
  80. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +16 -14
  81. package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
  82. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts +11 -0
  83. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts.map +1 -0
  84. package/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.d.ts +22 -0
  85. package/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.d.ts.map +1 -0
  86. package/libs/ui/inputs/src/index.d.ts +14 -14
  87. package/libs/ui/inputs/src/index.d.ts.map +1 -1
  88. package/libs/ui/inputs/src/lib/date-picker/date-picker.component.d.ts +9 -0
  89. package/libs/ui/inputs/src/lib/date-picker/date-picker.component.d.ts.map +1 -0
  90. package/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.d.ts +1 -1
  91. package/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.d.ts.map +1 -1
  92. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts +1 -1
  93. package/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.d.ts.map +1 -1
  94. package/libs/ui/inputs/src/lib/text-area/text-area.component.d.ts +7 -1
  95. package/libs/ui/inputs/src/lib/text-area/text-area.component.d.ts.map +1 -1
  96. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts +4 -1
  97. package/libs/ui/inputs/src/lib/text-input/text-input.component.d.ts.map +1 -1
  98. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +35 -35
  99. package/package.json +1 -1
  100. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -2
  101. package/src/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.ts +1 -0
  102. package/src/libs/api/repository/src/lib/gn4/auth/gravatar.service.ts +12 -1
  103. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +51 -1
  104. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +34 -7
  105. package/src/libs/common/domain/src/lib/model/record/index.ts +1 -0
  106. package/src/libs/common/domain/src/lib/model/record/user-feedbacks.model.ts +15 -0
  107. package/src/libs/common/domain/src/lib/platform.service.interface.ts +3 -0
  108. package/src/libs/common/fixtures/src/index.ts +8 -6
  109. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +3 -3
  110. package/src/libs/common/fixtures/src/lib/user-feedbacks.fixtures.ts +83 -0
  111. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.css +0 -0
  112. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.html +8 -0
  113. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.ts +64 -0
  114. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.css +0 -0
  115. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.html +4 -0
  116. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-resource-updated/form-field-resource-updated.component.ts +15 -0
  117. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +33 -33
  118. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +16 -0
  119. package/src/libs/feature/editor/src/lib/fields.config.ts +15 -0
  120. package/src/libs/feature/record/src/lib/feature-record.module.ts +5 -2
  121. package/src/libs/feature/record/src/lib/state/mdview.actions.ts +51 -6
  122. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +82 -7
  123. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +49 -8
  124. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +81 -24
  125. package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +40 -10
  126. package/src/libs/feature/router/src/lib/default/state/router.effects.ts +2 -2
  127. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +5 -0
  128. package/src/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.ts +54 -0
  129. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.css +0 -0
  130. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.html +75 -0
  131. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.ts +63 -0
  132. package/src/libs/ui/inputs/src/index.ts +14 -14
  133. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.css +3 -0
  134. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.html +11 -0
  135. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +16 -0
  136. package/src/libs/ui/inputs/src/lib/date-range-picker/date-range-picker.component.ts +8 -1
  137. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts +13 -0
  138. package/src/libs/ui/inputs/src/lib/text-area/text-area.component.html +2 -1
  139. package/src/libs/ui/inputs/src/lib/text-area/text-area.component.ts +29 -0
  140. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +1 -1
  141. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +16 -1
  142. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +2 -2
  143. package/translations/de.json +26 -0
  144. package/translations/en.json +26 -0
  145. package/translations/es.json +26 -0
  146. package/translations/fr.json +26 -0
  147. package/translations/it.json +26 -0
  148. package/translations/nl.json +26 -0
  149. package/translations/pt.json +26 -0
  150. package/translations/sk.json +26 -0
@@ -5,7 +5,12 @@ import * as MdViewActions from './mdview.actions'
5
5
  import * as MdViewSelectors from './mdview.selectors'
6
6
  import { LinkClassifierService, LinkUsage } from '../../../../../../libs/util/shared/src'
7
7
  import { DatavizConfigurationModel } from '../../../../../../libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model'
8
- import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
8
+ import {
9
+ CatalogRecord,
10
+ UserFeedback,
11
+ UserFeedbackViewModel,
12
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
13
+ import { AvatarServiceInterface } from '../../../../../../libs/api/repository/src'
9
14
 
10
15
  @Injectable()
11
16
  /**
@@ -15,19 +20,31 @@ import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/mode
15
20
  * To clear the current record use the `close()` method.
16
21
  */
17
22
  export class MdViewFacade {
23
+ constructor(
24
+ private store: Store,
25
+ private linkClassifier: LinkClassifierService,
26
+ private avatarService: AvatarServiceInterface
27
+ ) {}
28
+
18
29
  isPresent$ = this.store.pipe(
19
30
  select(MdViewSelectors.getMetadataUuid),
20
31
  map((uuid) => !!uuid)
21
32
  )
22
- isLoading$ = this.store.pipe(select(MdViewSelectors.getMetadataIsLoading))
33
+
34
+ isMetadataLoading$ = this.store.pipe(
35
+ select(MdViewSelectors.getMetadataIsLoading)
36
+ )
37
+
23
38
  metadata$ = this.store.pipe(
24
39
  select(MdViewSelectors.getMetadata),
25
40
  filter((md) => !!md)
26
41
  )
42
+
27
43
  isIncomplete$ = this.store.pipe(
28
44
  select(MdViewSelectors.getMetadataIsIncomplete),
29
45
  filter((incomplete) => incomplete !== null)
30
46
  )
47
+
31
48
  error$ = this.store.pipe(select(MdViewSelectors.getMetadataError))
32
49
 
33
50
  related$ = this.store.pipe(select(MdViewSelectors.getRelated))
@@ -37,11 +54,13 @@ export class MdViewFacade {
37
54
  allLinks$ = this.metadata$.pipe(
38
55
  map((record) => ('distributions' in record ? record.distributions : []))
39
56
  )
57
+
40
58
  apiLinks$ = this.allLinks$.pipe(
41
59
  map((links) =>
42
60
  links.filter((link) => this.linkClassifier.hasUsage(link, LinkUsage.API))
43
61
  )
44
62
  )
63
+
45
64
  mapApiLinks$ = this.allLinks$.pipe(
46
65
  map((links) =>
47
66
  links.filter((link) =>
@@ -49,6 +68,7 @@ export class MdViewFacade {
49
68
  )
50
69
  )
51
70
  )
71
+
52
72
  downloadLinks$ = this.allLinks$.pipe(
53
73
  map((links) =>
54
74
  links.filter((link) =>
@@ -56,11 +76,13 @@ export class MdViewFacade {
56
76
  )
57
77
  )
58
78
  )
79
+
59
80
  dataLinks$ = this.allLinks$.pipe(
60
81
  map((links) =>
61
82
  links.filter((link) => this.linkClassifier.hasUsage(link, LinkUsage.DATA))
62
83
  )
63
84
  )
85
+
64
86
  geoDataLinks$ = this.allLinks$.pipe(
65
87
  map((links) =>
66
88
  links.filter((link) =>
@@ -68,9 +90,11 @@ export class MdViewFacade {
68
90
  )
69
91
  )
70
92
  )
93
+
71
94
  landingPageLinks$ = this.metadata$.pipe(
72
95
  map((record) => ('landingPage' in record ? [record.landingPage] : []))
73
96
  )
97
+
74
98
  otherLinks$ = this.allLinks$.pipe(
75
99
  map((links) =>
76
100
  links.filter((link) =>
@@ -79,10 +103,13 @@ export class MdViewFacade {
79
103
  )
80
104
  )
81
105
 
82
- constructor(
83
- private store: Store,
84
- private linkClassifier: LinkClassifierService
85
- ) {}
106
+ userFeedbacks$ = this.store.pipe(select(MdViewSelectors.getUserFeedbacks))
107
+ isAllUserFeedbackLoading$ = this.store.pipe(
108
+ select(MdViewSelectors.getAllUserFeedbacksLoading)
109
+ )
110
+ isAddUserFeedbackLoading$ = this.store.pipe(
111
+ select(MdViewSelectors.getAddUserFeedbacksLoading)
112
+ )
86
113
 
87
114
  /**
88
115
  * This will show an incomplete record (e.g. from a search result) as a preview
@@ -91,16 +118,30 @@ export class MdViewFacade {
91
118
  setIncompleteMetadata(incomplete: CatalogRecord) {
92
119
  this.store.dispatch(MdViewActions.setIncompleteMetadata({ incomplete }))
93
120
  }
121
+
94
122
  /**
95
123
  * This will trigger the load of a full metadata record
96
124
  */
97
125
  loadFull(uuid: string) {
98
126
  this.store.dispatch(MdViewActions.loadFullMetadata({ uuid }))
99
127
  }
100
- close() {
101
- this.store.dispatch(MdViewActions.close())
128
+
129
+ closeMetadata() {
130
+ this.store.dispatch(MdViewActions.closeMetadata())
102
131
  }
132
+
103
133
  setChartConfig(chartConfig: DatavizConfigurationModel) {
104
134
  this.store.dispatch(MdViewActions.setChartConfig({ chartConfig }))
105
135
  }
136
+
137
+ /**
138
+ * UserFeedbacks
139
+ */
140
+ addUserFeedback(userFeedback: UserFeedback) {
141
+ this.store.dispatch(MdViewActions.addUserFeedback({ userFeedback }))
142
+ }
143
+
144
+ loadUserFeedbacks(datasetUuid: string) {
145
+ this.store.dispatch(MdViewActions.loadUserFeedbacks({ datasetUuid }))
146
+ }
106
147
  }
@@ -1,61 +1,118 @@
1
1
  import { Action, createReducer, on } from '@ngrx/store'
2
- import * as MdViewActions from './mdview.actions'
2
+ import * as MetadataViewActions from './mdview.actions'
3
3
  import { DatavizConfigurationModel } from '../../../../../../libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model'
4
- import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
4
+ import {
5
+ CatalogRecord,
6
+ UserFeedback,
7
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
5
8
 
6
- export const MD_VIEW_FEATURE_STATE_KEY = 'mdView'
9
+ export const METADATA_VIEW_FEATURE_STATE_KEY = 'metadataView'
7
10
 
8
- export interface MdViewState {
11
+ export interface MetadataViewState {
9
12
  loadingFull: boolean
10
13
  error: { notFound?: boolean; otherError?: string } | null
11
14
  metadata?: Partial<CatalogRecord>
12
15
  related?: CatalogRecord[]
16
+ userFeedbacks?: UserFeedback[]
17
+ allUserFeedbacksLoading: boolean
18
+ addUserFeedbackLoading: boolean
13
19
  chartConfig?: DatavizConfigurationModel
14
20
  }
15
21
 
16
- export const initialMdviewState: MdViewState = {
22
+ export const initialMetadataViewState: MetadataViewState = {
17
23
  error: null,
18
24
  loadingFull: false,
25
+ allUserFeedbacksLoading: false,
26
+ addUserFeedbackLoading: false,
19
27
  }
20
28
 
21
- const mdViewReducer = createReducer(
22
- initialMdviewState,
23
- on(MdViewActions.loadFullMetadata, (state) => ({
29
+ const metadataViewReducer = createReducer(
30
+ initialMetadataViewState,
31
+
32
+ /*
33
+ Metadata reducers
34
+ */
35
+ on(MetadataViewActions.loadFullMetadata, (state) => ({
24
36
  ...state,
25
37
  error: null,
26
38
  loadingFull: true,
27
39
  })),
28
- on(MdViewActions.setIncompleteMetadata, (state, { incomplete }) => ({
40
+ on(MetadataViewActions.setIncompleteMetadata, (state, { incomplete }) => ({
29
41
  ...state,
30
42
  error: null,
31
43
  metadata: incomplete,
32
44
  })),
33
- on(MdViewActions.loadFullSuccess, (state, { full }) => ({
45
+ on(MetadataViewActions.loadFullMetadataSuccess, (state, { full }) => ({
34
46
  ...state,
35
47
  error: null,
36
48
  metadata: full,
37
49
  loadingFull: false,
38
50
  })),
39
- on(MdViewActions.loadFullFailure, (state, { otherError, notFound }) => ({
40
- ...state,
41
- error: { otherError, notFound },
42
- loadingFull: false,
43
- })),
44
- on(MdViewActions.setRelated, (state, { related }) => ({
51
+ on(
52
+ MetadataViewActions.loadFullMetadataFailure,
53
+ (state, { otherError, notFound }) => ({
54
+ ...state,
55
+ error: { otherError, notFound },
56
+ loadingFull: false,
57
+ })
58
+ ),
59
+ on(MetadataViewActions.closeMetadata, (state) => {
60
+ const { metadata, related, userFeedbacks, ...stateWithoutMetadata } = state
61
+ return stateWithoutMetadata
62
+ }),
63
+
64
+ /*
65
+ Related reducers
66
+ */
67
+ on(MetadataViewActions.setRelated, (state, { related }) => ({
45
68
  ...state,
46
69
  related,
47
70
  })),
48
- on(MdViewActions.setChartConfig, (state, { chartConfig }) => ({
71
+
72
+ /*
73
+ ChartConfig reducers
74
+ */
75
+ on(MetadataViewActions.setChartConfig, (state, { chartConfig }) => ({
49
76
  ...state,
50
77
  chartConfig,
51
78
  })),
52
- on(MdViewActions.close, (state) => {
53
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
- const { metadata, related, ...stateWithoutMd } = state
55
- return stateWithoutMd
56
- })
79
+
80
+ /*
81
+ UserFeedbacks reducers
82
+ */
83
+ on(MetadataViewActions.loadUserFeedbacks, (state) => ({
84
+ ...state,
85
+ error: null,
86
+ allUserFeedbacksLoading: true,
87
+ })),
88
+ on(MetadataViewActions.addUserFeedback, (state) => ({
89
+ ...state,
90
+ addUserFeedbackLoading: true,
91
+ })),
92
+ on(
93
+ MetadataViewActions.loadUserFeedbacksSuccess,
94
+ (state, { userFeedbacks }) => ({
95
+ ...state,
96
+ error: null,
97
+ userFeedbacks: userFeedbacks,
98
+ addUserFeedbackLoading: false,
99
+ allUserFeedbacksLoading: false,
100
+ })
101
+ ),
102
+ on(
103
+ MetadataViewActions.loadUserFeedbacksFailure,
104
+ (state, { otherError, notFound }) => ({
105
+ ...state,
106
+ error: { otherError, notFound },
107
+ addUserFeedbackLoading: false,
108
+ allUserFeedbacksLoading: false,
109
+ })
110
+ )
57
111
  )
58
112
 
59
- export function reducer(state: MdViewState | undefined, action: Action) {
60
- return mdViewReducer(state, action)
113
+ export function reducer(
114
+ metadataViewState: MetadataViewState | undefined,
115
+ action: Action
116
+ ) {
117
+ return metadataViewReducer(metadataViewState, action)
61
118
  }
@@ -1,36 +1,66 @@
1
1
  import { createFeatureSelector, createSelector } from '@ngrx/store'
2
- import { MD_VIEW_FEATURE_STATE_KEY, MdViewState } from './mdview.reducer'
2
+ import {
3
+ METADATA_VIEW_FEATURE_STATE_KEY,
4
+ MetadataViewState,
5
+ } from './mdview.reducer'
3
6
 
4
- export const getMdViewState = createFeatureSelector<MdViewState>(
5
- MD_VIEW_FEATURE_STATE_KEY
7
+ export const getMdViewState = createFeatureSelector<MetadataViewState>(
8
+ METADATA_VIEW_FEATURE_STATE_KEY
6
9
  )
7
10
 
11
+ /*
12
+ Metadata selectors
13
+ */
8
14
  export const getMetadataUuid = createSelector(
9
15
  getMdViewState,
10
- (state: MdViewState) =>
16
+ (state: MetadataViewState) =>
11
17
  state.metadata ? state.metadata.uniqueIdentifier : null
12
18
  )
13
19
  export const getMetadata = createSelector(
14
20
  getMdViewState,
15
- (state: MdViewState) => state.metadata
21
+ (state: MetadataViewState) => state.metadata
16
22
  )
17
23
  export const getMetadataIsIncomplete = createSelector(
18
24
  getMdViewState,
19
- (state: MdViewState) => (state.metadata ? state.loadingFull : null)
25
+ (state: MetadataViewState) => (state.metadata ? state.loadingFull : null)
20
26
  )
21
27
  export const getMetadataIsLoading = createSelector(
22
28
  getMdViewState,
23
- (state: MdViewState) => state.loadingFull
29
+ (state: MetadataViewState) => state.loadingFull
24
30
  )
25
31
  export const getMetadataError = createSelector(
26
32
  getMdViewState,
27
- (state: MdViewState) => state.error
33
+ (state: MetadataViewState) => state.error
28
34
  )
35
+
36
+ /*
37
+ Related selectors
38
+ */
29
39
  export const getRelated = createSelector(
30
40
  getMdViewState,
31
- (state: MdViewState) => state.related
41
+ (state: MetadataViewState) => state.related
32
42
  )
43
+
44
+ /*
45
+ Metadata selectors
46
+ */
33
47
  export const getChartConfig = createSelector(
34
48
  getMdViewState,
35
- (state: MdViewState) => state.chartConfig
49
+ (state: MetadataViewState) => state.chartConfig
50
+ )
51
+
52
+ /*
53
+ UserFeedback selectors
54
+ */
55
+ export const getUserFeedbacks = createSelector(
56
+ getMdViewState,
57
+ (state: MetadataViewState) => state.userFeedbacks
58
+ )
59
+ export const getAllUserFeedbacksLoading = createSelector(
60
+ getMdViewState,
61
+ (state: MetadataViewState) => state.allUserFeedbacksLoading
62
+ )
63
+ export const getAddUserFeedbacksLoading = createSelector(
64
+ getMdViewState,
65
+ (state: MetadataViewState) => state.addUserFeedbackLoading
36
66
  )
@@ -15,7 +15,7 @@ import {
15
15
  } from '../../../../../../../libs/common/domain/src/lib/model/search'
16
16
  import { Actions, createEffect, ofType } from '@ngrx/effects'
17
17
  import { navigation } from '@ngrx/router-store/data-persistence'
18
- import { of, pairwise, startWith, withLatestFrom } from 'rxjs'
18
+ import { of, pairwise, startWith } from 'rxjs'
19
19
  import { map, mergeMap, tap } from 'rxjs/operators'
20
20
  import * as RouterActions from './router.actions'
21
21
  import { RouterFacade } from './router.facade'
@@ -141,7 +141,7 @@ export class RouterEffects {
141
141
  navigateToSearch$ = createEffect(() =>
142
142
  this._actions$.pipe(
143
143
  navigation(this.routerConfig.searchRouteComponent, {
144
- run: () => MdViewActions.close(),
144
+ run: () => MdViewActions.closeMetadata(),
145
145
  })
146
146
  )
147
147
  )
@@ -31,6 +31,8 @@ import { MaxLinesComponent } from './max-lines/max-lines.component'
31
31
  import { RecordApiFormComponent } from './record-api-form/record-api-form.component'
32
32
  import { MarkdownParserComponent } from './markdown-parser/markdown-parser.component'
33
33
  import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-overlay-preview.component'
34
+ import { UserFeedbackItemComponent } from './user-feedback-item/user-feedback-item.component'
35
+ import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
34
36
 
35
37
  @NgModule({
36
38
  imports: [
@@ -47,6 +49,7 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
47
49
  NgOptimizedImage,
48
50
  MarkdownParserComponent,
49
51
  ThumbnailComponent,
52
+ TimeSincePipe,
50
53
  ],
51
54
  declarations: [
52
55
  MetadataInfoComponent,
@@ -68,6 +71,7 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
68
71
  PaginationButtonsComponent,
69
72
  MaxLinesComponent,
70
73
  RecordApiFormComponent,
74
+ UserFeedbackItemComponent,
71
75
  ImageOverlayPreviewComponent,
72
76
  ],
73
77
  exports: [
@@ -91,6 +95,7 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
91
95
  MaxLinesComponent,
92
96
  RecordApiFormComponent,
93
97
  MarkdownParserComponent,
98
+ UserFeedbackItemComponent,
94
99
  ImageOverlayPreviewComponent,
95
100
  ],
96
101
  })
@@ -0,0 +1,54 @@
1
+ import { Pipe, PipeTransform } from '@angular/core'
2
+ import { TranslateService } from '@ngx-translate/core'
3
+ import { formatDistance } from 'date-fns'
4
+ import { de, enUS, es, fr, it, nl, pt, sk } from 'date-fns/locale'
5
+
6
+ @Pipe({
7
+ name: 'timeSince',
8
+ standalone: true,
9
+ })
10
+ export class TimeSincePipe implements PipeTransform {
11
+ constructor(private translate: TranslateService) {}
12
+
13
+ transform(value: Date): string {
14
+ if (isNaN(value.getTime())) {
15
+ throw new Error('Invalid Date')
16
+ }
17
+
18
+ const maintenant = new Date()
19
+ let locale: Locale
20
+
21
+ switch (this.translate.currentLang) {
22
+ case 'fr':
23
+ locale = fr
24
+ break
25
+ case 'de':
26
+ locale = de
27
+ break
28
+ case 'es':
29
+ locale = es
30
+ break
31
+ case 'it':
32
+ locale = it
33
+ break
34
+ case 'nl':
35
+ locale = nl
36
+ break
37
+ case 'pt':
38
+ locale = pt
39
+ break
40
+ case 'sk':
41
+ locale = sk
42
+ break
43
+ case 'en':
44
+ default:
45
+ locale = enUS
46
+ break
47
+ }
48
+
49
+ return formatDistance(value, maintenant, {
50
+ addSuffix: true,
51
+ locale: locale,
52
+ })
53
+ }
54
+ }
@@ -0,0 +1,75 @@
1
+ <div
2
+ *ngIf="userFeedbackParent.published"
3
+ class="flex flex-col bg-white rounded w-full"
4
+ [ngClass]="[isAnAnswer ? 'ps-4 ' : 'p-4']"
5
+ >
6
+ <div class="flex flex-row">
7
+ <div class="avatar">
8
+ <img
9
+ class="rounded-full"
10
+ [src]="userFeedbackParent.avatarUrl"
11
+ alt="avatar"
12
+ />
13
+ </div>
14
+ <div class="p-4 flex flex-col">
15
+ <span>{{ userFeedbackParent.authorName }}</span>
16
+ <span> {{ userFeedbackParent.date | timeSince }}</span>
17
+ </div>
18
+ </div>
19
+ <div data-cy="commentText" class="mt-4 whitespace-pre-line">
20
+ {{ userFeedbackParent.comment }}
21
+ </div>
22
+ <div
23
+ class="w-full"
24
+ *ngFor="let userFeedBacksAnswer of userFeedBacksAnswers; let last = last"
25
+ >
26
+ <hr class="-mx-4 my-6" />
27
+ <gn-ui-user-feedback-item
28
+ [userFeedbackParent]="userFeedBacksAnswer"
29
+ [isLastComment]="last"
30
+ ></gn-ui-user-feedback-item>
31
+ </div>
32
+
33
+ <div *ngIf="isActiveUserEditor" class="mt-2 flex flex-col">
34
+ <hr class="-mx-4 my-4" />
35
+ <div
36
+ id="new-comment-buttons"
37
+ class="flex flex-row gap-2 items-center justify-end"
38
+ >
39
+ <gn-ui-text-area
40
+ [disabled]="isAddUserFeedbackLoading"
41
+ [(value)]="newAnswer"
42
+ (valueChange)="onNewAnswerValueChange()"
43
+ (keyup.control.enter)="publishNewAnswer()"
44
+ [placeholder]="
45
+ 'record.metadata.userFeedbacks.newAnswer.placeholder' | translate
46
+ "
47
+ class="grow"
48
+ extraClass="bg-transparent border-0 placeholder-primary-darker text-primary-darker h-9"
49
+ ></gn-ui-text-area>
50
+ <div *ngIf="!isAnswerEmpty" class="flex flex-row justify-end">
51
+ <gn-ui-button
52
+ [disabled]="isAddUserFeedbackLoading"
53
+ [type]="'outline'"
54
+ (buttonClick)="publishNewAnswer()"
55
+ [title]="
56
+ 'record.metadata.userFeedbacks.newAnswer.buttonTitle' | translate
57
+ "
58
+ extraClass="!p-[0.5em] text-primary-darker border-primary-darker h-9"
59
+ >
60
+ <mat-icon
61
+ class="material-symbols-outlined"
62
+ *ngIf="!isAddUserFeedbackLoading"
63
+ >
64
+ send
65
+ </mat-icon>
66
+ <ng-container *ngIf="isAddUserFeedbackLoading">
67
+ <div class="flex justify-center w-full">
68
+ <gn-ui-spinning-loader></gn-ui-spinning-loader>
69
+ </div>
70
+ </ng-container>
71
+ </gn-ui-button>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
@@ -0,0 +1,63 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ EventEmitter,
5
+ Input,
6
+ OnInit,
7
+ Output,
8
+ } from '@angular/core'
9
+ import {
10
+ UserFeedback,
11
+ UserFeedbackViewModel,
12
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
13
+ import { UserModel } from '../../../../../../libs/common/domain/src/lib/model/user'
14
+
15
+ @Component({
16
+ selector: 'gn-ui-user-feedback-item',
17
+ templateUrl: './user-feedback-item.component.html',
18
+ styleUrls: ['./user-feedback-item.component.css'],
19
+ changeDetection: ChangeDetectionStrategy.OnPush,
20
+ })
21
+ export class UserFeedbackItemComponent implements OnInit {
22
+ @Input() userFeedbackParent: UserFeedbackViewModel
23
+ @Input() userFeedBacksAnswers: UserFeedbackViewModel[]
24
+ @Input() isActiveUserEditor: boolean
25
+ @Input() activeUser: UserModel
26
+ @Input() isLastComment: boolean
27
+ @Input() isAddUserFeedbackLoading: boolean
28
+
29
+ @Output() newUserFeedbackAnswer = new EventEmitter<UserFeedback>()
30
+
31
+ isAnAnswer = false
32
+ newAnswer = ''
33
+ isAnswerEmpty = true
34
+
35
+ ngOnInit(): void {
36
+ this.isAnAnswer = !!this.userFeedbackParent.parentUuid
37
+ }
38
+
39
+ onNewAnswerValueChange() {
40
+ this.isAnswerEmpty = this.newAnswer.length === 0
41
+ }
42
+
43
+ publishNewAnswer() {
44
+ if (this.newAnswer.trim() === '') return
45
+
46
+ const newAnswer: UserFeedback = {
47
+ ...this.userFeedbackParent,
48
+ uuid: undefined,
49
+ published: true,
50
+ comment: this.newAnswer,
51
+ parentUuid: this.userFeedbackParent.uuid,
52
+ authorUserId: this.activeUser?.id,
53
+ authorEmail: this.activeUser?.email,
54
+ date: new Date(),
55
+ authorName: `${this.activeUser?.name} ${this.activeUser?.surname}`,
56
+ }
57
+
58
+ this.newUserFeedbackAnswer.emit(newAnswer)
59
+
60
+ this.newAnswer = ''
61
+ this.onNewAnswerValueChange()
62
+ }
63
+ }
@@ -1,21 +1,21 @@
1
- export * from './lib/dropdown-selector/dropdown-selector.component'
2
- export * from './lib/dropdown-selector/dropdown-selector.model'
3
- export * from './lib/dropdown-multiselect/dropdown-multiselect.component'
4
- export * from './lib/dropdown-multiselect/dropdown-multiselect.model'
5
- export * from './lib/text-input/text-input.component'
6
- export * from './lib/chips-input/chips-input.component'
7
- export * from './lib/text-area/text-area.component'
8
1
  export * from './lib/autocomplete/autocomplete.component'
9
- export * from './lib/star-toggle/star-toggle.component'
10
2
  export * from './lib/button/button.component'
11
- export * from './lib/viewport-intersector/viewport-intersector.component'
12
3
  export * from './lib/check-toggle/check-toggle.component'
13
- export * from './lib/ui-inputs.module'
4
+ export * from './lib/checkbox/checkbox.component'
5
+ export * from './lib/chips-input/chips-input.component'
14
6
  export * from './lib/copy-text-button/copy-text-button.component'
7
+ export * from './lib/date-picker/date-picker.component'
8
+ export * from './lib/date-range-picker/date-range-picker.component'
15
9
  export * from './lib/drag-and-drop-file-input/drag-and-drop-file-input.component'
10
+ export * from './lib/dropdown-multiselect/dropdown-multiselect.component'
11
+ export * from './lib/dropdown-multiselect/dropdown-multiselect.model'
12
+ export * from './lib/dropdown-selector/dropdown-selector.component'
13
+ export * from './lib/dropdown-selector/dropdown-selector.model'
14
+ export * from './lib/editable-label/editable-label.directive'
16
15
  export * from './lib/navigation-button/navigation-button.component'
17
- export * from './lib/viewport-intersector/viewport-intersector.component'
18
- export * from './lib/checkbox/checkbox.component'
19
16
  export * from './lib/search-input/search-input.component'
20
- export * from './lib/date-range-picker/date-range-picker.component'
21
- export * from './lib/editable-label/editable-label.directive'
17
+ export * from './lib/star-toggle/star-toggle.component'
18
+ export * from './lib/text-area/text-area.component'
19
+ export * from './lib/text-input/text-input.component'
20
+ export * from './lib/ui-inputs.module'
21
+ export * from './lib/viewport-intersector/viewport-intersector.component'
@@ -0,0 +1,3 @@
1
+ mat-datepicker-toggle {
2
+ @apply text-primary;
3
+ }
@@ -0,0 +1,11 @@
1
+ <div
2
+ class="flex items-center justify-between pl-3 rounded-lg border border-gray-300 bg-white"
3
+ >
4
+ <input
5
+ [matDatepicker]="picker"
6
+ [value]="date"
7
+ (dateChange)="dateChange.emit($event.value)"
8
+ />
9
+ <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
10
+ </div>
11
+ <mat-datepicker #picker></mat-datepicker>
@@ -0,0 +1,16 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core'
2
+ import { MatNativeDateModule } from '@angular/material/core'
3
+ import { MatDatepickerModule } from '@angular/material/datepicker'
4
+ import { MatIconModule } from '@angular/material/icon'
5
+
6
+ @Component({
7
+ selector: 'gn-ui-date-picker',
8
+ templateUrl: './date-picker.component.html',
9
+ styleUrls: ['./date-picker.component.css'],
10
+ standalone: true,
11
+ imports: [MatIconModule, MatNativeDateModule, MatDatepickerModule],
12
+ })
13
+ export class DatePickerComponent {
14
+ @Input() date: Date
15
+ @Output() dateChange = new EventEmitter<Date>()
16
+ }