Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

search: add date range facet widget #416

Merged
merged 2 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion projects/rero/ng-core/src/lib/record/record.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { RecordSearchComponent } from './search/record-search.component';
import { JsonComponent } from './search/result/item/json.component';
import { RecordSearchResultComponent } from './search/result/record-search-result.component';
import { RecordSearchResultDirective } from './search/result/record-search-result.directive';
import { AggregationDateRangeComponent } from './search/aggregation/date-range/date-range.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -103,7 +104,8 @@ import { RecordSearchResultDirective } from './search/result/record-search-resul
LabelComponent,
TextareaFieldComponent,
CustomSelectFieldComponent,
MarkdownFieldComponent
MarkdownFieldComponent,
AggregationDateRangeComponent
],
imports: [
// NOTE : BrowserAnimationModule **should** be include in application core module.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,26 @@ <h5 class="mb-0">
<div class="card-body pl-3 pr-2 py-3">
<ng-container [ngSwitch]="aggregation.type">
<!-- Range -->
<ng-core-aggregation-slider [key]="aggregation.key" [min]="aggregation.config.min || 1"
[max]="aggregation.config.max || 100" [step]="aggregation.config.step || 1"
[buckets]="aggregation.value.buckets" *ngSwitchCase="'range'">
<ng-core-aggregation-slider *ngSwitchCase="'range'"
[key]="aggregation.key"
[min]="aggregation.config.min || 1"
[max]="aggregation.config.max || 100"
[step]="aggregation.config.step || 1"
[buckets]="aggregation.value.buckets">
</ng-core-aggregation-slider>

<!-- Date range -->
<ng-core-aggregation-date-range *ngSwitchCase="'date-range'"
[key]="aggregation.key"
[config]="aggregation.config"
[buckets]="aggregation.value.buckets">
</ng-core-aggregation-date-range>
<!-- Terms (default) -->
<ng-container *ngSwitchDefault>
<ng-core-record-search-aggregation-buckets [buckets]="aggregation.value.buckets"
[aggregationKey]="aggregation.key" [size]="aggregation.bucketSize"
*ngIf="aggregation.value.buckets.length > 0; else noResult">
<ng-core-record-search-aggregation-buckets
*ngIf="aggregation.value.buckets.length > 0; else noResult"
[buckets]="aggregation.value.buckets"
[aggregationKey]="aggregation.key"
[size]="aggregation.bucketSize">
</ng-core-record-search-aggregation-buckets>
<ng-template #noResult>
<i class="small" translate *ngIf="aggregation.loaded">No result</i>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!--
RERO angular core
Copyright (C) 2021 RERO
Copyright (C) 2021 UCLouvain

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<div class="row mt-3">
<div class="col-12 form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-calendar"></i></span>
</div>
<input class="form-control"
[(ngModel)]="dateRangeModel"
[bsValue]="dateRangeModel"
[bsConfig]="bsConfig"
bsDaterangepicker>
</div>
</div>
</div>
<div class="text-center mt-2">
<small>
<a href class="mx-3" (click)="$event.preventDefault(); updateFilter()" translate>Filter</a>
<a href class="mx-3" (click)="$event.preventDefault(); clearFilter()" *ngIf="hasQueryParam" translate>Clear filter</a>
</small>
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* RERO angular core
* Copyright (C) 2021 RERO
* Copyright (C) 2021 UCLouvain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AggregationDateRangeComponent } from './date-range.component';
import {TranslateModule} from '@ngx-translate/core';

describe('AggregationDateRangeComponent', () => {
let component: AggregationDateRangeComponent;
let fixture: ComponentFixture<AggregationDateRangeComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [ AggregationDateRangeComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(AggregationDateRangeComponent);
component = fixture.componentInstance;
component.config = {
min: new Date(),
max: new Date(),
};
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* RERO angular core
* Copyright (C) 2021 RERO
* Copyright (C) 2021 UCLouvain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {RecordSearchService} from '../../record-search.service';
import {Subscription} from 'rxjs';
import {TranslateService} from '@ngx-translate/core';

@Component({
selector: 'ng-core-aggregation-date-range',
templateUrl: './date-range.component.html'
})
export class AggregationDateRangeComponent implements OnInit, OnDestroy {

// COMPONENTS ATTRIBUTES ====================================================
/** Buckets list. */
@Input() buckets: Array<any>;
/** Aggregation key. */
@Input() key: string;
/** Components configuration. */
@Input() config: any;

/** model used for bsDatePicker field */
dateRangeModel: Date[];
/** bsDatePicker configuration. */
bsConfig: any = {
isAnimated: true,
containerClass: 'theme-dark-blue'
};
/** True if route have aggregation query param. */
hasQueryParam = false;

/** Subscription to search service. */
private _searchServiceSubscription: Subscription;

// CONSTRUCTOR & HOOKS ======================================================
constructor(
private _recordSearchService: RecordSearchService,
private _translateService: TranslateService
) { }

/** OnInit hook */
ngOnInit(): void {
// Define min/max values if not exists
if (!this.config.hasOwnProperty('min') || this.config.min < 0) {
this.config.min = 0;
}
if (!this.config.hasOwnProperty('max')) {
this.config.max = new Date();
this.config.max.setFullYear(this.config.max.getFullYear() + 1).getTime();
}

// Build bsDateRangePicker configuration
this.bsConfig.maxDate = new Date(this.config.max);
this.bsConfig.minDate = new Date(this.config.min);
const today = new Date();
this.bsConfig.ranges = [{
value: [new Date(new Date().setDate(today.getDate() - 7)), today],
label: this._translateService.instant(_('Last 7 days'))
}, {
value: [new Date(new Date().setDate(today.getDate() - 31)), today],
label: this._translateService.instant(_('Last month'))
}, {
value: [new Date(new Date().setDate(today.getDate() - 366)), today],
label: this._translateService.instant(_('Last year'))
}, {
value: [new Date(today.getFullYear(), today.getMonth(), 1), new Date(today.getFullYear(), today.getMonth() + 1, 0)],
label: this._translateService.instant(_('This month'))
}, {
value: [new Date(today.getFullYear(), 0, 1), new Date(today.getFullYear() + 1, 0, 1)],
label: this._translateService.instant(_('This year'))
}];

this.dateRangeModel = [this.config.min, this.config.max];
this._searchServiceSubscription = this._recordSearchService.aggregationsFilters.subscribe((filters: any) => {
if (!filters) {
return;
}
let filter = filters.find((element: any) => element.key === this.key);
if (filter) {
filter = filter.values[0].split('--').map((item: string) => {
return new Date(+item);
});
this.hasQueryParam = true;
this.dateRangeModel = filter;
} else {
this.dateRangeModel = [];
}
});
}

/** OnDestroy hook */
ngOnDestroy(): void {
this._searchServiceSubscription.unsubscribe();
}

// COMPONENTS FUNCTIONS =====================================================
/** Update aggregation filter. */
updateFilter() {
if (this.dateRangeModel && this.dateRangeModel[0] && this.dateRangeModel[1]) {
this._recordSearchService.updateAggregationFilter(this.key, [
`${this.dateRangeModel[0].getTime()}--${this.dateRangeModel[1].getTime()}`
]);
}
}

/** Clear aggregation filter. */
clearFilter() {
this._recordSearchService.updateAggregationFilter(this.key, []);
}

}