Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Maintenance - Mise à jour mensuelle Lundi 6 Février entre 7h00 et 9h00
Open sidebar
urgi-is
data-discovery
Commits
8e1d8d70
Commit
8e1d8d70
authored
Jul 30, 2018
by
Exbrayat Cédric
Browse files
feat: aggregation ui
parent
af4db7e9
Changes
19
Hide whitespace changes
Inline
Side-by-side
frontend/src/app/aggregation/aggregation.component.html
0 → 100644
View file @
8e1d8d70
<div
class=
"card mb-1"
*ngIf=
"aggregation.buckets.length"
>
<div
class=
"card-body"
>
<!-- title -->
<h3
class=
"card-title"
>
{{ aggregation.name }}
</h3>
<!-- values -->
<form
[formGroup]=
"aggregationForm"
>
<div
class=
"card-text"
*ngFor=
"let bucket of aggregation.buckets"
>
<div
class=
"form-check"
>
<input
class=
"form-check-input"
type=
"checkbox"
[id]=
"aggregation.name + bucket.key"
[formControlName]=
"bucket.key"
>
<label
class=
"form-check-label"
[for]=
"aggregation.name + bucket.key"
>
{{ bucket.key }} [{{ bucket.documentCount | number }}]
</label>
</div>
</div>
</form>
</div>
</div>
frontend/src/app/aggregation/aggregation.component.scss
0 → 100644
View file @
8e1d8d70
.card-title
{
font-size
:
1
.25rem
;
}
frontend/src/app/aggregation/aggregation.component.spec.ts
0 → 100644
View file @
8e1d8d70
import
{
fakeAsync
,
TestBed
,
tick
}
from
'
@angular/core/testing
'
;
import
{
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
ComponentTester
,
speculoosMatchers
}
from
'
ngx-speculoos
'
;
import
{
AggregationComponent
}
from
'
./aggregation.component
'
;
import
{
toAggregation
}
from
'
../models/test-model-generators
'
;
import
{
AggregationCriterion
}
from
'
../models/aggregation-criterion
'
;
describe
(
'
AggregationsComponent
'
,
()
=>
{
const
aggregation
=
toAggregation
(
'
coo
'
,
[
'
France
'
,
'
Italy
'
,
'
New Zealand
'
]);
class
AggregationComponentTester
extends
ComponentTester
<
AggregationComponent
>
{
constructor
()
{
super
(
AggregationComponent
);
}
get
title
()
{
return
this
.
element
(
'
.card-title
'
);
}
get
labels
()
{
return
this
.
elements
(
'
label
'
);
}
get
firstCheckbox
()
{
return
this
.
input
(
'
input
'
);
}
}
beforeEach
(()
=>
TestBed
.
configureTestingModule
({
imports
:
[
ReactiveFormsModule
],
declarations
:
[
AggregationComponent
]
}));
beforeEach
(()
=>
jasmine
.
addMatchers
(
speculoosMatchers
));
it
(
'
should display an aggregation with buckets
'
,
()
=>
{
const
tester
=
new
AggregationComponentTester
();
// given an aggregation
tester
.
componentInstance
.
aggregation
=
aggregation
;
tester
.
detectChanges
();
// then it should display a title
expect
(
tester
.
title
).
toHaveText
(
'
coo
'
);
// and the buckets with their name and count
expect
(
tester
.
labels
.
length
).
toBe
(
3
);
expect
(
tester
.
labels
[
0
]).
toHaveText
(
'
France [10]
'
);
expect
(
tester
.
labels
[
1
]).
toHaveText
(
'
Italy [20]
'
);
expect
(
tester
.
labels
[
2
]).
toHaveText
(
'
New Zealand [30]
'
);
});
it
(
'
should not display an aggregation with empty buckets
'
,
()
=>
{
const
tester
=
new
AggregationComponentTester
();
// given an aggregation
tester
.
componentInstance
.
aggregation
=
toAggregation
(
'
coo
'
,
[]);
tester
.
detectChanges
();
// then it should not display a title
expect
(
tester
.
title
).
toBeNull
();
// and the buckets should not be displayed either
expect
(
tester
.
labels
.
length
).
toBe
(
0
);
});
it
(
'
should extract keys from selected values
'
,
()
=>
{
// given a few selected values among a bucket
const
values
:
{
[
key
:
string
]:
boolean
|
null
}
=
{
'
France
'
:
true
,
'
England
'
:
false
,
'
Italy
'
:
true
,
'
New Zealand
'
:
null
};
// when extracting keys
const
keys
=
AggregationComponent
.
extractKeys
(
values
);
// then it should return only the truthy ones
expect
(
keys
).
toEqual
([
'
France
'
,
'
Italy
'
]);
});
it
(
'
should build a form based on the bucket
'
,
()
=>
{
// given an aggregation with a bucket
const
component
=
new
AggregationComponent
();
component
.
aggregation
=
aggregation
;
// when initializing the component
component
.
ngOnInit
();
// then it should have a form with several fields
const
controls
=
component
.
aggregationForm
.
controls
;
expect
(
Object
.
keys
(
controls
)).
toEqual
([
'
France
'
,
'
Italy
'
,
'
New Zealand
'
]);
});
it
(
'
should build a form and check selected criteria
'
,
()
=>
{
// given an aggregation with a bucket and a selected value
const
selectedKeys
=
[
'
France
'
];
const
component
=
new
AggregationComponent
();
component
.
aggregation
=
aggregation
;
component
.
selectedKeys
=
selectedKeys
;
// when initializing the component
component
.
ngOnInit
();
// then it should have a form with several fields
const
controls
=
component
.
aggregationForm
.
controls
;
expect
(
Object
.
keys
(
controls
)).
toEqual
([
'
France
'
,
'
Italy
'
,
'
New Zealand
'
]);
// and France should be checked
expect
(
component
.
aggregationForm
.
get
(
'
France
'
).
value
).
toBeTruthy
();
});
it
(
'
should build a form and disable the unique criteria
'
,
()
=>
{
// given an aggregation with a bucket and a unique value
const
component
=
new
AggregationComponent
();
component
.
aggregation
=
toAggregation
(
'
coo
'
,
[
'
France
'
]);
// when initializing the component
component
.
ngOnInit
();
// then it should have a form with one disabled field
const
controls
=
component
.
aggregationForm
.
controls
;
expect
(
Object
.
keys
(
controls
)).
toEqual
([
'
France
'
]);
// and France should be disabled
expect
(
component
.
aggregationForm
.
get
(
'
France
'
).
disable
).
toBeTruthy
();
});
it
(
'
should emit an event when a checkbox is toggled
'
,
fakeAsync
(()
=>
{
const
tester
=
new
AggregationComponentTester
();
// given an aggregation
const
component
=
tester
.
componentInstance
;
component
.
aggregation
=
aggregation
;
tester
.
detectChanges
();
expect
(
tester
.
firstCheckbox
).
not
.
toBeChecked
();
// then it should emit an event
let
emittedEvent
:
AggregationCriterion
;
component
.
aggregationChange
.
subscribe
((
event
:
AggregationCriterion
)
=>
emittedEvent
=
event
);
// when a value is checked
tester
.
firstCheckbox
.
check
();
tester
.
detectChanges
();
tick
();
expect
(
tester
.
firstCheckbox
).
toBeChecked
();
expect
(
emittedEvent
.
name
).
toBe
(
'
coo
'
);
expect
(
emittedEvent
.
values
).
toEqual
([
'
France
'
]);
}));
});
frontend/src/app/aggregation/aggregation.component.ts
0 → 100644
View file @
8e1d8d70
import
{
ChangeDetectionStrategy
,
Component
,
EventEmitter
,
Input
,
OnInit
,
Output
}
from
'
@angular/core
'
;
import
{
FormControl
,
FormGroup
}
from
'
@angular/forms
'
;
import
{
Aggregation
}
from
'
../models/page
'
;
import
{
AggregationCriterion
}
from
'
../models/aggregation-criterion
'
;
@
Component
({
selector
:
'
rare-aggregation
'
,
templateUrl
:
'
./aggregation.component.html
'
,
styleUrls
:
[
'
./aggregation.component.scss
'
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
})
export
class
AggregationComponent
implements
OnInit
{
@
Input
()
aggregation
:
Aggregation
;
@
Input
()
selectedKeys
:
Array
<
string
>
=
[];
// the component emits an event if the user adds or remove a criterion
@
Output
()
aggregationChange
=
new
EventEmitter
<
AggregationCriterion
>
();
aggregationForm
:
FormGroup
=
new
FormGroup
({});
/**
* This extracts the keys with a truthy value from an object.
* For example,
* { France: true, England: false, 'New Zealand': null }
* returns
* [ 'France' ]
*/
static
extractKeys
(
formValues
:
{
[
key
:
string
]:
boolean
|
null
})
{
return
Object
.
entries
<
boolean
>
(
formValues
)
.
filter
(([
key
,
value
])
=>
value
)
.
map
(([
key
])
=>
key
);
}
ngOnInit
():
void
{
// create as many form control as there are buckets
const
buckets
=
this
.
aggregation
.
buckets
;
buckets
.
map
(
bucket
=>
{
const
control
=
new
FormControl
(
false
);
// if the criteria is selected, set the field to true
if
(
this
.
selectedKeys
.
includes
(
bucket
.
key
))
{
control
.
setValue
(
true
);
}
this
.
aggregationForm
.
addControl
(
bucket
.
key
,
control
);
});
// disable if only one bucket
if
(
buckets
.
length
===
1
)
{
this
.
aggregationForm
.
disable
();
}
// subscribe to form changes
// to emit a new event every time a value changes
this
.
aggregationForm
.
valueChanges
.
subscribe
(
formValues
=>
{
const
values
=
AggregationComponent
.
extractKeys
(
formValues
);
const
event
:
AggregationCriterion
=
{
name
:
this
.
aggregation
.
name
,
values
};
this
.
aggregationChange
.
emit
(
event
);
});
}
}
frontend/src/app/aggregations/aggregations.component.html
0 → 100644
View file @
8e1d8d70
<div
*ngIf=
"aggregations?.length"
>
<div
*ngFor=
"let aggregation of aggregations"
>
<rare-aggregation
[aggregation]=
"aggregation"
[selectedKeys]=
"selectedKeysForAggregation(aggregation.name)"
(aggregationChange)=
"onAggregationChange($event)"
></rare-aggregation>
</div>
</div>
frontend/src/app/aggregations/aggregations.component.scss
0 → 100644
View file @
8e1d8d70
frontend/src/app/aggregations/aggregations.component.spec.ts
0 → 100644
View file @
8e1d8d70
import
{
fakeAsync
,
TestBed
,
tick
}
from
'
@angular/core/testing
'
;
import
{
By
}
from
'
@angular/platform-browser
'
;
import
{
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
ComponentTester
}
from
'
ngx-speculoos
'
;
import
{
AggregationsComponent
}
from
'
./aggregations.component
'
;
import
{
AggregationComponent
}
from
'
../aggregation/aggregation.component
'
;
import
{
toAggregation
}
from
'
../models/test-model-generators
'
;
import
{
AggregationCriterion
}
from
'
../models/aggregation-criterion
'
;
describe
(
'
AggregationsComponent
'
,
()
=>
{
class
AggregationsComponentTester
extends
ComponentTester
<
AggregationsComponent
>
{
constructor
()
{
super
(
AggregationsComponent
);
}
get
aggregations
()
{
return
this
.
debugElement
.
queryAll
(
By
.
directive
(
AggregationComponent
));
}
}
beforeEach
(()
=>
TestBed
.
configureTestingModule
({
imports
:
[
ReactiveFormsModule
],
declarations
:
[
AggregationsComponent
,
AggregationComponent
]
}));
it
(
'
should display no aggregations if null
'
,
()
=>
{
const
tester
=
new
AggregationsComponentTester
();
// given no aggregations
tester
.
detectChanges
();
// then it should display no aggregations
expect
(
tester
.
aggregations
.
length
).
toBe
(
0
);
});
it
(
'
should display no aggregations if empty
'
,
()
=>
{
const
tester
=
new
AggregationsComponentTester
();
const
component
=
tester
.
componentInstance
;
// given no aggregations
component
.
aggregations
=
[];
tester
.
detectChanges
();
// then it should display no aggregations
expect
(
tester
.
aggregations
.
length
).
toBe
(
0
);
});
it
(
'
should extract the selected criteria for the aggregation
'
,
()
=>
{
const
component
=
new
AggregationsComponent
();
component
.
selectedCriteria
=
[{
name
:
'
coo
'
,
values
:
[
'
France
'
,
'
Italy
'
]
},
{
name
:
'
domain
'
,
values
:
[
'
Plant
'
]
}];
const
cooCriteria
=
component
.
selectedKeysForAggregation
(
'
coo
'
);
expect
(
cooCriteria
).
toEqual
([
'
France
'
,
'
Italy
'
]);
const
domainCriteria
=
component
.
selectedKeysForAggregation
(
'
domain
'
);
expect
(
domainCriteria
).
toEqual
([
'
Plant
'
]);
const
unknownCriteria
=
component
.
selectedKeysForAggregation
(
'
unknown
'
);
expect
(
unknownCriteria
).
toEqual
([]);
});
it
(
'
should display aggregations if there are some
'
,
()
=>
{
const
tester
=
new
AggregationsComponentTester
();
const
component
=
tester
.
componentInstance
;
// given a few aggregations
const
domain
=
toAggregation
(
'
domain
'
,
[
'
Plant
'
]);
const
coo
=
toAggregation
(
'
coo
'
,
[
'
France
'
,
'
Italy
'
]);
component
.
aggregations
=
[
domain
,
coo
];
component
.
selectedCriteria
=
[{
name
:
'
coo
'
,
values
:
[
'
France
'
]
}];
tester
.
detectChanges
();
// then it should display each aggregation
expect
(
tester
.
aggregations
.
length
).
toBe
(
2
);
const
aggregation1
=
tester
.
aggregations
[
0
].
componentInstance
as
AggregationComponent
;
expect
(
aggregation1
.
aggregation
).
toBe
(
domain
);
expect
(
aggregation1
.
selectedKeys
).
toEqual
([]);
const
aggregation2
=
tester
.
aggregations
[
1
].
componentInstance
as
AggregationComponent
;
expect
(
aggregation2
.
aggregation
).
toBe
(
coo
);
expect
(
aggregation2
.
selectedKeys
).
toEqual
([
'
France
'
]);
});
it
(
'
should update criteria when a criterion changes
'
,
()
=>
{
const
tester
=
new
AggregationsComponentTester
();
const
component
=
tester
.
componentInstance
;
// given a few aggregations
const
domain
=
toAggregation
(
'
domain
'
,
[
'
Plant
'
]);
const
coo
=
toAggregation
(
'
coo
'
,
[
'
France
'
,
'
Italy
'
]);
component
.
aggregations
=
[
domain
,
coo
];
component
.
selectedCriteria
=
[{
name
:
'
coo
'
,
values
:
[
'
France
'
]
}];
tester
.
detectChanges
();
// when the aggregation emits an event
const
aggregationComponent
=
tester
.
aggregations
[
0
].
componentInstance
as
AggregationComponent
;
const
criteria
=
{
name
:
'
coo
'
,
values
:
[
'
France
'
]
};
aggregationComponent
.
aggregationChange
.
emit
(
criteria
);
// then it should add a criteria
expect
(
component
.
selectedCriteria
.
length
).
toBe
(
1
);
expect
(
component
.
selectedCriteria
[
0
]).
toBe
(
criteria
);
// when the aggregation emits an event with another value
const
updatedCriteria
=
{
name
:
'
coo
'
,
values
:
[
'
France
'
,
'
Italy
'
]
};
aggregationComponent
.
aggregationChange
.
emit
(
updatedCriteria
);
// then it should update the existing criteria
expect
(
component
.
selectedCriteria
.
length
).
toBe
(
1
);
expect
(
component
.
selectedCriteria
[
0
]).
toBe
(
updatedCriteria
);
// when the aggregation emits an event with no values
const
emptyCriteria
=
{
name
:
'
coo
'
,
values
:
[]
as
Array
<
string
>
};
aggregationComponent
.
aggregationChange
.
emit
(
emptyCriteria
);
// then it should delete the criteria
expect
(
component
.
selectedCriteria
.
length
).
toBe
(
0
);
});
it
(
'
should emit all criteria when an aggregation emits a change
'
,
fakeAsync
(()
=>
{
const
tester
=
new
AggregationsComponentTester
();
// given an aggregation
const
component
=
tester
.
componentInstance
;
const
domain
=
toAggregation
(
'
domain
'
,
[
'
Plant
'
]);
const
coo
=
toAggregation
(
'
coo
'
,
[
'
France
'
,
'
Italy
'
]);
component
.
aggregations
=
[
domain
,
coo
];
// and two selected criteria
component
.
selectedCriteria
=
[
{
name
:
'
domain
'
,
values
:
[
'
Plant
'
]
},
{
name
:
'
coo
'
,
values
:
[
'
Italy
'
]
}
];
tester
.
detectChanges
();
// then it should emit an event
let
emittedEvent
:
Array
<
AggregationCriterion
>
=
[];
component
.
aggregationsChange
.
subscribe
((
event
:
Array
<
AggregationCriterion
>
)
=>
emittedEvent
=
event
);
// when an event is emitted by an aggregation
const
aggregationComponent
=
tester
.
aggregations
[
0
].
componentInstance
as
AggregationComponent
;
aggregationComponent
.
aggregationChange
.
emit
({
name
:
'
coo
'
,
values
:
[
'
France
'
]
});
tester
.
detectChanges
();
tick
();
expect
(
emittedEvent
.
length
).
toBe
(
2
);
expect
(
emittedEvent
[
0
].
name
).
toBe
(
'
domain
'
);
expect
(
emittedEvent
[
0
].
values
).
toEqual
([
'
Plant
'
]);
expect
(
emittedEvent
[
1
].
name
).
toBe
(
'
coo
'
);
expect
(
emittedEvent
[
1
].
values
).
toEqual
([
'
France
'
]);
}));
});
frontend/src/app/aggregations/aggregations.component.ts
0 → 100644
View file @
8e1d8d70
import
{
ChangeDetectionStrategy
,
Component
,
EventEmitter
,
Input
,
Output
}
from
'
@angular/core
'
;
import
{
Aggregation
}
from
'
../models/page
'
;
import
{
AggregationCriterion
}
from
'
../models/aggregation-criterion
'
;
@
Component
({
selector
:
'
rare-aggregations
'
,
templateUrl
:
'
./aggregations.component.html
'
,
styleUrls
:
[
'
./aggregations.component.scss
'
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
})
export
class
AggregationsComponent
{
@
Input
()
aggregations
:
Array
<
Aggregation
>
=
[];
@
Input
()
selectedCriteria
:
Array
<
AggregationCriterion
>
=
[];
@
Output
()
aggregationsChange
=
new
EventEmitter
<
Array
<
AggregationCriterion
>>
();
/**
* Extracts the selected criteria for the aggregation.
* For example, returns [ 'France' ] for 'coo'
* if selectedCriteria is [{ name: 'coo', values: [ 'France' ] }]
* Returns an empty array if there are no values for this criteria
*/
selectedKeysForAggregation
(
name
:
string
):
Array
<
string
>
{
if
(
this
.
selectedCriteria
.
length
)
{
const
matchingCriteria
=
this
.
selectedCriteria
.
find
(
criteria
=>
criteria
.
name
===
name
);
if
(
matchingCriteria
)
{
return
matchingCriteria
.
values
;
}
}
return
[];
}
/**
* Finds the old criterion if it exists and replaces it with the new one received,
* removes it if the values are empty,
* or adds it to the criteria if it doesn't exist,
* then emits the updated criteria.
*/
onAggregationChange
(
criterionChanged
:
AggregationCriterion
):
void
{
const
index
=
this
.
selectedCriteria
.
findIndex
(
criterion
=>
criterion
.
name
===
criterionChanged
.
name
);
// if it already exists in the criteria
if
(
index
!==
-
1
)
{
// and the new criterion has values
if
(
criterionChanged
.
values
&&
criterionChanged
.
values
.
length
)
{
// replace the old one with the new one
this
.
selectedCriteria
[
index
]
=
criterionChanged
;
}
else
{
// else remove it
this
.
selectedCriteria
.
splice
(
index
,
1
);
}
}
else
{
// if it doesn't already exist, add it if necessary
if
(
criterionChanged
.
values
&&
criterionChanged
.
values
.
length
)
{
this
.
selectedCriteria
.
push
(
criterionChanged
);
}
}
this
.
aggregationsChange
.
emit
(
this
.
selectedCriteria
);
}
}
frontend/src/app/app.module.ts
View file @
8e1d8d70
...
...
@@ -3,6 +3,9 @@ import { LOCALE_ID, NgModule } from '@angular/core';
import
{
RouterModule
}
from
'
@angular/router
'
;
import
{
HttpClientModule
}
from
'
@angular/common/http
'
;
import
{
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
registerLocaleData
}
from
'
@angular/common
'
;
import
localeFr
from
'
@angular/common/locales/fr
'
;
import
{
NgbPaginationModule
,
NgbTypeaheadModule
}
from
'
@ng-bootstrap/ng-bootstrap
'
;
import
{
routes
}
from
'
./app.routes
'
;
import
{
AppComponent
}
from
'
./app.component
'
;
...
...
@@ -10,9 +13,8 @@ import { HomeComponent } from './home/home.component';
import
{
SearchComponent
}
from
'
./search/search.component
'
;
import
{
GeneticResourcesComponent
}
from
'
./genetic-resources/genetic-resources.component
'
;
import
{
GeneticResourceComponent
}
from
'
./genetic-resource/genetic-resource.component
'
;
import
{
NgbPaginationModule
,
NgbTypeaheadModule
}
from
'
@ng-bootstrap/ng-bootstrap
'
;
import
{
registerLocaleData
}
from
'
@angular/common
'
;
import
localeFr
from
'
@angular/common/locales/fr
'
;
import
{
AggregationsComponent
}
from
'
./aggregations/aggregations.component
'
;
import
{
AggregationComponent
}
from
'
./aggregation/aggregation.component
'
;
registerLocaleData
(
localeFr
);
...
...
@@ -22,7 +24,9 @@ registerLocaleData(localeFr);
HomeComponent
,
SearchComponent
,
GeneticResourcesComponent
,
GeneticResourceComponent
GeneticResourceComponent
,
AggregationsComponent
,
AggregationComponent
],
imports
:
[
BrowserModule
,
...
...
frontend/src/app/genetic-resources/genetic-resources.component.ts
View file @
8e1d8d70
...
...
@@ -14,7 +14,7 @@ export class GeneticResourcesComponent {
@
Input
()
geneticResources
:
Page
<
GeneticResourceModel
>
;
get
firstResultIndex
()
{
return
(
this
.
geneticResources
.
number
*
this
.
geneticResources
.
size
)
+
1
return
(
this
.
geneticResources
.
number
*
this
.
geneticResources
.
size
)
+
1
;
}
get
lastResultIndex
()
{
...
...
frontend/src/app/models/aggregation-criterion.ts
0 → 100644
View file @
8e1d8d70
export
interface
AggregationCriterion
{
name
:
string
;
values
:
Array
<
string
>
;
}
frontend/src/app/models/page.ts
View file @
8e1d8d70
...
...
@@ -6,3 +6,17 @@ export interface Page<T> {
totalPages
:
number
;
maxResults
:
number
;
}
export
interface
Bucket
{
key
:
string
;
documentCount
:
number
;
}
export
interface
Aggregation
{
name
:
string
;
buckets
:
Array
<
Bucket
>
;
}
export
interface
AggregatedPage
<
T
>
extends
Page
<
T
>
{
aggregations
:
Array
<
Aggregation
>
;
}
frontend/src/app/models/test-model-generators.ts
View file @
8e1d8d70
import
{
Page
}
from
'
./page
'
;
import
{
AggregatedPage
,
Aggregation
,
Bucket
}
from
'
./page
'
;
import
{
GeneticResourceModel
}
from
'
./genetic-resource.model
'
;
import
{
AggregationCriterion
}
from
'
./aggregation-criterion
'
;
export
function
toSinglePage
<
T
>
(
content
:
Array
<
T
>
):
Page
<
T
>
{
export
function
toSinglePage
<
T
>
(
content
:
Array
<
T
>
,
aggregations
?:
Array
<
Aggregation
>
):
Aggregated
Page
<
T
>
{
return
{
content
,
number
:
0
,
size
:
20
,
totalElements
:
content
.
length
,
totalPages
:
1
,
maxResults
:
10000
maxResults
:
10000
,
aggregations
:
aggregations
||
[]
};
}
export
function
toSecondPage
<
T
>
(
content
:
Array
<
T
>
):
Page
<
T
>
{
export
function
toSecondPage
<
T
>
(
content
:
Array
<
T
>
,
aggregations
?:
Array
<
Aggregation
>
):
Aggregated
Page
<
T
>
{
return
{
content
,
number
:
1
,
size
:
20
,
totalElements
:
20
+
content
.
length
,
totalPages
:
2
,
maxResults
:
10000
maxResults
:
10000
,
aggregations
:
aggregations
||
[]
};
}
export
function
toAggregation
(
name
:
string
,
values
:
Array
<
string
>
):
Aggregation
{
// creates a bucket for each value, with a document count of (index+1)*10
const
buckets
:
Array
<
Bucket
>
=
values
.
map
((
key
,
index
)
=>
({
key
,
documentCount
:
(
index
+
1
)
*
10
}));
return
{
name
,
buckets
};
}
export
function
toAggregationCriterion
(
name
:
string
,
values
:
Array
<
string
>
):
AggregationCriterion
{
return
{