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

Metadata-editor/ Pagination #603

Merged
merged 4 commits into from
Sep 1, 2023
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
39 changes: 39 additions & 0 deletions apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
describe('dashboard', () => {
let originalList
let newList
describe('pagination', () => {
it('should display different results on click on arrow', () => {
cy.visit('/')
cy.get('gn-ui-record-table')
.find('.record-table-col')
.first()
.as('pageOne')

cy.get('@pageOne')
.invoke('text')
.then((list) => {
originalList = list.trim()
cy.get('gn-ui-pagination-buttons').find('gn-ui-button').last().click()
cy.get('gn-ui-record-table')
.find('.record-table-col')
.first()
.invoke('text')
.then((list) => {
newList = list.trim()
expect(newList).not.to.be(originalList)
})
})
})
it('should display different results on click on specific page', () => {
cy.get('gn-ui-pagination-buttons').find('gn-ui-button').eq(1).click()
cy.get('gn-ui-record-table')
.find('.record-table-col')
.first()
.invoke('text')
.then((list) => {
newList = list.trim()
expect(newList).to.be(originalList)
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,11 @@ <h1 class="text-[56px] capitalize font-title grow" translate="">
results.records.hits.displayedOn
</div>
<div class="grow">
<gn-ui-pagination
hideButton="true"
<gn-ui-pagination-buttons
[currentPage]="searchFacade.currentPage$ | async"
[nPages]="searchFacade.totalPages$ | async"
[totalPages]="searchFacade.totalPages$ | async"
(newCurrentPageEvent)="paginate($event)"
></gn-ui-pagination>
></gn-ui-pagination-buttons>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export class RecordTableComponent {
}
@Component({
// eslint-disable-next-line
selector: 'gn-ui-pagination',
selector: 'gn-ui-pagination-buttons',
template: '',
})
export class PaginationComponent {
export class PaginationButtonsComponent {
@Input() currentPage = 1
@Input() nPages = 1
@Input() totalPages = 1
@Input() hideButton = false
@Output() newCurrentPageEvent = new EventEmitter<number>()
}
Expand Down Expand Up @@ -64,7 +64,7 @@ describe('DashboardPageComponent', () => {
schemas: [NO_ERRORS_SCHEMA],
declarations: [
DashboardPageComponent,
PaginationComponent,
PaginationButtonsComponent,
RecordTableComponent,
],
providers: [
Expand Down Expand Up @@ -117,7 +117,7 @@ describe('DashboardPageComponent', () => {
By.directive(RecordTableComponent)
).componentInstance
pagination = fixture.debugElement.query(
By.directive(PaginationComponent)
By.directive(PaginationButtonsComponent)
).componentInstance
})
it('displays record table', () => {
Expand All @@ -126,7 +126,7 @@ describe('DashboardPageComponent', () => {
it('displays pagination', () => {
expect(pagination).toBeTruthy()
expect(pagination.currentPage).toEqual(currentPage)
expect(pagination.nPages).toEqual(totalPages)
expect(pagination.totalPages).toEqual(totalPages)
})
describe('when click on a record', () => {
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="relative">
<div class="flex flex-row gap-[5px] items-center">
<gn-ui-button
type="light"
[disabled]="currentPage === 1"
(buttonClick)="previousPage()"
>
<mat-icon>chevron_left</mat-icon>
</gn-ui-button>
<ng-container *ngFor="let page of visiblePages">
<ng-container *ngIf="page === '...'">
<span class="mx-[5px]">{{ page }}</span>
</ng-container>
<ng-container *ngIf="page !== '...'">
<gn-ui-button
[type]="page === currentPage ? 'primary' : 'light'"
[disabled]="page === currentPage"
(buttonClick)="changePage(page)"
>{{ page }}</gn-ui-button
>
</ng-container>
</ng-container>
<gn-ui-button
type="light"
[disabled]="currentPage === totalPages"
(buttonClick)="nextPage()"
>
<mat-icon>chevron_right</mat-icon>
</gn-ui-button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { PaginationButtonsComponent } from './pagination-buttons.component'

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

const mockChangePage = (page) => {
component.setPage(page)
}

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PaginationButtonsComponent],
}).compileComponents()

fixture = TestBed.createComponent(PaginationButtonsComponent)
component = fixture.componentInstance
component.currentPage = 3
component.totalPages = 10
component.calculateVisiblePages()
component.changePage = mockChangePage
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})
describe('when using next arrow', () => {
beforeEach(() => {
component.currentPage = 2
const paginationButtons =
fixture.nativeElement.querySelectorAll('gn-ui-button')
paginationButtons.forEach((buttonElement) => {
const matIcon = buttonElement.querySelector('mat-icon')
if (matIcon && matIcon.textContent.trim() === 'chevron_right') {
buttonElement.dispatchEvent(new Event('buttonClick'))
}
})
})
it('should access next page on click', () => {
expect(component.currentPage).toBe(3)
})
})
describe('when using previous arrow', () => {
beforeEach(() => {
component.currentPage = 4
const paginationButtons =
fixture.nativeElement.querySelectorAll('gn-ui-button')
paginationButtons.forEach((buttonElement) => {
const matIcon = buttonElement.querySelector('mat-icon')
if (matIcon && matIcon.textContent.trim() === 'chevron_left') {
buttonElement.dispatchEvent(new Event('buttonClick'))
}
})
})
it('is should access previous page', () => {
expect(component.currentPage).toBe(3)
})
})
describe('when accessing first page', () => {
beforeEach(() => {
component.currentPage = 1
fixture.detectChanges()
})
it('is should disable the previous arrow', () => {
const paginationButtons =
fixture.nativeElement.querySelectorAll('gn-ui-button')
paginationButtons.forEach((buttonElement) => {
const matIcon = buttonElement.querySelector('mat-icon')
if (matIcon && matIcon.textContent.trim() === 'chevron_left') {
const prevBtn = buttonElement.disabled
expect(prevBtn).toBeTruthy()
}
})
})
})
describe('when accessing last page', () => {
beforeEach(() => {
component.currentPage = 10
fixture.detectChanges()
})
it('is should disable the next arrow', () => {
const paginationButtons =
fixture.nativeElement.querySelectorAll('gn-ui-button')
paginationButtons.forEach((buttonElement) => {
const matIcon = buttonElement.querySelector('mat-icon')
if (matIcon && matIcon.textContent.trim() === 'chevron_right') {
const nextBtn = buttonElement.disabled
expect(nextBtn).toBeTruthy()
}
})
})
})
describe('when clicking on page button', () => {
beforeEach(() => {
const paginationButtons =
fixture.nativeElement.querySelectorAll('gn-ui-button')
const pageBtnList = []
paginationButtons.forEach((buttonElement) => {
const matIcon = buttonElement.querySelector('mat-icon')
if (!matIcon) {
pageBtnList.push(buttonElement)
}
})
pageBtnList[1].dispatchEvent(new Event('buttonClick'))
})
it('is should access the requested page', () => {
expect(component.currentPage).toBe(2)
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { TranslateModule } from '@ngx-translate/core'
import {
componentWrapperDecorator,
Meta,
moduleMetadata,
StoryObj,
} from '@storybook/angular'
import {
TRANSLATE_DEFAULT_CONFIG,
UtilI18nModule,
} from '@geonetwork-ui/util/i18n'
import { UiInputsModule, ButtonComponent } from '@geonetwork-ui/ui/inputs'
import { PaginationButtonsComponent } from './pagination-buttons.component'
import { FormsModule } from '@angular/forms'
import { action } from '@storybook/addon-actions'
import { MatIcon } from '@angular/material/icon'

export default {
title: 'Elements/PaginationButtonsComponent',
component: PaginationButtonsComponent,
decorators: [
moduleMetadata({
declarations: [ButtonComponent, MatIcon],
imports: [
UtilI18nModule,
FormsModule,
TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG),
],
}),
],
render: (args: PaginationButtonsComponent) => ({
props: {
...args,
newCurrentPageEvent: action('newCurrentPageEvent'),
},
}),
} as Meta<PaginationButtonsComponent>

export const Primary: StoryObj<PaginationButtonsComponent> = {
args: {
currentPage: 1,
totalPages: 10,
},
parameters: {
layout: 'centered',
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
Component,
EventEmitter,
Input,
OnChanges,
Output,
} from '@angular/core'

@Component({
selector: 'gn-ui-pagination-buttons',
templateUrl: './pagination-buttons.component.html',
styleUrls: ['./pagination-buttons.component.css'],
})
export class PaginationButtonsComponent implements OnChanges {
@Input() currentPage: number
@Input() totalPages: number
visiblePages: (number | '...')[] = []
@Output() newCurrentPageEvent = new EventEmitter<number>()

ngOnChanges(): void {
this.calculateVisiblePages()
}

calculateVisiblePages(): void {
const maxVisiblePages = 5
const halfVisible = Math.floor(maxVisiblePages / 2)
const startPage = Math.max(this.currentPage - halfVisible, 1)
const endPage = Math.min(this.currentPage + halfVisible, this.totalPages)

const visiblePages: (number | '...')[] = []
if (startPage > 1) {
visiblePages.push(1)
if (startPage > 2) {
visiblePages.push('...')
}
}
for (let page = startPage; page <= endPage; page++) {
visiblePages.push(page)
}
if (endPage < this.totalPages) {
if (endPage < this.totalPages - 1) {
visiblePages.push('...')
}
visiblePages.push(this.totalPages)
}

this.visiblePages = visiblePages
}

changePage(page) {
this.setPage(page)
}

nextPage() {
this.setPage(this.currentPage + 1)
}

previousPage() {
this.setPage(this.currentPage - 1)
}

setPage(newPage) {
if (!Number.isInteger(newPage)) return
this.currentPage = newPage
this.calculateVisiblePages()
this.newCurrentPageEvent.emit(this.currentPage)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { MatIcon } from '@angular/material/icon'
import { FormsModule } from '@angular/forms'

export default {
title: 'Layout/PaginationComponent',
title: 'Elements/PaginationComponent',
component: PaginationComponent,
decorators: [
moduleMetadata({
Expand Down
3 changes: 3 additions & 0 deletions libs/ui/elements/src/lib/ui-elements.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { FormsModule } from '@angular/forms'
import { AvatarComponent } from './avatar/avatar.component'
import { UserPreviewComponent } from './user-preview/user-preview.component'
import { GnUiLinkifyDirective } from './metadata-info/linkify.directive'
import { PaginationButtonsComponent } from './pagination-buttons/pagination-buttons.component'

@NgModule({
imports: [
Expand Down Expand Up @@ -55,6 +56,7 @@ import { GnUiLinkifyDirective } from './metadata-info/linkify.directive'
AvatarComponent,
UserPreviewComponent,
GnUiLinkifyDirective,
PaginationButtonsComponent,
],
exports: [
MetadataInfoComponent,
Expand All @@ -71,6 +73,7 @@ import { GnUiLinkifyDirective } from './metadata-info/linkify.directive'
ThumbnailComponent,
AvatarComponent,
UserPreviewComponent,
PaginationButtonsComponent,
],
})
export class UiElementsModule {}
Loading