geonetwork-ui 2.6.0-dev.186d57931 → 2.6.0-dev.3e7617888
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/index.mjs +2 -1
- package/esm2022/libs/api/metadata-converter/src/lib/common/resource-types.mjs +17 -15
- package/esm2022/libs/feature/search/src/index.mjs +2 -2
- package/esm2022/libs/feature/search/src/lib/feature-search.module.mjs +12 -5
- package/esm2022/libs/feature/search/src/lib/results-hits/results-hits.container.component.mjs +41 -0
- package/esm2022/libs/feature/search/src/lib/utils/service/fields.mjs +70 -1
- package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +4 -3
- package/esm2022/libs/ui/elements/src/index.mjs +2 -1
- package/esm2022/libs/ui/elements/src/lib/kind-badge/kind-badge.component.mjs +51 -0
- package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -4
- package/esm2022/libs/ui/inputs/src/index.mjs +2 -1
- package/esm2022/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.mjs +3 -3
- package/esm2022/libs/ui/inputs/src/lib/inline-filter/inline-filter.component.mjs +42 -0
- package/esm2022/libs/ui/inputs/src/lib/inline-filter/inline-filter.model.mjs +2 -0
- package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +7 -2
- package/esm2022/libs/ui/search/src/index.mjs +2 -1
- package/esm2022/libs/ui/search/src/lib/results-hits-number/results-hits-number.component.mjs +3 -3
- package/esm2022/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.mjs +53 -0
- package/esm2022/libs/ui/search/src/lib/ui-search.module.mjs +11 -3
- package/esm2022/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.mjs +3 -3
- package/esm2022/translations/de.json +5 -1
- package/esm2022/translations/en.json +5 -1
- package/esm2022/translations/es.json +5 -1
- package/esm2022/translations/fr.json +5 -1
- package/esm2022/translations/it.json +5 -1
- package/esm2022/translations/nl.json +5 -1
- package/esm2022/translations/pt.json +5 -1
- package/fesm2022/geonetwork-ui.mjs +337 -74
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/index.d.ts +1 -0
- package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts +21 -0
- package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts.map +1 -1
- package/libs/feature/search/src/index.d.ts +1 -1
- package/libs/feature/search/src/index.d.ts.map +1 -1
- package/libs/feature/search/src/lib/feature-search.module.d.ts +4 -2
- package/libs/feature/search/src/lib/feature-search.module.d.ts.map +1 -1
- package/libs/feature/search/src/lib/results-hits/results-hits.container.component.d.ts +21 -0
- package/libs/feature/search/src/lib/results-hits/results-hits.container.component.d.ts.map +1 -0
- package/libs/feature/search/src/lib/utils/service/fields.d.ts +21 -0
- package/libs/feature/search/src/lib/utils/service/fields.d.ts.map +1 -1
- package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
- package/libs/ui/elements/src/index.d.ts +1 -0
- package/libs/ui/elements/src/index.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/kind-badge/kind-badge.component.d.ts +11 -0
- package/libs/ui/elements/src/lib/kind-badge/kind-badge.component.d.ts.map +1 -0
- 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/inputs/src/index.d.ts +1 -0
- package/libs/ui/inputs/src/index.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/inline-filter/inline-filter.component.d.ts +14 -0
- package/libs/ui/inputs/src/lib/inline-filter/inline-filter.component.d.ts.map +1 -0
- package/libs/ui/inputs/src/lib/inline-filter/inline-filter.model.d.ts +6 -0
- package/libs/ui/inputs/src/lib/inline-filter/inline-filter.model.d.ts.map +1 -0
- package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +25 -24
- package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts.map +1 -1
- package/libs/ui/search/src/index.d.ts +1 -0
- package/libs/ui/search/src/index.d.ts.map +1 -1
- package/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.d.ts +17 -0
- package/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.d.ts.map +1 -0
- package/libs/ui/search/src/lib/ui-search.module.d.ts +21 -19
- package/libs/ui/search/src/lib/ui-search.module.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/index.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/common/resource-types.ts +29 -15
- package/src/libs/feature/search/src/index.ts +1 -1
- package/src/libs/feature/search/src/lib/feature-search.module.ts +9 -2
- package/src/libs/feature/search/src/lib/results-hits/results-hits.container.component.css +0 -0
- package/src/libs/feature/search/src/lib/results-hits/results-hits.container.component.html +16 -0
- package/src/libs/feature/search/src/lib/results-hits/results-hits.container.component.ts +59 -0
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +4 -5
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +99 -0
- package/src/libs/ui/elements/src/index.ts +1 -0
- package/src/libs/ui/elements/src/lib/kind-badge/kind-badge.component.css +6 -0
- package/src/libs/ui/elements/src/lib/kind-badge/kind-badge.component.html +9 -0
- package/src/libs/ui/elements/src/lib/kind-badge/kind-badge.component.ts +51 -0
- package/src/libs/ui/elements/src/lib/ui-elements.module.ts +3 -0
- package/src/libs/ui/inputs/src/index.ts +1 -0
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/inline-filter/inline-filter.component.html +23 -0
- package/src/libs/ui/inputs/src/lib/inline-filter/inline-filter.component.ts +44 -0
- package/src/libs/ui/inputs/src/lib/inline-filter/inline-filter.model.ts +5 -0
- package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +3 -0
- package/src/libs/ui/search/src/index.ts +1 -0
- package/src/libs/ui/search/src/lib/results-hits-number/results-hits-number.component.html +1 -1
- package/src/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.html +24 -0
- package/src/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.ts +53 -0
- package/src/libs/ui/search/src/lib/ui-search.module.ts +5 -0
- package/src/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.html +1 -1
- package/translations/de.json +5 -1
- package/translations/en.json +5 -1
- package/translations/es.json +5 -1
- package/translations/fr.json +5 -1
- package/translations/it.json +5 -1
- package/translations/nl.json +5 -1
- package/translations/pt.json +5 -1
- package/translations/sk.json +5 -1
- package/esm2022/libs/feature/search/src/lib/results-hits-number/results-hits.container.component.mjs +0 -18
- package/libs/feature/search/src/lib/results-hits-number/results-hits.container.component.d.ts +0 -9
- package/libs/feature/search/src/lib/results-hits-number/results-hits.container.component.d.ts.map +0 -1
- package/src/libs/feature/search/src/lib/results-hits-number/results-hits.container.component.html +0 -4
- package/src/libs/feature/search/src/lib/results-hits-number/results-hits.container.component.ts +0 -10
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="flex flex-col gap-3 sm:flex-row justify-between"
|
|
3
|
+
[ngClass]="{
|
|
4
|
+
'sm:items-center': (searchFacade.resultsHits$ | async) !== 0,
|
|
5
|
+
}"
|
|
6
|
+
>
|
|
7
|
+
<gn-ui-results-hits-number
|
|
8
|
+
[loading]="searchFacade.isLoading$ | async"
|
|
9
|
+
[hits]="searchFacade.resultsHits$ | async"
|
|
10
|
+
></gn-ui-results-hits-number>
|
|
11
|
+
<gn-ui-results-hits-search-kind
|
|
12
|
+
(selectionChanged)="onSelectionChanged($event)"
|
|
13
|
+
[choices]="filterChoices$ | async"
|
|
14
|
+
[selected]="selected$ | async"
|
|
15
|
+
></gn-ui-results-hits-search-kind>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
catchError,
|
|
3
|
+
filter,
|
|
4
|
+
map,
|
|
5
|
+
Observable,
|
|
6
|
+
of,
|
|
7
|
+
startWith,
|
|
8
|
+
switchMap,
|
|
9
|
+
} from 'rxjs'
|
|
10
|
+
import { Component, OnInit } from '@angular/core'
|
|
11
|
+
import { marker } from '@biesbjerg/ngx-translate-extract-marker'
|
|
12
|
+
import { SearchFacade } from '../state/search.facade'
|
|
13
|
+
import { FieldAvailableValue, FieldValue } from '../utils/service/fields'
|
|
14
|
+
import { SearchService } from '../utils/service/search.service'
|
|
15
|
+
import { FieldsService } from '../utils/service/fields.service'
|
|
16
|
+
|
|
17
|
+
marker('search.filters.recordKind.all')
|
|
18
|
+
marker('search.filters.recordKind.dataset')
|
|
19
|
+
marker('search.filters.recordKind.service')
|
|
20
|
+
marker('search.filters.recordKind.reuse')
|
|
21
|
+
|
|
22
|
+
@Component({
|
|
23
|
+
selector: 'gn-ui-results-hits',
|
|
24
|
+
templateUrl: './results-hits.container.component.html',
|
|
25
|
+
styleUrls: ['./results-hits.container.component.css'],
|
|
26
|
+
})
|
|
27
|
+
export class ResultsHitsContainerComponent implements OnInit {
|
|
28
|
+
fieldName = 'recordKind'
|
|
29
|
+
filterChoices$: Observable<FieldAvailableValue[]>
|
|
30
|
+
selected$: Observable<FieldValue[]>
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
protected searchFacade: SearchFacade,
|
|
34
|
+
private searchService: SearchService,
|
|
35
|
+
private fieldsService: FieldsService
|
|
36
|
+
) {}
|
|
37
|
+
|
|
38
|
+
ngOnInit() {
|
|
39
|
+
this.selected$ = this.searchFacade.searchFilters$.pipe(
|
|
40
|
+
switchMap((filters) =>
|
|
41
|
+
this.fieldsService.readFieldValuesFromFilters(filters)
|
|
42
|
+
),
|
|
43
|
+
map((fieldValues) => fieldValues[this.fieldName]),
|
|
44
|
+
filter((selected) => !!selected),
|
|
45
|
+
startWith([]),
|
|
46
|
+
catchError(() => of([]))
|
|
47
|
+
) as Observable<FieldValue[]>
|
|
48
|
+
|
|
49
|
+
this.filterChoices$ = <Observable<FieldAvailableValue[]>>(
|
|
50
|
+
this.fieldsService.getAvailableValues(this.fieldName)
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onSelectionChanged(values: string[]) {
|
|
55
|
+
this.fieldsService
|
|
56
|
+
.buildFiltersFromFieldValues({ [this.fieldName]: values })
|
|
57
|
+
.subscribe((filters) => this.searchService.updateFilters(filters))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
MultilingualSearchField,
|
|
11
11
|
OrganizationSearchField,
|
|
12
12
|
OwnerSearchField,
|
|
13
|
+
ResourceTypeLegacyField,
|
|
13
14
|
SimpleSearchField,
|
|
14
15
|
TranslatedSearchField,
|
|
16
|
+
RecordKindField,
|
|
15
17
|
UserSearchField,
|
|
16
18
|
} from './fields'
|
|
17
19
|
import { forkJoin, Observable, of } from 'rxjs'
|
|
@@ -47,11 +49,8 @@ export class FieldsService {
|
|
|
47
49
|
protected fields = {
|
|
48
50
|
organization: new OrganizationSearchField(this.injector),
|
|
49
51
|
format: new SimpleSearchField('format', this.injector, 'asc'),
|
|
50
|
-
resourceType: new
|
|
51
|
-
|
|
52
|
-
this.injector,
|
|
53
|
-
'asc'
|
|
54
|
-
),
|
|
52
|
+
resourceType: new ResourceTypeLegacyField(this.injector), // Deprecated, use `recordKind` instead
|
|
53
|
+
recordKind: new RecordKindField(this.injector),
|
|
55
54
|
representationType: new TranslatedSearchField(
|
|
56
55
|
'cl_spatialRepresentationType.key',
|
|
57
56
|
this.injector,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from '../../../../../../../libs/api/repository/src'
|
|
23
23
|
import { LangService } from '../../../../../../../libs/util/i18n/src'
|
|
24
24
|
import { formatUserInfo } from '../../../../../../../libs/util/shared/src'
|
|
25
|
+
import { PossibleResourceTypes } from '../../../../../../../libs/api/metadata-converter/src'
|
|
25
26
|
|
|
26
27
|
export type FieldType = 'values' | 'dateRange'
|
|
27
28
|
|
|
@@ -29,6 +30,7 @@ export type FieldValue = string | number
|
|
|
29
30
|
export interface FieldAvailableValue {
|
|
30
31
|
value: FieldValue
|
|
31
32
|
label: string
|
|
33
|
+
count?: number
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export abstract class AbstractSearchField {
|
|
@@ -80,6 +82,7 @@ export class SimpleSearchField implements AbstractSearchField {
|
|
|
80
82
|
const bucketPromises = buckets.map(async (bucket) => ({
|
|
81
83
|
label: `${await this.getBucketLabel(bucket)} (${bucket.count})`,
|
|
82
84
|
value: bucket.term.toString(),
|
|
85
|
+
count: bucket.count,
|
|
83
86
|
}))
|
|
84
87
|
return Promise.all(bucketPromises)
|
|
85
88
|
})
|
|
@@ -480,3 +483,99 @@ export class AvailableServicesField extends SimpleSearchField {
|
|
|
480
483
|
return of(values)
|
|
481
484
|
}
|
|
482
485
|
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* This class is meant to be used with the legacy filter on `resourceType` (now deprecated, the use of `recordKind` field is recommended).
|
|
489
|
+
* Since creating filters on the same ES field is not possible, in order to make the resource type filter still working,
|
|
490
|
+
* we create an ES on the fly: `resourceTypeLegacy` that references the `resourceType` under the hood.
|
|
491
|
+
* @deprecated Use `recordKind` field instead.
|
|
492
|
+
*/
|
|
493
|
+
export class ResourceTypeLegacyField extends TranslatedSearchField {
|
|
494
|
+
constructor(injector: Injector) {
|
|
495
|
+
super('resourceTypeLegacy', injector, 'asc')
|
|
496
|
+
|
|
497
|
+
// Ask ES to create a field on the fly: 'resourceTypeLegacy' that is in fact, 'resourceType'
|
|
498
|
+
this.esService.registerRuntimeField(
|
|
499
|
+
'resourceTypeLegacy',
|
|
500
|
+
`for (resourceType in doc.resourceType) { emit(resourceType) }`
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export class RecordKindField extends SimpleSearchField {
|
|
506
|
+
TYPE_MAPPING = {
|
|
507
|
+
dataset: ['dataset', 'series', 'featureCatalog'],
|
|
508
|
+
service: ['service'],
|
|
509
|
+
reuse: Object.entries(PossibleResourceTypes)
|
|
510
|
+
.filter(([_, v]) => v === 'reuse')
|
|
511
|
+
.map(([k]) => k), // = ['application', 'map', 'staticMap', 'interactiveMap', ...]
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
constructor(injector: Injector) {
|
|
515
|
+
super('resourceType', injector, 'asc')
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
getAvailableValues(): Observable<FieldAvailableValue[]> {
|
|
519
|
+
return this.repository.aggregate(this.getAggregations()).pipe(
|
|
520
|
+
map(
|
|
521
|
+
(response) =>
|
|
522
|
+
(response[this.esFieldName] as AggregationBuckets).buckets || []
|
|
523
|
+
),
|
|
524
|
+
map((buckets: TermBucket[]) => {
|
|
525
|
+
const counts = buckets.reduce(
|
|
526
|
+
(acc, { term, count }) => {
|
|
527
|
+
const value = term.toString()
|
|
528
|
+
const key = this.TYPE_MAPPING.reuse.includes(value)
|
|
529
|
+
? 'reuse'
|
|
530
|
+
: this.TYPE_MAPPING.dataset.includes(value)
|
|
531
|
+
? 'dataset'
|
|
532
|
+
: value
|
|
533
|
+
|
|
534
|
+
acc[key] = (acc[key] || 0) + count
|
|
535
|
+
return acc
|
|
536
|
+
},
|
|
537
|
+
{} as Record<string, number>
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
return Object.keys(this.TYPE_MAPPING).map((type) => ({
|
|
541
|
+
label: type,
|
|
542
|
+
value: type,
|
|
543
|
+
count: counts[type] ?? 0,
|
|
544
|
+
}))
|
|
545
|
+
})
|
|
546
|
+
)
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
getFiltersForValues(values: FieldValue[]): Observable<FieldFilters> {
|
|
550
|
+
const filters = {
|
|
551
|
+
[this.esFieldName]: values.reduce((acc, value) => {
|
|
552
|
+
if (value === '') return { ...acc, [value]: true }
|
|
553
|
+
|
|
554
|
+
const keysToAdd = this.TYPE_MAPPING[value] || [value]
|
|
555
|
+
keysToAdd.forEach((key: string) => (acc[key] = true))
|
|
556
|
+
|
|
557
|
+
return acc
|
|
558
|
+
}, {}),
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return of(filters)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
getValuesForFilter(filters: FieldFilters): Observable<FieldValue[]> {
|
|
565
|
+
const filter = filters[this.esFieldName]
|
|
566
|
+
if (!filter) return of([])
|
|
567
|
+
|
|
568
|
+
const activeValues = Object.keys(filter).filter((v) => filter[v])
|
|
569
|
+
const activeTypes = Object.keys(this.TYPE_MAPPING).filter((type) =>
|
|
570
|
+
this.TYPE_MAPPING[type].every((t: string) => activeValues.includes(t))
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
// Allow unknown values eg. 'type=somethingnotexist' (for UI to select none)
|
|
574
|
+
const allTypes = [].concat(...Object.values(this.TYPE_MAPPING))
|
|
575
|
+
const unknownValues = activeValues.filter(
|
|
576
|
+
(value) => !allTypes.includes(value)
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
return of([...activeTypes, ...unknownValues])
|
|
580
|
+
}
|
|
581
|
+
}
|
|
@@ -7,6 +7,7 @@ export * from './lib/downloads-list/downloads-list.component'
|
|
|
7
7
|
export * from './lib/error/error.component'
|
|
8
8
|
export * from './lib/image-input/image-input.component'
|
|
9
9
|
export * from './lib/image-overlay-preview/image-overlay-preview.component'
|
|
10
|
+
export * from './lib/kind-badge/kind-badge.component'
|
|
10
11
|
export * from './lib/link-card/link-card.component'
|
|
11
12
|
export * from './lib/markdown-editor/markdown-editor.component'
|
|
12
13
|
export * from './lib/markdown-parser/markdown-parser.component'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<ng-icon [name]="iconKind" class="mr-1"></ng-icon>
|
|
2
|
+
|
|
3
|
+
<ng-container *ngIf="contentTemplate; else defaultContent">
|
|
4
|
+
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
|
5
|
+
</ng-container>
|
|
6
|
+
|
|
7
|
+
<ng-template #defaultContent>
|
|
8
|
+
{{ kind | translate }}
|
|
9
|
+
</ng-template>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common'
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
Input,
|
|
6
|
+
TemplateRef,
|
|
7
|
+
} from '@angular/core'
|
|
8
|
+
import { provideIcons } from '@ng-icons/core'
|
|
9
|
+
import {
|
|
10
|
+
iconoirAppleWallet,
|
|
11
|
+
iconoirAppleShortcuts,
|
|
12
|
+
iconoirCode,
|
|
13
|
+
iconoirCreditCard,
|
|
14
|
+
} from '@ng-icons/iconoir'
|
|
15
|
+
import { NgIconsModule } from '@ng-icons/core'
|
|
16
|
+
import { BadgeComponent } from '../../../../../../libs/ui/inputs/src'
|
|
17
|
+
import { TranslateModule } from '@ngx-translate/core'
|
|
18
|
+
|
|
19
|
+
enum KindConfig {
|
|
20
|
+
all = 'iconoirAppleWallet', // (this one is for filter)
|
|
21
|
+
dataset = 'iconoirAppleShortcuts',
|
|
22
|
+
service = 'iconoirCode',
|
|
23
|
+
reuse = 'iconoirCreditCard',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Component({
|
|
27
|
+
selector: 'gn-ui-kind-badge',
|
|
28
|
+
templateUrl: './kind-badge.component.html',
|
|
29
|
+
styleUrls: ['./kind-badge.component.css'],
|
|
30
|
+
viewProviders: [
|
|
31
|
+
provideIcons({
|
|
32
|
+
iconoirAppleWallet,
|
|
33
|
+
iconoirAppleShortcuts,
|
|
34
|
+
iconoirCode,
|
|
35
|
+
iconoirCreditCard,
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
39
|
+
standalone: true,
|
|
40
|
+
imports: [NgIconsModule, CommonModule, BadgeComponent, TranslateModule],
|
|
41
|
+
})
|
|
42
|
+
export class KindBadgeComponent {
|
|
43
|
+
@Input() contentTemplate: TemplateRef<unknown>
|
|
44
|
+
@Input() kind: string
|
|
45
|
+
|
|
46
|
+
hasProjectedContent = false
|
|
47
|
+
|
|
48
|
+
get iconKind() {
|
|
49
|
+
return KindConfig[this.kind] || KindConfig.dataset
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -16,6 +16,7 @@ import { TranslateModule } from '@ngx-translate/core'
|
|
|
16
16
|
import { AvatarComponent } from './avatar/avatar.component'
|
|
17
17
|
import { ImageInputComponent } from './image-input/image-input.component'
|
|
18
18
|
import { MarkdownParserComponent } from './markdown-parser/markdown-parser.component'
|
|
19
|
+
import { KindBadgeComponent } from './kind-badge/kind-badge.component'
|
|
19
20
|
import { ThumbnailComponent } from './thumbnail/thumbnail.component'
|
|
20
21
|
import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
|
|
21
22
|
import { UserPreviewComponent } from './user-preview/user-preview.component'
|
|
@@ -46,6 +47,7 @@ import { ServiceCapabilitiesComponent } from './service-capabilities/service-cap
|
|
|
46
47
|
ApplicationBannerComponent,
|
|
47
48
|
InternalLinkCardComponent,
|
|
48
49
|
ServiceCapabilitiesComponent,
|
|
50
|
+
KindBadgeComponent,
|
|
49
51
|
],
|
|
50
52
|
providers: [
|
|
51
53
|
provideNgIconsConfig({
|
|
@@ -62,6 +64,7 @@ import { ServiceCapabilitiesComponent } from './service-capabilities/service-cap
|
|
|
62
64
|
ApplicationBannerComponent,
|
|
63
65
|
InternalLinkCardComponent,
|
|
64
66
|
ServiceCapabilitiesComponent,
|
|
67
|
+
KindBadgeComponent,
|
|
65
68
|
],
|
|
66
69
|
})
|
|
67
70
|
export class UiElementsModule {}
|
|
@@ -15,6 +15,7 @@ export * from './lib/dropdown-selector/dropdown-selector.model'
|
|
|
15
15
|
export * from './lib/editable-label/editable-label.directive'
|
|
16
16
|
export * from './lib/file-input/file-input.component'
|
|
17
17
|
export * from './lib/files-drop/files-drop.directive'
|
|
18
|
+
export * from './lib/inline-filter/inline-filter.component'
|
|
18
19
|
export * from './lib/search-input/search-input.component'
|
|
19
20
|
export * from './lib/star-toggle/star-toggle.component'
|
|
20
21
|
export * from './lib/switch-toggle/switch-toggle.component'
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
#overlayContainer
|
|
60
60
|
>
|
|
61
61
|
<div
|
|
62
|
-
class="border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary"
|
|
62
|
+
class="border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary"
|
|
63
63
|
>
|
|
64
64
|
<button
|
|
65
65
|
type="button"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<ul class="flex flex-wrap list-none gap-2">
|
|
2
|
+
<li *ngFor="let choice of choices">
|
|
3
|
+
<label
|
|
4
|
+
class=""
|
|
5
|
+
[ngClass]="{
|
|
6
|
+
selected: isSelected(choice),
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
<input
|
|
10
|
+
class="hidden"
|
|
11
|
+
type="checkbox"
|
|
12
|
+
#checkBox
|
|
13
|
+
[checked]="isSelected(choice)"
|
|
14
|
+
(change)="select(choice, checkBox.checked)"
|
|
15
|
+
[attr.data-cy]="'inlineFilter-' + choice.value"
|
|
16
|
+
/>
|
|
17
|
+
<ng-container
|
|
18
|
+
*ngTemplateOutlet="itemTemplate; context: { $implicit: choice }"
|
|
19
|
+
>
|
|
20
|
+
</ng-container>
|
|
21
|
+
</label>
|
|
22
|
+
</li>
|
|
23
|
+
</ul>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ContentChild,
|
|
4
|
+
EventEmitter,
|
|
5
|
+
Input,
|
|
6
|
+
Output,
|
|
7
|
+
TemplateRef,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
import { Choice } from './inline-filter.model'
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'gn-ui-inline-filter',
|
|
13
|
+
templateUrl: './inline-filter.component.html',
|
|
14
|
+
})
|
|
15
|
+
export class InlineFilterComponent {
|
|
16
|
+
@Input() choices: Choice[]
|
|
17
|
+
@Input() selected: unknown[] = []
|
|
18
|
+
|
|
19
|
+
@Output() selectValues = new EventEmitter<unknown[]>()
|
|
20
|
+
|
|
21
|
+
@ContentChild(TemplateRef) itemTemplate: TemplateRef<any>
|
|
22
|
+
|
|
23
|
+
isSelected(choice: Choice) {
|
|
24
|
+
return (
|
|
25
|
+
this.selected.indexOf(choice.value) > -1 ||
|
|
26
|
+
(this.selected.length === 0 && choice.value === 'all')
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
select(choice: Choice, selected: boolean) {
|
|
31
|
+
if (choice.value === 'all' && selected) {
|
|
32
|
+
this.selected = [choice.value]
|
|
33
|
+
} else {
|
|
34
|
+
this.selected = selected
|
|
35
|
+
? [...this.selected.filter((v) => v !== choice.value), choice.value]
|
|
36
|
+
: this.selected.filter((v) => v !== choice.value)
|
|
37
|
+
|
|
38
|
+
// If any value selected, unselect all
|
|
39
|
+
this.selected = this.selected.filter((v) => v !== 'all')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.selectValues.emit(this.selected)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -33,6 +33,7 @@ import { DragAndDropFileInputComponent } from './drag-and-drop-file-input/drag-a
|
|
|
33
33
|
import { DropdownMultiselectComponent } from './dropdown-multiselect/dropdown-multiselect.component'
|
|
34
34
|
import { DropdownSelectorComponent } from './dropdown-selector/dropdown-selector.component'
|
|
35
35
|
import { EditableLabelDirective } from './editable-label/editable-label.directive'
|
|
36
|
+
import { InlineFilterComponent } from './inline-filter/inline-filter.component'
|
|
36
37
|
import { TextAreaComponent } from './text-area/text-area.component'
|
|
37
38
|
import { ViewportIntersectorComponent } from './viewport-intersector/viewport-intersector.component'
|
|
38
39
|
|
|
@@ -42,6 +43,7 @@ import { ViewportIntersectorComponent } from './viewport-intersector/viewport-in
|
|
|
42
43
|
DropdownMultiselectComponent,
|
|
43
44
|
ViewportIntersectorComponent,
|
|
44
45
|
CheckboxComponent,
|
|
46
|
+
InlineFilterComponent,
|
|
45
47
|
],
|
|
46
48
|
imports: [
|
|
47
49
|
CommonModule,
|
|
@@ -90,6 +92,7 @@ import { ViewportIntersectorComponent } from './viewport-intersector/viewport-in
|
|
|
90
92
|
CheckboxComponent,
|
|
91
93
|
DateRangePickerComponent,
|
|
92
94
|
EditableLabelDirective,
|
|
95
|
+
InlineFilterComponent,
|
|
93
96
|
BadgeComponent,
|
|
94
97
|
],
|
|
95
98
|
})
|
|
@@ -16,5 +16,6 @@ export * from './lib/record-preview-text/record-preview-text.component'
|
|
|
16
16
|
export * from './lib/record-preview-title/record-preview-title.component'
|
|
17
17
|
export * from './lib/record-metric/record-metric.component'
|
|
18
18
|
export * from './lib/results-list-item/results-list-item.component'
|
|
19
|
+
export * from './lib/results-hits-search-kind/results-hits-search-kind.component'
|
|
19
20
|
export * from './lib/results-hits-number/results-hits-number.component'
|
|
20
21
|
export * from './lib/results-table/results-table.component'
|
package/src/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.html
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<gn-ui-inline-filter
|
|
2
|
+
[choices]="availableChoices"
|
|
3
|
+
[selected]="selected"
|
|
4
|
+
(selectValues)="onSelectedValues($event)"
|
|
5
|
+
>
|
|
6
|
+
<ng-template let-choice>
|
|
7
|
+
<gn-ui-kind-badge
|
|
8
|
+
[kind]="choice.value"
|
|
9
|
+
[contentTemplate]="customTemplate"
|
|
10
|
+
class="gn-ui-btn-outline rounded-md py-2 px-2 border-gray-400 cursor-pointer focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors bg-transparent hover:text-primary-darker focus:text-primary-darker active:text-primary-black"
|
|
11
|
+
[ngClass]="{
|
|
12
|
+
'!bg-primary-lightest hover:bg-primary-lightest':
|
|
13
|
+
isSelectedChoice(choice.value) || isAllChoice(choice.value),
|
|
14
|
+
}"
|
|
15
|
+
>
|
|
16
|
+
<ng-template #customTemplate>
|
|
17
|
+
{{ 'search.filters.recordKind.' + choice.value | translate
|
|
18
|
+
}}<span class="ml-1" *ngIf="isSelectedChoice(choice.value)"
|
|
19
|
+
>({{ choice.count }})</span
|
|
20
|
+
>
|
|
21
|
+
</ng-template>
|
|
22
|
+
</gn-ui-kind-badge>
|
|
23
|
+
</ng-template>
|
|
24
|
+
</gn-ui-inline-filter>
|
package/src/libs/ui/search/src/lib/results-hits-search-kind/results-hits-search-kind.component.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
EventEmitter,
|
|
4
|
+
Input,
|
|
5
|
+
OnChanges,
|
|
6
|
+
SimpleChanges,
|
|
7
|
+
Output,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
import { Choice } from '../../../../../../libs/ui/inputs/src'
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'gn-ui-results-hits-search-kind',
|
|
13
|
+
templateUrl: './results-hits-search-kind.component.html',
|
|
14
|
+
})
|
|
15
|
+
export class ResultsHitsSearchKindComponent implements OnChanges {
|
|
16
|
+
@Input() selected: string[] = []
|
|
17
|
+
@Input() choices: Choice[] = []
|
|
18
|
+
@Output() selectionChanged = new EventEmitter<string[]>()
|
|
19
|
+
|
|
20
|
+
availableChoices: Choice[] = []
|
|
21
|
+
|
|
22
|
+
ngOnChanges(changes: SimpleChanges) {
|
|
23
|
+
if (changes.choices && changes.choices.currentValue) {
|
|
24
|
+
this.availableChoices = this.buildFilterChoices(this.choices)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
buildFilterChoices(availableValues: Choice[]) {
|
|
29
|
+
return [
|
|
30
|
+
...[
|
|
31
|
+
{
|
|
32
|
+
label: 'all',
|
|
33
|
+
value: 'all',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
...availableValues,
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onSelectedValues(values: string[]) {
|
|
41
|
+
const selectedValues = values.includes('all') ? [] : values
|
|
42
|
+
|
|
43
|
+
this.selectionChanged.emit(selectedValues)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isSelectedChoice(choiceValue: string) {
|
|
47
|
+
return this.selected.includes(choiceValue)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
isAllChoice(choiceValue: string) {
|
|
51
|
+
return this.selected.length === 0 && choiceValue === 'all'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -11,6 +11,7 @@ import { RecordPreviewRowComponent } from './record-preview-row/record-preview-r
|
|
|
11
11
|
import { RecordPreviewTextComponent } from './record-preview-text/record-preview-text.component'
|
|
12
12
|
import { RecordPreviewTitleComponent } from './record-preview-title/record-preview-title.component'
|
|
13
13
|
import { ResultsHitsNumberComponent } from './results-hits-number/results-hits-number.component'
|
|
14
|
+
import { ResultsHitsSearchKindComponent } from './results-hits-search-kind/results-hits-search-kind.component'
|
|
14
15
|
import {
|
|
15
16
|
DEFAULT_RESULTS_LAYOUT_CONFIG,
|
|
16
17
|
RESULTS_LAYOUT_CONFIG,
|
|
@@ -24,6 +25,7 @@ import { UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
|
|
|
24
25
|
import {
|
|
25
26
|
MetadataQualityComponent,
|
|
26
27
|
UiElementsModule,
|
|
28
|
+
KindBadgeComponent,
|
|
27
29
|
} from '../../../../../libs/ui/elements/src'
|
|
28
30
|
import { RecordPreviewFeedComponent } from './record-preview-feed/record-preview-feed.component'
|
|
29
31
|
import { CommonModule } from '@angular/common'
|
|
@@ -48,6 +50,7 @@ import { matFace } from '@ng-icons/material-icons/baseline'
|
|
|
48
50
|
RecordMetricComponent,
|
|
49
51
|
ResultsListComponent,
|
|
50
52
|
ResultsHitsNumberComponent,
|
|
53
|
+
ResultsHitsSearchKindComponent,
|
|
51
54
|
ResultsListItemComponent,
|
|
52
55
|
RecordPreviewFeedComponent,
|
|
53
56
|
RecordPreviewRowComponent,
|
|
@@ -74,6 +77,7 @@ import { matFace } from '@ng-icons/material-icons/baseline'
|
|
|
74
77
|
matFace,
|
|
75
78
|
matHomeWorkOutline,
|
|
76
79
|
}),
|
|
80
|
+
KindBadgeComponent,
|
|
77
81
|
MetadataQualityComponent,
|
|
78
82
|
],
|
|
79
83
|
exports: [
|
|
@@ -86,6 +90,7 @@ import { matFace } from '@ng-icons/material-icons/baseline'
|
|
|
86
90
|
FacetsModule,
|
|
87
91
|
RecordPreviewComponent,
|
|
88
92
|
ResultsHitsNumberComponent,
|
|
93
|
+
ResultsHitsSearchKindComponent,
|
|
89
94
|
RecordPreviewFeedComponent,
|
|
90
95
|
RecordPreviewRowComponent,
|
|
91
96
|
],
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<ng-container *ngSwitchCase="'light'">
|
|
4
4
|
<div class="flex items-center relative">
|
|
5
5
|
<div
|
|
6
|
-
class="flex-shrink-0 {{ color.text }}
|
|
6
|
+
class="flex-shrink-0 {{ color.text }} font-medium mr-2
|
|
7
7
|
text-opacity-100 !text-slate-800"
|
|
8
8
|
data-cy="progressPercentage"
|
|
9
9
|
>
|
package/translations/de.json
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"datafeeder.month.september": "September",
|
|
52
52
|
"datafeeder.wizardSummarize.createdAt": "Erstellt am",
|
|
53
53
|
"datafeeder.wizardSummarize.scale": "Maßstab",
|
|
54
|
-
"datahub.header.datasets": "
|
|
54
|
+
"datahub.header.datasets": "Katalog",
|
|
55
55
|
"datahub.header.lastRecords": "Die neuesten",
|
|
56
56
|
"datahub.header.myfavorites": "Meine Favoriten",
|
|
57
57
|
"datahub.header.news": "Startseite",
|
|
@@ -467,6 +467,10 @@
|
|
|
467
467
|
"results.layout.selectOne": "Layout auswählen",
|
|
468
468
|
"results.records.hits.displayedOn": "{displayed, plural, =0{Kein Datensatz.} one{1 Datensatz} other{{displayed} Datensätze }} {hits, plural, other{angezeigt von {hits} insgesamt.}}",
|
|
469
469
|
"results.records.hits.empty.help.html": "Vorschläge: <ul class='list-disc list-inside'><li>Versuchen Sie es mit anderen Worten</li><li>Beschränken Sie die Suchwörter</li></ul>",
|
|
470
|
+
"search.filters.recordKind.all": "Alle",
|
|
471
|
+
"search.filters.recordKind.dataset": "Datensätze",
|
|
472
|
+
"search.filters.recordKind.reuse": "Wiederverwendungen",
|
|
473
|
+
"search.filters.recordKind.service": "Dienste",
|
|
470
474
|
"results.records.hits.found": "{hits, plural, =0{Keine Dokumente entsprechen der angegebenen Suche.} one{1 Datensatz gefunden.} other{{hits} Datensätze gefunden.}}",
|
|
471
475
|
"results.records.hits.selected": "{ amount } ausgewählt",
|
|
472
476
|
"results.showMore": "Mehr Ergebnisse anzeigen...",
|
package/translations/en.json
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"datafeeder.month.september": "September",
|
|
52
52
|
"datafeeder.wizardSummarize.createdAt": "Created at",
|
|
53
53
|
"datafeeder.wizardSummarize.scale": "Scale",
|
|
54
|
-
"datahub.header.datasets": "
|
|
54
|
+
"datahub.header.datasets": "Catalog",
|
|
55
55
|
"datahub.header.lastRecords": "The latest",
|
|
56
56
|
"datahub.header.myfavorites": "My favorites",
|
|
57
57
|
"datahub.header.news": "Home",
|
|
@@ -467,6 +467,10 @@
|
|
|
467
467
|
"results.layout.selectOne": "Results layout",
|
|
468
468
|
"results.records.hits.displayedOn": "{displayed, plural, =0{No dataset.} one{1 } other{{displayed} }} {hits, plural, other{displayed on {hits} total.}}",
|
|
469
469
|
"results.records.hits.empty.help.html": "Suggestions: <ul class='list-disc list-inside'><li>Try other words</li><li>Specify fewer words</li></ul>",
|
|
470
|
+
"search.filters.recordKind.all": "All",
|
|
471
|
+
"search.filters.recordKind.dataset": "Datasets",
|
|
472
|
+
"search.filters.recordKind.reuse": "Reuses",
|
|
473
|
+
"search.filters.recordKind.service": "Services",
|
|
470
474
|
"results.records.hits.found": "{hits, plural, =0{No datasets match the specified search.} one{1 dataset found.} other{{hits} datasets found.}}",
|
|
471
475
|
"results.records.hits.selected": "{ amount } selected",
|
|
472
476
|
"results.showMore": "Show more results...",
|
package/translations/es.json
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"datafeeder.month.september": "",
|
|
52
52
|
"datafeeder.wizardSummarize.createdAt": "",
|
|
53
53
|
"datafeeder.wizardSummarize.scale": "",
|
|
54
|
-
"datahub.header.datasets": "",
|
|
54
|
+
"datahub.header.datasets": "Catálogo",
|
|
55
55
|
"datahub.header.lastRecords": "",
|
|
56
56
|
"datahub.header.myfavorites": "",
|
|
57
57
|
"datahub.header.news": "",
|
|
@@ -467,6 +467,10 @@
|
|
|
467
467
|
"results.layout.selectOne": "",
|
|
468
468
|
"results.records.hits.displayedOn": "",
|
|
469
469
|
"results.records.hits.empty.help.html": "",
|
|
470
|
+
"search.filters.recordKind.all": "Todos",
|
|
471
|
+
"search.filters.recordKind.dataset": "",
|
|
472
|
+
"search.filters.recordKind.reuse": "",
|
|
473
|
+
"search.filters.recordKind.service": "",
|
|
470
474
|
"results.records.hits.found": "",
|
|
471
475
|
"results.records.hits.selected": "",
|
|
472
476
|
"results.showMore": "",
|