diff --git a/rero_ils/config.py b/rero_ils/config.py
index c87099e2e9..2f2b2db7d9 100644
--- a/rero_ils/config.py
+++ b/rero_ils/config.py
@@ -52,6 +52,7 @@
from rero_ils.modules.api import IlsRecordIndexer
from rero_ils.modules.loans.api import Loan
+from rero_ils.utils import get_agg_config
from .modules.circ_policies.api import CircPolicy
from .modules.documents.api import Document
@@ -703,33 +704,80 @@ def _(x):
'status',
],
'expand': ['document_type'],
+ 'initialBucketSize': 5
},
'ptrn': {
'order': [
'roles'
],
- 'expand': ['roles']
+ 'expand': ['roles'],
+ 'initialBucketSize': 5
},
'pers': {
'order': [
'sources'
],
- 'expand': ['sources']
+ 'expand': ['sources'],
+ 'initialBucketSize': 5
},
}
+# Default number of results in facet
+RERO_ILS_DEFAULT_AGGREGATION_SIZE = 50
+
+# Number of aggregation by index name
+RERO_ILS_AGGREGATION_SIZE = {
+ 'documents': 50
+}
+
RECORDS_REST_FACETS = {
'documents': dict(
aggs=dict(
- document_type=dict(terms=dict(field='type')),
- library=dict(terms=dict(field='items.library_pid')),
- author__en=dict(terms=dict(field='facet_authors_en')),
- author__fr=dict(terms=dict(field='facet_authors_fr')),
- author__de=dict(terms=dict(field='facet_authors_de')),
- author__it=dict(terms=dict(field='facet_authors_it')),
- language=dict(terms=dict(field='languages.language')),
- subject=dict(terms=dict(field='facet_subjects')),
- status=dict(terms=dict(field='items.status'))
+ document_type=partial(
+ get_agg_config,
+ index_name='documents',
+ field='type'
+ ),
+ library=partial(
+ get_agg_config,
+ index_name='documents',
+ field='items.library_pid'
+ ),
+ author__en=partial(
+ get_agg_config,
+ index_name='documents',
+ field='facet_authors_en'
+ ),
+ author__fr=partial(
+ get_agg_config,
+ index_name='documents',
+ field='facet_authors_fr'
+ ),
+ author__de=partial(
+ get_agg_config,
+ index_name='documents',
+ field='facet_authors_de'
+ ),
+ author__it=partial(
+ get_agg_config,
+ index_name='documents',
+ field='facet_authors_it'
+ ),
+ language=partial(
+ get_agg_config,
+ index_name='documents',
+ field='languages.language'
+ ),
+ subject=partial(
+ get_agg_config,
+ index_name='documents',
+ field='facet_subjects'
+ ),
+ status=partial(
+ get_agg_config,
+ index_name='items.status',
+ field='items.status'
+ )
),
filters={
_('document_type'): terms_filter('type'),
diff --git a/rero_ils/utils.py b/rero_ils/utils.py
index b5ff294b5d..f206767df5 100644
--- a/rero_ils/utils.py
+++ b/rero_ils/utils.py
@@ -65,3 +65,25 @@ def send_mail(subject, recipients, template, language, **context):
def unique_list(data):
"""Unicity of list."""
return list(dict.fromkeys(data))
+
+
+def get_agg_config(index_name, field):
+ """Get Elasticsearch aggregation term configuration.
+
+ This function allows to configure aggregation size per index name using
+ environnement variables.
+
+ :param index_name: name of Elasticsearch index
+ :param field: field name for the aggregation
+ :return: dict of Elasticsearch DSL aggregation configuration
+ """
+ from flask import current_app
+ return dict(terms=dict(
+ field=field,
+ size=current_app.config.get(
+ 'RERO_ILS_AGGREGATION_SIZE', {}
+ ).get(
+ index_name,
+ current_app.config.get('RERO_ILS_DEFAULT_AGGREGATION_SIZE')
+ )
+ ))
diff --git a/ui/src/app/records/records.module.ts b/ui/src/app/records/records.module.ts
index 5b5fb42ddf..9e782f2911 100644
--- a/ui/src/app/records/records.module.ts
+++ b/ui/src/app/records/records.module.ts
@@ -48,6 +48,7 @@ import { PersonsSearchComponent } from './search/public-search/persons-search.co
import { RefAuthorityComponent } from './editor/ref-authority/ref-authority.component';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { RolesCheckboxesComponent } from './editor/roles-checkboxes/roles-checkboxes.component';
+import { AggregationComponent } from './search/aggregation/aggregation.component';
@NgModule({
declarations: [
@@ -79,7 +80,8 @@ import { RolesCheckboxesComponent } from './editor/roles-checkboxes/roles-checkb
DocumentsSearchComponent,
PersonsSearchComponent,
RefAuthorityComponent,
- RolesCheckboxesComponent
+ RolesCheckboxesComponent,
+ AggregationComponent
],
imports: [
CommonModule,
diff --git a/ui/src/app/records/search/aggregation/aggregation.component.html b/ui/src/app/records/search/aggregation/aggregation.component.html
new file mode 100644
index 0000000000..6ebe0c42ff
--- /dev/null
+++ b/ui/src/app/records/search/aggregation/aggregation.component.html
@@ -0,0 +1,34 @@
+
diff --git a/ui/src/app/records/search/aggregation/aggregation.component.scss b/ui/src/app/records/search/aggregation/aggregation.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/src/app/records/search/aggregation/aggregation.component.spec.ts b/ui/src/app/records/search/aggregation/aggregation.component.spec.ts
new file mode 100644
index 0000000000..6e21f7d425
--- /dev/null
+++ b/ui/src/app/records/search/aggregation/aggregation.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AggregationComponent } from './aggregation.component';
+
+describe('AggregationComponent', () => {
+ let component: AggregationComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ AggregationComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AggregationComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ui/src/app/records/search/aggregation/aggregation.component.ts b/ui/src/app/records/search/aggregation/aggregation.component.ts
new file mode 100644
index 0000000000..d0ddfa45dc
--- /dev/null
+++ b/ui/src/app/records/search/aggregation/aggregation.component.ts
@@ -0,0 +1,61 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+
+@Component({
+ selector: 'app-aggregation',
+ templateUrl: './aggregation.component.html',
+ styleUrls: ['./aggregation.component.scss']
+})
+export class AggregationComponent {
+
+ @Input() aggFilters = null;
+ @Input() aggsSettings = null;
+ @Input() aggregation = null;
+
+ @Output() addAggFilter = new EventEmitter<{term: string, value: string}>();
+ @Output() removeAggFilter = new EventEmitter<{term: string, value: string}>();
+
+ private moreMode = true;
+
+ isFiltered(term: any, value?: any) {
+ if (value) {
+ const filterValue = `${term}=${value}`;
+ return this.aggFilters.some((val: any) => filterValue === val);
+ } else {
+ return this.aggFilters.some((val: any) => term === val.split('=')[0]);
+ }
+ }
+
+ aggFilter(term: string, value: string) {
+ if (this.isFiltered(term, value)) {
+ this.removeAggFilter.emit({term: term, value: value});
+ } else {
+ this.addAggFilter.emit({term: term, value: value});
+ }
+ }
+
+ isOpen(title: string) {
+ if (this.isFiltered(title)) {
+ return true;
+ }
+ if (this.aggsSettings.expand.some((value: any) => value === title)) {
+ return true;
+ }
+ return false;
+ }
+
+ sizeOfBucket() {
+ if (this.moreMode) {
+ return this.aggsSettings.initialBucketSize;
+ } else {
+ return this.aggregation.buckets.length;
+ }
+ }
+
+ displayMoreAndLessLink() {
+ return this.aggregation.buckets.length > this.aggsSettings.initialBucketSize;
+ }
+
+ setMoreMode(state: boolean) {
+ this.moreMode = state;
+ }
+}
diff --git a/ui/src/app/records/search/search.component.html b/ui/src/app/records/search/search.component.html
index 0fbb0bdde4..b37efe5a92 100644
--- a/ui/src/app/records/search/search.component.html
+++ b/ui/src/app/records/search/search.component.html
@@ -28,22 +28,13 @@
diff --git a/ui/src/app/records/search/search.component.ts b/ui/src/app/records/search/search.component.ts
index cf6a960506..4bd3daa5f9 100644
--- a/ui/src/app/records/search/search.component.ts
+++ b/ui/src/app/records/search/search.component.ts
@@ -125,6 +125,7 @@ export class SearchComponent implements OnInit {
public language = null;
public permissions = null;
onInitDone = false;
+
constructor(
protected recordsService: RecordsService,
protected route: ActivatedRoute,
@@ -251,35 +252,6 @@ export class SearchComponent implements OnInit {
});
}
- aggFilter(term, value) {
- const filterValue = `${term}=${value}`;
- if (this.isFiltered(term, value)) {
- this.aggFilters = this.aggFilters.filter(val => val !== filterValue);
- } else {
- this.aggFilters.push(filterValue);
- }
- this.updateRoute();
- }
-
- isFiltered(term, value?) {
- if (value) {
- const filterValue = `${term}=${value}`;
- return this.aggFilters.some(val => filterValue === val);
- } else {
- return this.aggFilters.some(val => term === val.split('=')[0]);
- }
- }
-
- startOpen(title: string) {
- if (this.isFiltered(title)) {
- return true;
- }
- if (this.aggsSettings.expand.some(value => value === title)) {
- return true;
- }
- return false;
- }
-
hasPermissionToCreate() {
if (this.permissions
&& this.permissions.cannot_create
@@ -288,4 +260,20 @@ export class SearchComponent implements OnInit {
}
return true;
}
+
+ removeAggFilter(event: any) {
+ this.aggFilters = this.aggFilters.filter(
+ val => val !== this.formatFilterValue(event)
+ );
+ this.updateRoute();
+ }
+
+ addAggFilter(event: any) {
+ this.aggFilters.push(this.formatFilterValue(event));
+ this.updateRoute();
+ }
+
+ formatFilterValue(object: {term: string, value: string}) {
+ return `${object.term}=${object.value}`;
+ }
}
diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json
index 7bf5c95c17..13120a560c 100644
--- a/ui/src/assets/i18n/de.json
+++ b/ui/src/assets/i18n/de.json
@@ -243,5 +243,7 @@
"Documents": "Documents",
"Persons": "Persons",
"results": "Resultate",
- "No result found.": "Keine Resultate gefunden"
-}
\ No newline at end of file
+ "No result found.": "Keine Resultate gefunden",
+ "more…": "Weiteres…",
+ "less…": "Weniger…"
+}
diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json
index 97d1820b45..002583ec14 100644
--- a/ui/src/assets/i18n/en.json
+++ b/ui/src/assets/i18n/en.json
@@ -46,18 +46,18 @@
"readingRoom": "readingRoom",
"readingroom": "readingroom",
"publicaccess": "publicaccess",
- "fre": "fre",
- "eng": "eng",
- "ger": "ger",
- "ita": "ita",
- "lat": "lat",
- "spa": "spa",
- "ara": "ara",
- "por": "por",
- "rus": "rus",
- "heb": "heb",
- "jpn": "jpn",
- "chi": "chi",
+ "fre": "French",
+ "eng": "English",
+ "ger": "German",
+ "ita": "Italian",
+ "lat": "Latin",
+ "spa": "Spanish",
+ "ara": "Arabic",
+ "por": "Portuguese",
+ "rus": "Russian",
+ "heb": "Hebrew",
+ "jpn": "Japanese",
+ "chi": "Chinese",
"und": "Undefined",
"patron": "patron",
"librarian": "librarian",
diff --git a/ui/src/assets/i18n/en_US.json b/ui/src/assets/i18n/en_US.json
index 681660ff9f..6096ba8ba9 100644
--- a/ui/src/assets/i18n/en_US.json
+++ b/ui/src/assets/i18n/en_US.json
@@ -46,19 +46,19 @@
"readingRoom": "readingRoom",
"readingroom": "readingroom",
"publicaccess": "publicaccess",
- "fre": "fre",
- "eng": "eng",
- "ger": "ger",
- "ita": "ita",
- "lat": "lat",
- "spa": "spa",
- "ara": "ara",
- "por": "por",
- "rus": "rus",
- "heb": "heb",
- "jpn": "jpn",
- "chi": "chi",
- "und": "und",
+ "fre": "French",
+ "eng": "English",
+ "ger": "German",
+ "ita": "Italian",
+ "lat": "Latin",
+ "spa": "Spanish",
+ "ara": "Arabic",
+ "por": "Portuguese",
+ "rus": "Russian",
+ "heb": "Hebrew",
+ "jpn": "Japanese",
+ "chi": "Chinese",
+ "und": "Undefined",
"patron": "patron",
"librarian": "librarian",
"system_librarian": "system librarian",
@@ -243,5 +243,7 @@
"Documents": "Documents",
"Persons": "Persons",
"results": "results",
- "No result found.": "No result found."
-}
\ No newline at end of file
+ "No result found.": "No result found.",
+ "more…": "more…",
+ "less…": "less…"
+}
diff --git a/ui/src/assets/i18n/fr.json b/ui/src/assets/i18n/fr.json
index 63f371e6c2..978f86d708 100644
--- a/ui/src/assets/i18n/fr.json
+++ b/ui/src/assets/i18n/fr.json
@@ -243,5 +243,7 @@
"Documents": "Documents",
"Persons": "Personnes",
"results": "résultats",
- "No result found.": "Aucun résultat n'a été trouvé."
-}
\ No newline at end of file
+ "No result found.": "Aucun résultat n'a été trouvé.",
+ "more…": "plus…",
+ "less…": "moins…"
+}
diff --git a/ui/src/assets/i18n/it.json b/ui/src/assets/i18n/it.json
index e01f1d4d2b..9962312c53 100644
--- a/ui/src/assets/i18n/it.json
+++ b/ui/src/assets/i18n/it.json
@@ -243,5 +243,7 @@
"Documents": "Documenti",
"Persons": "Persons",
"results": "risultati",
- "No result found.": "Nessun risultato trovato."
-}
\ No newline at end of file
+ "No result found.": "Nessun risultato trovato.",
+ "more…": "di più…",
+ "less…": "di meno…"
+}