Skip to content

Commit

Permalink
Merge pull request #90 from camptocamp/rework-filter-area
Browse files Browse the repository at this point in the history
[Search] Rework filter area
  • Loading branch information
cmoinier authored Jul 15, 2024
2 parents 2691cc0 + 56c2536 commit 3b1f50f
Show file tree
Hide file tree
Showing 16 changed files with 395 additions and 30 deletions.
38 changes: 30 additions & 8 deletions apps/datahub-e2e/src/e2e/search.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,17 @@ describe('search', () => {
it('should display the search results in a grid', () => {
cy.get('mel-datahub-results-list-grid').should('be.visible')
})
it('should filter the results when selecting a filter value (licence)', () => {
cy.get('@filters').eq(3).click()
it('should filter the results when selecting a filter value (producer)', () => {
cy.get('@filters').eq(1).click()
getFilterOptions()
cy.get('@options').eq(1).click()
cy.get('@result-cards').should('have.length', 2)
cy.get('@result-cards').should('have.length', 1)
cy.get('@result-cards')
.first()
.find('h1')
.should('have.text', ' Accroches vélos MEL ')
cy.get('@result-cards')
.eq(1)
.find('h1')
.should(
'have.text',
' Mat éolien construit ou en projet dans les Hauts de France '
" Concentrations annuelles de polluants dans l'air ambiant issues du réseau permanent de mesures en région Hauts-de-France "
)
})
it('should filter the results when selecting multiple filter values (producer)', () => {
Expand Down Expand Up @@ -223,6 +219,32 @@ describe('search', () => {
' Aucune correspondance. '
)
})
describe('expanded search panel', () => {
beforeEach(() => {
cy.get('[data-cy="filterExpandBtn"]').as('expandBtn')
})
it('should expand the search panel and show more filters on click', () => {
cy.get('mel-datahub-filter-dropdown').should('have.length', 3)
cy.get('@expandBtn').click()
cy.get('mel-datahub-filter-dropdown').should('have.length', 6)
})
it('should show the reset button and reset the filters on click', () => {
cy.get('@expandBtn').click()
cy.get('@filters').eq(3).click()
getFilterOptions()
cy.get('@options').eq(1).click()
cy.get('@result-cards').should('have.length', 2)
cy.get('body').click()
cy.get('[data-cy=filterResetBtn]').click()
cy.get('@result-cards').should('have.length', 14)
})
it('should show close button and show less filters on click', () => {
cy.get('@expandBtn').click()
cy.get('mel-datahub-filter-dropdown').should('have.length', 6)
cy.get('[data-cy=filterCloseBtn]').click()
cy.get('mel-datahub-filter-dropdown').should('have.length', 3)
})
})
})
describe('pagination', () => {
beforeEach(() => {
Expand Down
25 changes: 25 additions & 0 deletions apps/datahub-e2e/src/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ declare namespace Cypress {
login(username?: string, password?: string, redirect?: boolean)
signOut(): void
clearFavorites()
selectDropdownOption(value: string): void
openDropdown(): Chainable<JQuery<HTMLElement>>
}
}

Expand Down Expand Up @@ -68,6 +70,29 @@ Cypress.Commands.add('signOut', () => {
cy.get('a[title="Sign out"]').click()
})

// previous value should be a <gn-ui-dropdown-selector> component
Cypress.Commands.add(
'openDropdown',
{ prevSubject: true },
(dropdownElement) => {
cy.get('body').click('bottomLeft') // first click on the document to close other dropdowns
cy.wrap(dropdownElement).find('button').click()
return cy.get('.cdk-overlay-container').find('[role=listbox]')
}
)

// previous value should be a <gn-ui-dropdown-selector> component
Cypress.Commands.add(
'selectDropdownOption',
{ prevSubject: true },
(dropdownElement, value: string) => {
cy.wrap(dropdownElement)
.openDropdown()
.find(`[data-cy-value="${value}"]`)
.click()
}
)

/**
* This will most likely fail if the user is not logged in!
*/
Expand Down
2 changes: 2 additions & 0 deletions apps/datahub/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { MelDataViewComponent } from './dataset/dataset-visualisation/data-view/
import { environment } from '../environments/environnment'
import { MelModule, MelEmbeddedTranslateLoader } from '@mel-dataplatform/mel'
import { MelFieldsService } from './search/service/fields.service'
import { MelDatahubDropdownRangeComponent } from './search/search-filters/mel-datahub-dropdown-range/mel-datahub-dropdown-range.component'

@NgModule({
declarations: [
Expand All @@ -86,6 +87,7 @@ import { MelFieldsService } from './search/service/fields.service'
DatasetVisualisationComponent,
MelMapViewComponent,
MelDataViewComponent,
MelDatahubDropdownRangeComponent,
],
imports: [
MelModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
</div>
<h1
class="mel-page-title sm:block my-10 sm:-ml-20 sm:mr-10 md:mr-20 lg:mr-44"
data-cy="recordTitle"
>
{{ record.title }}
</h1>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<button
class="mel-primary-button rounded-none"
class="mel-primary-button gap-0 rounded-none w-52"
[attr.aria-owns]="id"
(click)="openOverlay()"
(keydown)="handleTriggerKeydown($event)"
cdkOverlayOrigin
#overlayOrigin="cdkOverlayOrigin"
>
{{ title }}
<span>{{ title }}</span>
<div class="grow flex items-center mr-2 gap-2 overflow-hidden">
@if(hasSelectedChoices){
<div
class="shrink-0 rounded-full text-primary bg-white font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count"
class="shrink-0 rounded-full text-primary bg-white font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count ml-2"
>
{{ selected['length'] }}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
@if (fieldName === 'qualityScore'){
<mel-datahub-dropdown-range
class="w-full"
[title]="title"
[choices]="choices$ | async"
(selectValues)="onSelectedValues($event)"
[attr.data-cy-field]="fieldName"
></mel-datahub-dropdown-range>
} @else {
<mel-datahub-dropdown-multiselect
class="w-full"
[title]="title"
[maxRows]="6"
[choices]="choices$ | async"
[selected]="selected$ | async"
[allowSearch]="true"
(selectValues)="onSelectedValues($event)"
[attr.data-cy-field]="fieldName"
>
</mel-datahub-dropdown-multiselect>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<button
class="mel-primary-button gap-0 rounded-none w-52 justify-between"
[attr.aria-owns]="id"
(click)="openOverlay()"
cdkOverlayOrigin
#overlayOrigin="cdkOverlayOrigin"
>
<span>{{ title }}</span>
<button class="h-6 w-6" data-cy="clearSelection">
@if(hasSelectedChoices && !overlayOpen){
<mat-icon
class="material-symbols-outlined shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn"
(click)="clearSelection($event)"
>
close
</mat-icon>
}
</button>
<mat-icon class="material-symbols-outlined shrink-0">
@if(overlayOpen){
<ng-container>expand_less</ng-container>
} @else {
<ng-container>expand_more</ng-container>
}
</mat-icon>
</button>

<ng-template
cdkConnectedOverlay
cdkConnectedOverlayHasBackdrop
cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
[cdkConnectedOverlayOrigin]="overlayOrigin"
[cdkConnectedOverlayOpen]="overlayOpen"
[cdkConnectedOverlayPositions]="overlayPositions"
[cdkConnectedOverlayScrollStrategy]="scrollStrategy"
[cdkConnectedOverlayFlexibleDimensions]="true"
(overlayOutsideClick)="closeOverlay()"
(detach)="closeOverlay()"
>
<div
class="bg-white border border-gray-300 shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container"
[style.max-height]="overlayMaxHeight"
[style.width]="'300px'"
role="listbox"
tabindex="-1"
[attr.id]="id"
[attr.aria-multiselectable]="true"
[attr.aria-label]="title"
#overlayContainer
>
<div class="flex flex-col ml-3 gap-3">
<div class="mr-3">
<div class="text-primary" translate>
mel.datahub.search.filters.range.from
</div>
<gn-ui-text-input
class="w-64"
(valueChange)="lowValue = $event"
[value]="lowValue"
[hint]="'mel.datahub.search.filters.minValue' | translate"
></gn-ui-text-input>
</div>
<div class="mr-3">
<div class="text-primary" translate>
mel.datahub.search.filters.range.to
</div>
<gn-ui-text-input
class="w-64"
(valueChange)="highValue = $event"
[value]="highValue"
[hint]="'mel.datahub.search.filters.maxValue' | translate"
(keyup.enter)="onValidate()"
></gn-ui-text-input>
</div>
<mel-datahub-button
[disabled]="!lowValue || !highValue"
class="self-end mr-3"
[label]="'mel.datahub.search.filters.validate' | translate"
[icon]="'arrow'"
(click)="onValidate()"
></mel-datahub-button>
</div>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {
CdkOverlayOrigin,
ConnectedPosition,
ScrollStrategyOptions,
} from '@angular/cdk/overlay'
import {
ChangeDetectionStrategy,
Component,
ElementRef,
EventEmitter,
Input,
Output,
ViewChild,
} from '@angular/core'
import { Choice, propagateToDocumentOnly } from 'geonetwork-ui'

@Component({
selector: 'mel-datahub-dropdown-range',
templateUrl: './mel-datahub-dropdown-range.component.html',
styles: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MelDatahubDropdownRangeComponent {
lowValue = ''
highValue = ''
@Input() choices: Choice[]
@Input() title: string
@Input() selected: unknown[] = []
@Output() selectValues = new EventEmitter<unknown[]>()
@ViewChild('overlayOrigin') overlayOrigin: CdkOverlayOrigin
@ViewChild('overlayContainer', { read: ElementRef })
overlayContainer: ElementRef
overlayPositions: ConnectedPosition[] = [
{
originX: 'start',
originY: 'bottom',
overlayX: 'start',
overlayY: 'top',
offsetY: 8,
},
{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'bottom',
offsetY: -8,
},
]
scrollStrategy = this.scrollStrategies.reposition()
overlayOpen = false
overlayWidth = 'auto'
overlayMaxHeight = 'none'
id = `dropdown-range-${Math.floor(Math.random() * 10000)}`

get hasSelectedChoices() {
return this.selected.length > 0
}

constructor(private scrollStrategies: ScrollStrategyOptions) {}

openOverlay() {
this.overlayWidth =
this.overlayOrigin.elementRef.nativeElement.getBoundingClientRect()
.width + 'px'
this.overlayOpen = true
}

closeOverlay() {
this.overlayOpen = false
}

clearSelection(event: Event) {
this.selectValues.emit([])
this.highValue = ''
this.lowValue = ''
this.selected = []
propagateToDocumentOnly(event)
}

onValidate() {
const lowValue = Number(this.lowValue) * 10
const highValue = Number(this.highValue) * 10
this.selected = this.choices
.filter((choice) => {
const choiceNb = Number(choice.value)
if (lowValue && highValue) {
return choiceNb >= lowValue && choiceNb <= highValue
} else if (lowValue) {
return choiceNb >= lowValue
} else if (highValue) {
return choiceNb <= highValue
}
return true
})
.map((choice) => choice.value)
if (this.selected.length === 0) {
// If no value is selected, we keep the low and high values to display nothing
this.selected.push(lowValue, highValue)
}
this.selectValues.emit(this.selected)
}
}
Loading

0 comments on commit 3b1f50f

Please sign in to comment.