geonetwork-ui 2.6.0-dev.600519f47 → 2.6.0-dev.609dd7257
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.
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +4 -1
- package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/constant.mjs +4 -2
- package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +2 -2
- package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +45 -15
- package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +7 -1
- package/esm2022/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.mjs +2 -1
- package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
- package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
- package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +4 -3
- package/esm2022/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-from-catalog.component.mjs +1 -1
- package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +49 -23
- package/esm2022/libs/feature/search/src/lib/constants.mjs +3 -2
- package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +5 -3
- package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +13 -10
- package/esm2022/libs/ui/elements/src/index.mjs +1 -2
- package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +19 -34
- package/esm2022/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.mjs +59 -0
- package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +35 -10
- package/esm2022/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.mjs +5 -1
- package/esm2022/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.mjs +50 -29
- package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +7 -3
- package/esm2022/libs/ui/layout/src/index.mjs +2 -1
- package/esm2022/libs/ui/layout/src/lib/cell-popin/cell-popin.component.mjs +110 -0
- package/esm2022/libs/ui/layout/src/lib/interactive-table/interactive-table.component.mjs +20 -10
- package/esm2022/libs/ui/layout/src/lib/truncated-text/truncated-text.component.mjs +15 -49
- package/esm2022/libs/ui/layout/src/lib/ui-layout.module.mjs +2 -2
- package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +5 -3
- package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +16 -8
- package/esm2022/translations/de.json +20 -6
- package/esm2022/translations/en.json +20 -6
- package/esm2022/translations/es.json +19 -5
- package/esm2022/translations/fr.json +20 -6
- package/esm2022/translations/it.json +22 -8
- package/esm2022/translations/nl.json +19 -5
- package/esm2022/translations/pt.json +19 -5
- package/fesm2022/geonetwork-ui.mjs +1003 -711
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/elasticsearch/constant.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +8 -2
- package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +2 -0
- package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts +1 -0
- package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts.map +1 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +20 -17
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
- package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +3 -0
- package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +13 -5
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
- package/libs/feature/search/src/lib/constants.d.ts.map +1 -1
- package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts +2 -1
- package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
- package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +6 -5
- package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
- package/libs/ui/elements/src/index.d.ts +0 -1
- package/libs/ui/elements/src/index.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts +3 -6
- package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts +14 -0
- package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts.map +1 -0
- package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts +3 -0
- package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.d.ts +20 -9
- package/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts +2 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
- package/libs/ui/layout/src/index.d.ts +1 -0
- package/libs/ui/layout/src/index.d.ts.map +1 -1
- package/libs/ui/layout/src/lib/cell-popin/cell-popin.component.d.ts +28 -0
- package/libs/ui/layout/src/lib/cell-popin/cell-popin.component.d.ts.map +1 -0
- package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts +4 -2
- package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts.map +1 -1
- package/libs/ui/layout/src/lib/truncated-text/truncated-text.component.d.ts +5 -10
- package/libs/ui/layout/src/lib/truncated-text/truncated-text.component.d.ts.map +1 -1
- package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +2 -1
- package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
- package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +5 -3
- package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +7 -0
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/constant.ts +3 -1
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +1 -1
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +57 -14
- package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
- package/src/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.ts +3 -0
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +20 -14
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +3 -0
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +61 -0
- package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +1 -1
- package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.ts +1 -0
- package/src/libs/feature/record/src/lib/map-view/map-view.component.html +27 -9
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +84 -27
- package/src/libs/feature/search/src/lib/constants.ts +2 -1
- package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +1 -1
- package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +1 -0
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +1 -0
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +13 -3
- package/src/libs/ui/elements/src/index.ts +0 -1
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +8 -76
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +20 -51
- package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.html +69 -0
- package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.ts +61 -0
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +48 -9
- package/src/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.ts +4 -0
- package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +96 -37
- package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.ts +60 -29
- package/src/libs/ui/elements/src/lib/ui-elements.module.ts +2 -0
- package/src/libs/ui/layout/src/index.ts +1 -0
- package/src/libs/ui/layout/src/lib/cell-popin/cell-popin.component.html +40 -0
- package/src/libs/ui/layout/src/lib/cell-popin/cell-popin.component.ts +141 -0
- package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +2 -2
- package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +13 -6
- package/src/libs/ui/layout/src/lib/truncated-text/truncated-text.component.html +25 -42
- package/src/libs/ui/layout/src/lib/truncated-text/truncated-text.component.ts +10 -49
- package/src/libs/ui/layout/src/lib/ui-layout.module.ts +1 -1
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +6 -4
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +1 -0
- package/src/libs/ui/search/src/lib/results-table/results-table.component.html +14 -20
- package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +13 -5
- package/translations/de.json +20 -6
- package/translations/en.json +20 -6
- package/translations/es.json +19 -5
- package/translations/fr.json +20 -6
- package/translations/it.json +22 -8
- package/translations/nl.json +19 -5
- package/translations/pt.json +19 -5
- package/translations/sk.json +19 -5
- package/esm2022/libs/ui/elements/src/lib/related-record-card/related-record-card.component.mjs +0 -56
- package/libs/ui/elements/src/lib/related-record-card/related-record-card.component.d.ts +0 -19
- package/libs/ui/elements/src/lib/related-record-card/related-record-card.component.d.ts.map +0 -1
- package/src/libs/ui/elements/src/lib/related-record-card/related-record-card.component.css +0 -0
- package/src/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html +0 -9
- package/src/libs/ui/elements/src/lib/related-record-card/related-record-card.component.ts +0 -61
|
@@ -29,7 +29,10 @@ import {
|
|
|
29
29
|
} from 'rxjs/operators'
|
|
30
30
|
import { MdViewFacade } from '../state/mdview.facade'
|
|
31
31
|
import { DataService } from '../../../../../../libs/feature/dataviz/src'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
DatasetOnlineResource,
|
|
34
|
+
DatasetServiceDistribution,
|
|
35
|
+
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
33
36
|
import {
|
|
34
37
|
createViewFromLayer,
|
|
35
38
|
MapContext,
|
|
@@ -62,6 +65,7 @@ import { FetchError } from '../../../../../../libs/util/data-fetcher/src'
|
|
|
62
65
|
marker('map.dropdown.placeholder')
|
|
63
66
|
marker('wfs.feature.limit')
|
|
64
67
|
marker('dataset.error.restrictedAccess')
|
|
68
|
+
marker('map.select.style')
|
|
65
69
|
|
|
66
70
|
@Component({
|
|
67
71
|
selector: 'gn-ui-map-view',
|
|
@@ -96,32 +100,32 @@ export class MapViewComponent implements AfterViewInit {
|
|
|
96
100
|
selection: Feature
|
|
97
101
|
showLegend = true
|
|
98
102
|
legendExists = false
|
|
103
|
+
loading = false
|
|
104
|
+
error = null
|
|
105
|
+
|
|
106
|
+
selectLinkToDisplay(i: number) {
|
|
107
|
+
this.selectedLinkIndex$.next(i)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
selectStyleToDisplay(i: number) {
|
|
111
|
+
this.selectedStyleIndex$.next(i)
|
|
112
|
+
}
|
|
99
113
|
|
|
100
114
|
toggleLegend() {
|
|
101
115
|
this.showLegend = !this.showLegend
|
|
102
116
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.legendExists = status
|
|
117
|
+
onLegendStatusChange(v: boolean) {
|
|
118
|
+
this.legendExists = v
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
compatibleMapLinks$ = combineLatest([
|
|
109
122
|
this.mdViewFacade.mapApiLinks$,
|
|
110
123
|
this.mdViewFacade.geoDataLinksWithGeometry$,
|
|
111
124
|
]).pipe(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (link.type === 'service' && link.accessServiceProtocol === 'tms') {
|
|
117
|
-
return this.dataService.getGeodataLinksFromTms(link)
|
|
118
|
-
}
|
|
119
|
-
return link
|
|
120
|
-
})
|
|
121
|
-
)
|
|
122
|
-
processedMapApiLinks = processedMapApiLinks.flat()
|
|
123
|
-
return [...processedMapApiLinks, ...geoDataLinksWithGeometry]
|
|
124
|
-
}),
|
|
125
|
+
map(([mapApiLinks, geoDataLinksWithGeometry]) => [
|
|
126
|
+
...mapApiLinks,
|
|
127
|
+
...geoDataLinksWithGeometry,
|
|
128
|
+
]),
|
|
125
129
|
shareReplay(1)
|
|
126
130
|
)
|
|
127
131
|
|
|
@@ -135,15 +139,73 @@ export class MapViewComponent implements AfterViewInit {
|
|
|
135
139
|
: [{ label: 'map.dropdown.placeholder', value: 0 }]
|
|
136
140
|
)
|
|
137
141
|
)
|
|
138
|
-
selectedLinkIndex$ = new BehaviorSubject(0)
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
private selectedLinkIndex$ = new BehaviorSubject(0)
|
|
144
|
+
private selectedStyleIndex$ = new BehaviorSubject(0)
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
selectedSourceLink$ = combineLatest([
|
|
144
147
|
this.compatibleMapLinks$,
|
|
145
148
|
this.selectedLinkIndex$.pipe(distinctUntilChanged()),
|
|
146
|
-
]).pipe(
|
|
149
|
+
]).pipe(
|
|
150
|
+
map(([links, idx]) => links[idx]),
|
|
151
|
+
shareReplay(1)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
styleLinks$ = this.selectedSourceLink$.pipe(
|
|
155
|
+
switchMap((src) => {
|
|
156
|
+
if (
|
|
157
|
+
src &&
|
|
158
|
+
src.type === 'service' &&
|
|
159
|
+
src.accessServiceProtocol === 'tms'
|
|
160
|
+
) {
|
|
161
|
+
return from(
|
|
162
|
+
this.dataService.getGeodataLinksFromTms(
|
|
163
|
+
src as DatasetServiceDistribution,
|
|
164
|
+
false
|
|
165
|
+
)
|
|
166
|
+
).pipe(
|
|
167
|
+
// We need to check for maplibre-style links because when a TMS service has no styles,
|
|
168
|
+
// getGeodataLinksFromTms returns the original TMS link, which isn't a maplibre-style link
|
|
169
|
+
map(
|
|
170
|
+
(links) =>
|
|
171
|
+
links?.filter(
|
|
172
|
+
(link) =>
|
|
173
|
+
link.type === 'service' &&
|
|
174
|
+
link.accessServiceProtocol === 'maplibre-style'
|
|
175
|
+
) || []
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
return of([])
|
|
180
|
+
}),
|
|
181
|
+
tap(() => this.selectedStyleIndex$.next(0)),
|
|
182
|
+
shareReplay(1)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
styleDropdownChoices$ = this.styleLinks$.pipe(
|
|
186
|
+
map((links) =>
|
|
187
|
+
links.length
|
|
188
|
+
? links.map((link, index) => ({
|
|
189
|
+
label: getLinkLabel(link),
|
|
190
|
+
value: index,
|
|
191
|
+
}))
|
|
192
|
+
: [
|
|
193
|
+
{
|
|
194
|
+
label: '\u00A0\u00A0\u00A0\u00A0',
|
|
195
|
+
value: 0,
|
|
196
|
+
},
|
|
197
|
+
]
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
selectedLink$ = combineLatest([
|
|
202
|
+
this.selectedSourceLink$,
|
|
203
|
+
this.styleLinks$,
|
|
204
|
+
this.selectedStyleIndex$.pipe(distinctUntilChanged()),
|
|
205
|
+
]).pipe(
|
|
206
|
+
map(([src, styles, styleIdx]) => (styles.length ? styles[styleIdx] : src)),
|
|
207
|
+
shareReplay(1)
|
|
208
|
+
)
|
|
147
209
|
|
|
148
210
|
currentLayers$ = combineLatest([this.selectedLink$, this.excludeWfs$]).pipe(
|
|
149
211
|
switchMap(([link, excludeWfs]) => {
|
|
@@ -296,11 +358,6 @@ export class MapViewComponent implements AfterViewInit {
|
|
|
296
358
|
}
|
|
297
359
|
return throwError(() => 'protocol not supported')
|
|
298
360
|
}
|
|
299
|
-
|
|
300
|
-
selectLinkToDisplay(link: number) {
|
|
301
|
-
this.selectedLinkIndex$.next(link)
|
|
302
|
-
}
|
|
303
|
-
|
|
304
361
|
handleError(error: FetchError | Error | string) {
|
|
305
362
|
if (error instanceof FetchError) {
|
|
306
363
|
this.error = this.translateService.instant(
|
|
@@ -20,9 +20,10 @@ export const FIELDS_SUMMARY: FieldName[] = [
|
|
|
20
20
|
'userSavedCount',
|
|
21
21
|
'cl_topic',
|
|
22
22
|
'cl_maintenanceAndUpdateFrequency',
|
|
23
|
-
'
|
|
23
|
+
'MD_LegalConstraints*Object',
|
|
24
24
|
'qualityScore',
|
|
25
25
|
'allKeywords',
|
|
26
|
+
'recordLink',
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
export const FIELDS_BRIEF: FieldName[] = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<gn-ui-autocomplete
|
|
2
|
-
[placeholder]="'search.field.any.placeholder' | translate"
|
|
2
|
+
[placeholder]="placeholder ?? ('search.field.any.placeholder' | translate)"
|
|
3
3
|
[displayWithFn]="displayWithFn"
|
|
4
4
|
[action]="autoCompleteAction"
|
|
5
5
|
(itemSelected)="handleItemSelection($event)"
|
|
@@ -30,6 +30,7 @@ export class FuzzySearchComponent implements OnInit {
|
|
|
30
30
|
@Input() autoFocus = false
|
|
31
31
|
@Input() forceTrackPosition = false
|
|
32
32
|
@Input() enterButton = false
|
|
33
|
+
@Input() placeholder?: string
|
|
33
34
|
@Output() itemSelected = new EventEmitter<CatalogRecord>()
|
|
34
35
|
@Output() inputSubmitted = new EventEmitter<string>()
|
|
35
36
|
@Output() isSearchActive = new EventEmitter<boolean>()
|
|
@@ -12,7 +12,7 @@ import { SearchService } from '../utils/service/search.service'
|
|
|
12
12
|
import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
|
|
13
13
|
import { ResultsTableComponent } from '../../../../../../libs/ui/search/src'
|
|
14
14
|
import { CommonModule } from '@angular/common'
|
|
15
|
-
import { Subscription } from 'rxjs'
|
|
15
|
+
import { Observable, Subscription } from 'rxjs'
|
|
16
16
|
import { NotificationsService } from '../../../../../../libs/feature/notifications/src'
|
|
17
17
|
import { TranslateService } from '@ngx-translate/core'
|
|
18
18
|
|
|
@@ -24,8 +24,6 @@ import { TranslateService } from '@ngx-translate/core'
|
|
|
24
24
|
imports: [CommonModule, ResultsTableComponent],
|
|
25
25
|
})
|
|
26
26
|
export class ResultsTableContainerComponent implements OnDestroy {
|
|
27
|
-
@Input() canDuplicate: (record: CatalogRecord) => boolean = () => true
|
|
28
|
-
@Input() canDelete: (record: CatalogRecord) => boolean = () => true
|
|
29
27
|
@Input() isDuplicating: false
|
|
30
28
|
|
|
31
29
|
@Output() recordClick = new EventEmitter<CatalogRecord>()
|
|
@@ -39,6 +37,18 @@ export class ResultsTableContainerComponent implements OnDestroy {
|
|
|
39
37
|
hasDraft = (record: CatalogRecord): boolean =>
|
|
40
38
|
this.recordsRepository.recordHasDraft(record.uniqueIdentifier)
|
|
41
39
|
|
|
40
|
+
canDuplicate = (record: CatalogRecord): boolean => {
|
|
41
|
+
return this.recordsRepository.canDuplicate(record)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
canDelete = (record: CatalogRecord): Observable<boolean> => {
|
|
45
|
+
return this.recordsRepository.canDelete(record)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
canEdit = (record: CatalogRecord): Observable<boolean> => {
|
|
49
|
+
return this.recordsRepository.canEditIndexedRecord(record)
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
constructor(
|
|
43
53
|
protected searchFacade: SearchFacade,
|
|
44
54
|
private searchService: SearchService,
|
|
@@ -19,7 +19,6 @@ export * from './lib/metadata-quality-item/metadata-quality-item.component'
|
|
|
19
19
|
export * from './lib/metadata-quality/metadata-quality.component'
|
|
20
20
|
export * from './lib/notification/notification.component'
|
|
21
21
|
export * from './lib/record-api-form/record-api-form.component'
|
|
22
|
-
export * from './lib/related-record-card/related-record-card.component'
|
|
23
22
|
export * from './lib/thumbnail/thumbnail.component'
|
|
24
23
|
export * from './lib/ui-elements.module'
|
|
25
24
|
export * from './lib/user-feedback-item/user-feedback-item.component'
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
[fit]="'cover'"
|
|
19
19
|
></gn-ui-thumbnail>
|
|
20
20
|
</div>
|
|
21
|
-
<div class="grow flex flex-col gap-3">
|
|
21
|
+
<div class="grow flex flex-col gap-3 w-0">
|
|
22
22
|
<div class="flex items-center gap-2">
|
|
23
23
|
<div class="grow flex flex-wrap items-center gap-2">
|
|
24
24
|
<gn-ui-kind-badge
|
|
@@ -60,8 +60,9 @@
|
|
|
60
60
|
</h4>
|
|
61
61
|
</div>
|
|
62
62
|
<div
|
|
63
|
-
*ngIf="
|
|
64
|
-
class="mr-6 text-xs text-gray-900
|
|
63
|
+
*ngIf="displayAbstract()"
|
|
64
|
+
class="mr-6 text-xs text-gray-900 overflow-hidden"
|
|
65
|
+
[ngClass]="getAbstractClass()"
|
|
65
66
|
data-cy="recordAbstract"
|
|
66
67
|
>
|
|
67
68
|
<gn-ui-markdown-parser
|
|
@@ -71,80 +72,11 @@
|
|
|
71
72
|
</div>
|
|
72
73
|
</div>
|
|
73
74
|
|
|
74
|
-
<
|
|
75
|
-
data-cy="recordOrg"
|
|
75
|
+
<gn-ui-internal-link-card-contact
|
|
76
76
|
*ngIf="size !== 'XS' && record.ownerOrganization?.name"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<div
|
|
81
|
-
class="w-[45px] h-[45px] rounded-lg overflow-hidden shrink-0 mr-3"
|
|
82
|
-
>
|
|
83
|
-
<gn-ui-thumbnail
|
|
84
|
-
[thumbnailUrl]="
|
|
85
|
-
record.ownerOrganization?.logoUrl?.toString() || ''
|
|
86
|
-
"
|
|
87
|
-
[fit]="'contain'"
|
|
88
|
-
class="w-full h-full rounded-lg"
|
|
89
|
-
></gn-ui-thumbnail>
|
|
90
|
-
</div>
|
|
91
|
-
<div *ngIf="organization?.name" class="flex-1 w-0 overflow-hidden">
|
|
92
|
-
<div
|
|
93
|
-
class="text-xs text-black font-normal leading-tight truncate"
|
|
94
|
-
translate
|
|
95
|
-
>
|
|
96
|
-
record.card.metadata.contact
|
|
97
|
-
</div>
|
|
98
|
-
<div
|
|
99
|
-
data-cy="recordOrgName"
|
|
100
|
-
class="text-xl text-primary-black font-medium truncate"
|
|
101
|
-
>
|
|
102
|
-
{{ organization.name }}
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
<div *ngIf="size === 'L'" class="ml-2 flex space-x-2">
|
|
107
|
-
<div *ngIf="organization?.website" class="flex">
|
|
108
|
-
<button
|
|
109
|
-
[title]="organization.website"
|
|
110
|
-
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
|
|
111
|
-
(click)="openExternalUrl($event, organization.website)"
|
|
112
|
-
>
|
|
113
|
-
<ng-icon name="iconoirInternet"></ng-icon>
|
|
114
|
-
</button>
|
|
115
|
-
</div>
|
|
116
|
-
<div *ngIf="contacts[0]?.email" class="flex">
|
|
117
|
-
<button
|
|
118
|
-
[title]="contacts[0].email"
|
|
119
|
-
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
|
|
120
|
-
data-cy="contact-email"
|
|
121
|
-
(click)="openMailto($event, contacts[0].email)"
|
|
122
|
-
>
|
|
123
|
-
<ng-icon name="matEmailOutline"></ng-icon>
|
|
124
|
-
</button>
|
|
125
|
-
</div>
|
|
126
|
-
<div *ngIf="contacts[0]?.phone" class="flex">
|
|
127
|
-
<button
|
|
128
|
-
[title]="'Copy to clipboard'"
|
|
129
|
-
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
|
|
130
|
-
data-cy="contact-phone"
|
|
131
|
-
(click)="copyToClipboard($event, contacts[0].phone)"
|
|
132
|
-
>
|
|
133
|
-
<ng-icon name="matPhoneOutline"></ng-icon>
|
|
134
|
-
</button>
|
|
135
|
-
</div>
|
|
136
|
-
<div *ngIf="contacts[0]?.address" class="flex">
|
|
137
|
-
<button
|
|
138
|
-
[title]="'Copy to clipboard'"
|
|
139
|
-
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
|
|
140
|
-
data-cy="contact-phone"
|
|
141
|
-
(click)="copyToClipboard($event, contacts[0].address)"
|
|
142
|
-
>
|
|
143
|
-
<ng-icon name="matLocationOnOutline"></ng-icon>
|
|
144
|
-
</button>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
77
|
+
[record]="record"
|
|
78
|
+
[size]="size"
|
|
79
|
+
></gn-ui-internal-link-card-contact>
|
|
148
80
|
</div>
|
|
149
81
|
</div>
|
|
150
82
|
</div>
|
|
@@ -7,35 +7,20 @@ import {
|
|
|
7
7
|
EventEmitter,
|
|
8
8
|
ElementRef,
|
|
9
9
|
} from '@angular/core'
|
|
10
|
-
import {
|
|
11
|
-
CatalogRecord,
|
|
12
|
-
Organization,
|
|
13
|
-
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
10
|
+
import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
14
11
|
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
|
|
15
12
|
import { GeoDataBadgeComponent } from '../geo-data-badge/geo-data-badge.component'
|
|
16
13
|
import { KindBadgeComponent } from '../kind-badge/kind-badge.component'
|
|
17
14
|
import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
|
|
18
15
|
import { MetadataQualityComponent } from '../metadata-quality/metadata-quality.component'
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
stripHtml,
|
|
24
|
-
} from '../../../../../../libs/util/shared/src'
|
|
25
|
-
import {
|
|
26
|
-
NgIconComponent,
|
|
27
|
-
provideIcons,
|
|
28
|
-
provideNgIconsConfig,
|
|
29
|
-
} from '@ng-icons/core'
|
|
30
|
-
import {
|
|
31
|
-
matLocationSearchingOutline,
|
|
32
|
-
matEmailOutline,
|
|
33
|
-
matPhoneOutline,
|
|
34
|
-
matLocationOnOutline,
|
|
35
|
-
} from '@ng-icons/material-icons/outline'
|
|
16
|
+
import { InternalLinkCardContactComponent } from '../internal-link-card-contact/internal-link-card-contact.component'
|
|
17
|
+
import { removeWhitespace, stripHtml } from '../../../../../../libs/util/shared/src'
|
|
18
|
+
import { provideIcons, provideNgIconsConfig } from '@ng-icons/core'
|
|
19
|
+
import { matLocationSearchingOutline } from '@ng-icons/material-icons/outline'
|
|
36
20
|
import { iconoirInternet } from '@ng-icons/iconoir'
|
|
37
21
|
import { TranslateModule } from '@ngx-translate/core'
|
|
38
22
|
import { fromEvent, Subscription } from 'rxjs'
|
|
23
|
+
import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
|
|
39
24
|
|
|
40
25
|
type CardSize = 'L' | 'M' | 'S' | 'XS'
|
|
41
26
|
|
|
@@ -45,22 +30,19 @@ type CardSize = 'L' | 'M' | 'S' | 'XS'
|
|
|
45
30
|
imports: [
|
|
46
31
|
NgClass,
|
|
47
32
|
NgIf,
|
|
48
|
-
ThumbnailComponent,
|
|
49
33
|
MetadataQualityComponent,
|
|
50
34
|
NgTemplateOutlet,
|
|
51
|
-
NgIconComponent,
|
|
52
35
|
TranslateModule,
|
|
53
36
|
GeoDataBadgeComponent,
|
|
54
37
|
KindBadgeComponent,
|
|
55
38
|
MarkdownParserComponent,
|
|
39
|
+
InternalLinkCardContactComponent,
|
|
40
|
+
ThumbnailComponent,
|
|
56
41
|
],
|
|
57
42
|
providers: [
|
|
58
43
|
provideIcons({
|
|
59
44
|
iconoirInternet,
|
|
60
45
|
matLocationSearchingOutline,
|
|
61
|
-
matEmailOutline,
|
|
62
|
-
matPhoneOutline,
|
|
63
|
-
matLocationOnOutline,
|
|
64
46
|
}),
|
|
65
47
|
provideNgIconsConfig({
|
|
66
48
|
size: '1.2em',
|
|
@@ -125,35 +107,22 @@ export class InternalLinkCardComponent implements OnInit {
|
|
|
125
107
|
)
|
|
126
108
|
}
|
|
127
109
|
|
|
128
|
-
get organization(): Organization {
|
|
129
|
-
return this.record.ownerOrganization
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
get contacts() {
|
|
133
|
-
return (
|
|
134
|
-
(this.record.kind === 'dataset'
|
|
135
|
-
? this.record.contactsForResource
|
|
136
|
-
: this.record.contacts) || []
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
110
|
getTitleClass() {
|
|
141
111
|
return this.titleClassMap[this._size]
|
|
142
112
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
event.stopPropagation()
|
|
151
|
-
window.open(`mailto:${email}`, '_blank')
|
|
113
|
+
getAbstractClass(): string {
|
|
114
|
+
const marginClass = ['S', 'XS'].includes(this.size) ? 'ml-2' : ''
|
|
115
|
+
const clampClass =
|
|
116
|
+
this.size === 'L' && !this.record.ownerOrganization?.name
|
|
117
|
+
? 'line-clamp-6'
|
|
118
|
+
: 'line-clamp-2'
|
|
119
|
+
return `${clampClass} ${marginClass}`.trim()
|
|
152
120
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
121
|
+
displayAbstract(): boolean {
|
|
122
|
+
return (
|
|
123
|
+
this.size === 'L' ||
|
|
124
|
+
(['M', 'S'].includes(this.size) && !this.record.ownerOrganization?.name)
|
|
125
|
+
)
|
|
157
126
|
}
|
|
158
127
|
|
|
159
128
|
get shouldShowThumbnail(): boolean {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<div
|
|
2
|
+
data-cy="recordOrg"
|
|
3
|
+
class="flex items-center justify-evenly bg-gray-50 rounded-lg h-[53px] px-2"
|
|
4
|
+
>
|
|
5
|
+
<div class="flex items-center flex-1 min-w-0">
|
|
6
|
+
<div class="w-[45px] h-[45px] rounded-lg overflow-hidden shrink-0 mr-3">
|
|
7
|
+
<gn-ui-thumbnail
|
|
8
|
+
[thumbnailUrl]="record.ownerOrganization?.logoUrl?.toString() || ''"
|
|
9
|
+
[fit]="'contain'"
|
|
10
|
+
class="w-full h-full rounded-lg"
|
|
11
|
+
></gn-ui-thumbnail>
|
|
12
|
+
</div>
|
|
13
|
+
<div *ngIf="organization?.name" class="flex-1 w-0 overflow-hidden">
|
|
14
|
+
<div
|
|
15
|
+
class="text-xs text-black font-normal leading-tight truncate"
|
|
16
|
+
translate
|
|
17
|
+
>
|
|
18
|
+
record.card.metadata.contact
|
|
19
|
+
</div>
|
|
20
|
+
<div
|
|
21
|
+
data-cy="recordOrgName"
|
|
22
|
+
class="text-xl text-primary-black font-medium truncate"
|
|
23
|
+
>
|
|
24
|
+
{{ organization.name }}
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div *ngIf="size === 'L'" class="ml-2 flex space-x-2">
|
|
29
|
+
<div *ngIf="organization?.website" class="flex">
|
|
30
|
+
<button
|
|
31
|
+
[title]="organization.website"
|
|
32
|
+
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
|
|
33
|
+
(click)="openExternalUrl($event, organization.website)"
|
|
34
|
+
>
|
|
35
|
+
<ng-icon name="iconoirInternet"></ng-icon>
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
<div *ngIf="contacts[0]?.email" class="flex">
|
|
39
|
+
<button
|
|
40
|
+
[title]="contacts[0].email"
|
|
41
|
+
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
|
|
42
|
+
data-cy="contact-email"
|
|
43
|
+
(click)="openMailto($event, contacts[0].email)"
|
|
44
|
+
>
|
|
45
|
+
<ng-icon name="matEmailOutline"></ng-icon>
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
<div *ngIf="contacts[0]?.phone" class="flex">
|
|
49
|
+
<button
|
|
50
|
+
[title]="'Copy to clipboard'"
|
|
51
|
+
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
|
|
52
|
+
data-cy="contact-phone"
|
|
53
|
+
(click)="copyToClipboard($event, contacts[0].phone)"
|
|
54
|
+
>
|
|
55
|
+
<ng-icon name="matPhoneOutline"></ng-icon>
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div *ngIf="contacts[0]?.address" class="flex">
|
|
59
|
+
<button
|
|
60
|
+
[title]="'Copy to clipboard'"
|
|
61
|
+
class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
|
|
62
|
+
data-cy="contact-phone"
|
|
63
|
+
(click)="copyToClipboard($event, contacts[0].address)"
|
|
64
|
+
>
|
|
65
|
+
<ng-icon name="matLocationOnOutline"></ng-icon>
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core'
|
|
2
|
+
import { NgIf } from '@angular/common'
|
|
3
|
+
import {
|
|
4
|
+
CatalogRecord,
|
|
5
|
+
Organization,
|
|
6
|
+
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
7
|
+
import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
|
|
8
|
+
import { NgIconComponent, provideIcons } from '@ng-icons/core'
|
|
9
|
+
import {
|
|
10
|
+
matEmailOutline,
|
|
11
|
+
matPhoneOutline,
|
|
12
|
+
matLocationOnOutline,
|
|
13
|
+
} from '@ng-icons/material-icons/outline'
|
|
14
|
+
import { iconoirInternet } from '@ng-icons/iconoir'
|
|
15
|
+
import { TranslateModule } from '@ngx-translate/core'
|
|
16
|
+
|
|
17
|
+
@Component({
|
|
18
|
+
selector: 'gn-ui-internal-link-card-contact',
|
|
19
|
+
standalone: true,
|
|
20
|
+
imports: [NgIf, ThumbnailComponent, NgIconComponent, TranslateModule],
|
|
21
|
+
providers: [
|
|
22
|
+
provideIcons({
|
|
23
|
+
iconoirInternet,
|
|
24
|
+
matEmailOutline,
|
|
25
|
+
matPhoneOutline,
|
|
26
|
+
matLocationOnOutline,
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
templateUrl: './internal-link-card-contact.component.html',
|
|
30
|
+
})
|
|
31
|
+
export class InternalLinkCardContactComponent {
|
|
32
|
+
@Input() record: CatalogRecord
|
|
33
|
+
@Input() size: 'L' | 'M' | 'S' | 'XS' = 'M'
|
|
34
|
+
|
|
35
|
+
get organization(): Organization {
|
|
36
|
+
return this.record.ownerOrganization
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get contacts() {
|
|
40
|
+
return (
|
|
41
|
+
(this.record.kind === 'dataset'
|
|
42
|
+
? this.record.contactsForResource
|
|
43
|
+
: this.record.contacts) || []
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
openExternalUrl(event: Event, url: URL): void {
|
|
48
|
+
event.stopPropagation()
|
|
49
|
+
window.open(url, '_blank')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
openMailto(event: Event, email: string): void {
|
|
53
|
+
event.stopPropagation()
|
|
54
|
+
window.open(`mailto:${email}`, '_blank')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
copyToClipboard(event: Event, text: string): void {
|
|
58
|
+
event.stopPropagation()
|
|
59
|
+
navigator.clipboard.writeText(text)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -20,6 +20,10 @@ import { NgIcon } from '@ng-icons/core'
|
|
|
20
20
|
import { matInfoOutline } from '@ng-icons/material-icons/outline'
|
|
21
21
|
import { provideIcons, provideNgIconsConfig } from '@ng-icons/core'
|
|
22
22
|
|
|
23
|
+
type QualityChecks = {
|
|
24
|
+
[key: string]: (metadata: Partial<CatalogRecord>) => boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
@Component({
|
|
24
28
|
selector: 'gn-ui-metadata-quality',
|
|
25
29
|
templateUrl: './metadata-quality.component.html',
|
|
@@ -69,18 +73,53 @@ export class MetadataQualityComponent implements OnChanges {
|
|
|
69
73
|
this.items.push({ name, value })
|
|
70
74
|
}
|
|
71
75
|
}
|
|
76
|
+
hasGetCapabilities(url: string): boolean {
|
|
77
|
+
return url.toLowerCase().includes('capabilities')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private readonly COMMON_CHECKS: QualityChecks = {
|
|
81
|
+
title: (metadata) => !!metadata?.title,
|
|
82
|
+
description: (metadata) => !!metadata?.abstract,
|
|
83
|
+
keywords: (metadata) => (metadata?.keywords?.length ?? 0) > 0,
|
|
84
|
+
legalConstraints: (metadata) =>
|
|
85
|
+
(metadata?.legalConstraints?.length ?? 0) > 0,
|
|
86
|
+
contact: (metadata) => !!metadata?.contacts?.[0]?.email,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private readonly SPECIFIC_CHECKS: Record<string, QualityChecks> = {
|
|
90
|
+
dataset: {
|
|
91
|
+
updateFrequency: (metadata) => !!metadata?.updateFrequency,
|
|
92
|
+
topic: (metadata) => (metadata?.topics?.length ?? 0) > 0,
|
|
93
|
+
organisation: (metadata) => !!metadata?.contacts?.[0]?.organization?.name,
|
|
94
|
+
},
|
|
95
|
+
service: {
|
|
96
|
+
capabilities: (metadata) =>
|
|
97
|
+
(metadata?.onlineResources ?? []).some((resource) =>
|
|
98
|
+
this.hasGetCapabilities(resource?.url?.href ?? '')
|
|
99
|
+
),
|
|
100
|
+
},
|
|
101
|
+
reuse: {
|
|
102
|
+
topic: (metadata) => (metadata?.topics?.length ?? 0) > 0,
|
|
103
|
+
organisation: (metadata) => !!metadata?.contacts?.[0]?.organization?.name,
|
|
104
|
+
source: (metadata) => !!metadata?.extras?.sourcesIdentifiers,
|
|
105
|
+
},
|
|
106
|
+
}
|
|
72
107
|
|
|
73
108
|
initialize() {
|
|
74
|
-
const contact = this.metadata?.contacts?.[0]
|
|
75
109
|
this.items = []
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
83
|
-
|
|
110
|
+
|
|
111
|
+
Object.entries(this.COMMON_CHECKS).forEach(([name, check]) => {
|
|
112
|
+
this.add(name, check(this.metadata))
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const datasetType = this.metadata?.kind
|
|
116
|
+
if (datasetType && this.SPECIFIC_CHECKS[datasetType]) {
|
|
117
|
+
Object.entries(this.SPECIFIC_CHECKS[datasetType]).forEach(
|
|
118
|
+
([name, check]) => {
|
|
119
|
+
this.add(name, check(this.metadata))
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
}
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
ngOnChanges(changes: SimpleChanges): void {
|