Skip to content

Commit

Permalink
search : extends search result behavior
Browse files Browse the repository at this point in the history
* Adds some areas into the default `record-search` component (used to
  render a search result) to allow content injection :
  top-search-result, top-result, top-facets, bottom-result,
  bottom-search-result.
* Add option to always hide a facet : In some case, we need to request
  to backend about a facet, but this facet should never be displayed
  by search components (other component can use content-injection to
  display them).

Co-authored-by: Renaud Michotte <renaud.michotte@gmail.com>
  • Loading branch information
zannkukai committed Nov 16, 2022
1 parent 7dd3454 commit f85ad35
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 558 deletions.
13 changes: 9 additions & 4 deletions projects/rero/ng-core/src/lib/record/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ export interface SearchFilter {
};
}

/**
* Interface for an aggregation
*/
/** Interfaces for an aggregation */
export interface Aggregation {
key: string;
bucketSize: any;
Expand All @@ -91,6 +89,13 @@ export interface Aggregation {
loaded?: boolean;
doc_count?: number;
type?: string;
config?: any;
config?: AggregationConfig;
name?: string;
}
export interface AggregationConfig {
type?: string,
min?: number,
max?: number,
step?: number
[x: string | number | symbol]: unknown // allow additional properties
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ <h5 class="mb-0">
</button>
</h5>
</div>
<div class="collapse" [class.show]="showAggregation()">
<div class="collapse" [class.show]="isAggregationDisplayed">
<div class="card-body pl-3 pr-2 py-3">
<ng-container [ngSwitch]="aggregation.type">
<!-- Range -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,16 @@ import { Aggregation } from '../../record';
templateUrl: './aggregation.component.html',
})
export class RecordSearchAggregationComponent {
// COMPONENT ATTRIBUTES =====================================================
/** Aggregation data */
@Input() aggregation: Aggregation;

/** Current selected values */
@Input() aggregationsFilters = [];

/**
* Output event when aggregation is clicked.
*/
/** Output event when aggregation is clicked. */
@Output() aggregationClicked = new EventEmitter<any>();

// GETTER & SETTER ==========================================================
/**
* Returns aggregations filters corresponding to the aggregation key.
* @return List of aggregation filters
Expand All @@ -42,26 +41,23 @@ export class RecordSearchAggregationComponent {
return aggregationFilters === undefined ? [] : aggregationFilters.values;
}

/**
* Display buckets for the aggregation or not.
* @return Boolean
*/
showAggregation(): boolean {
/** Is the aggregation content should be displayed. */
get isAggregationDisplayed(): boolean {
return this.aggregation.expanded || this.aggregationFilters.length > 0;
}

// PUBLIC COMPONENTS ========================================================

/**
* Method called when the title of an aggregation is clicked.
*/
toggleVisibility(): void {
// if filters are seleted, we do nothing.
// if filters are selected, we do nothing.
if (this.aggregationFilters.length > 0) {
return;
}

// Toggle expanded.
// Toggle aggregation expanded attribute
this.aggregation.expanded = !this.aggregation.expanded;

// Emit the value to parent.
this.aggregationClicked.emit({
key: this.aggregation.key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
</ng-container>
</li>
</ul>
<div *ngIf="displayMoreAndLessLink()">
<div *ngIf="displayMoreAndLessLink">
<button class="btn btn-link ml-2"
(click)="moreMode = !moreMode">{{ (moreMode ? 'more…' : 'less…') | translate }}</button>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,44 @@ export class BucketsComponent implements OnInit, OnDestroy, OnChanges {

/** More and less on aggregation content (facet) */
moreMode = true;

/** Current selected values for the aggregation */
/** Current selected values for the aggregations */
aggregationsFilters: Array<AggregationsFilter> = [];

/** Children of current bucket */
bucketChildren: any = {};

/** Subscription to aggregationsFilters observable */
private _aggregationsFiltersSubscription: Subscription;


// GETTERS & SETTERS =================================================================
/** Returns selected filters for the aggregation key. */
get aggregationFilters(): Array<string> {
const aggregationFilters = this.aggregationsFilters.find((item: AggregationsFilter) => item.key === this.aggregationKey);
return aggregationFilters === undefined
? []
: aggregationFilters.values;
}

/** Get bucket size. */
get bucketSize(): number {
const size = this.buckets.length;
return this.size === null || this.moreMode === false
? size
: this.size;
}

/** Get buckets with non-zero doc_count. */
get bucketsLength(): number {
return this.buckets.reduce((acc, bucket) => (bucket.doc_count) ? acc+1 : acc, 0);
}

/** Should display more or less link for a bucket ? */
get displayMoreAndLessLink(): boolean {
return (this.size === null)
? false
: this.bucketsLength > this.size;
}

// CONSTRUCTOR & HOOKS ==============================================================
/**
* Constructor
Expand All @@ -60,23 +88,24 @@ export class BucketsComponent implements OnInit, OnDestroy, OnChanges {
) {}

/**
* Component initialization method, which subscribe to the observable of
* aggregations filters for getting the aggregations filters each time
* they will change.
* OnInit hook
* Subscribe to aggregations filters observable for getting the aggregations filters each time
* they will change.
*/
ngOnInit() {
this._aggregationsFiltersSubscription = this._recordSearchService.aggregationsFilters.subscribe(
(aggregationsFilters: Array<AggregationsFilter>) => {
if (aggregationsFilters !== null) {
this.aggregationsFilters = aggregationsFilters;
}
}
);
this._aggregationsFiltersSubscription = this._recordSearchService
.aggregationsFilters
.subscribe((aggregationsFilters: Array<AggregationsFilter>) => {
if (aggregationsFilters !== null) {
this.aggregationsFilters = aggregationsFilters;
}
});
}

/**
* On changes hook, called each time an input property is modified.
* If buckets are changed, refresh children buckets.
* OnChanges hook
* Called each time an input property is modified.
* If buckets are changed, refresh children buckets.
* @param changes - bucket changes
*/
ngOnChanges(changes: SimpleChanges) {
Expand All @@ -88,76 +117,51 @@ export class BucketsComponent implements OnInit, OnDestroy, OnChanges {
}

/**
* Component destruction.
* Unsubscribes from the observable of aggregations filters.
* OnDestroy hook
* Unsubscribes from the observable of aggregations filters.
*/
ngOnDestroy() {
this._aggregationsFiltersSubscription.unsubscribe();
}

// GETTERS & SETTERS =================================================================
/**
* Returns selected filters for the aggregation key.
* @return List of selected filters
*/
get aggregationFilters(): Array<string> {
const aggregationFilters = this.aggregationsFilters.find(
(item: AggregationsFilter) => item.key === this.aggregationKey
);
return aggregationFilters === undefined
? []
: aggregationFilters.values;
}

/**
* Return bucket size
* @return Bucket size
*/
get bucketSize(): number {
const size = this.buckets.length;
return this.size === null || this.moreMode === false
? size
: this.size;
}

// COMPONENT F£UNCTIONS =====================================================
/**
* Check if a value is present in selected filters.
* @param value - string, filter value
* @return true if the value is present in the array.
* @param value - string: filter value
* @return `true` if value is present in the aggregation filters, `false` otherwise.
*/
isSelected(value: string): boolean {
return this.aggregationFilters.includes(value);
}

/**
* Do we need to display the children?
* @return true if we want to display the children
* @return `true` if we want to display the children, `false` otherwise.
*/
displayChildren(bucket): boolean {
return (
this.isSelected(bucket.key) ||
// not necessary but faster than hasChildrenFilter
bucket.indeterminate ||
// hasChildrenFilter is require to avoid blinks when a children is selected
// hasChildrenFilter is required to avoid blinks when a child is selected
this._recordSearchService.hasChildrenFilter(bucket)
);
}

/**
* Update selected filters by adding or removing the given value and push
* values to service.
* @param bucket - string, filter value
* @param bucket - string: the selected bucket value (checked OR unchecked)
*/
updateFilter(bucket: any) {
const index = this.aggregationsFilters.findIndex((item: any) => {
return item.key === this.aggregationKey;
});
const index = this.aggregationsFilters.findIndex((item: AggregationsFilter) => item.key === this.aggregationKey);

if (index === -1) {
// No filters exist for the aggregation.
this._recordSearchService.updateAggregationFilter(this.aggregationKey, [bucket.key], bucket);
} else {
if (!this.aggregationsFilters[index].values.includes(bucket.key)) {
const aggFilter = this.aggregationsFilters[index];
if (!aggFilter.values.includes(bucket.key)) {
// Bucket value is not yet selected, we add value to selected values.
this.aggregationsFilters[index].values.push(bucket.key);
this._recordSearchService.updateAggregationFilter(
Expand Down Expand Up @@ -189,28 +193,4 @@ export class BucketsComponent implements OnInit, OnDestroy, OnChanges {
}
return children;
}

/**
* Display more or less link
* @return Boolean
*/
displayMoreAndLessLink(): boolean {
return (this.size === null)
? false
: this.bucketsLength() > this.size;
}

/**
* Count buckets with non zero doc_count
* @return length of buckets
*/
bucketsLength(): number {
let bucketLength = 0;
for (const bucket of this.buckets) {
if (bucket.doc_count){
bucketLength += 1;
}
}
return bucketLength;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,9 @@ export class ListFiltersComponent implements OnChanges {
* @param buckets - Bucket to get the name from.
*/
getFilterNames(buckets: any) {
if (buckets.length === 0) {
if (!buckets || buckets.length === 0) {
return;
}

buckets.map((bucket: any) => {
for (const k in bucket) {
if (bucket[k].buckets) {
Expand Down
Loading

0 comments on commit f85ad35

Please sign in to comment.