diff --git a/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts b/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts index d4004611b1..485afd352b 100644 --- a/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts @@ -1,7 +1,7 @@ describe('dashboard', () => { - let originalList - let newList describe('pagination', () => { + let originalList + let newList it('should display different results on click on arrow', () => { cy.visit('/') cy.get('gn-ui-record-table') @@ -36,4 +36,33 @@ describe('dashboard', () => { }) }) }) + + // NEEDS TO WAIT UNTIL STYLE IS DONE + describe('sorting', () => { + let originalList + let newList + it('should order the result list on click', () => { + 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('.record-table-header').first().click() + cy.get('gn-ui-sort').find('gn-ui-button').first().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) + }) + }) + }) + }) }) diff --git a/apps/metadata-editor/src/app/records/records-list.component.html b/apps/metadata-editor/src/app/records/records-list.component.html index 71204476fc..01198dccb5 100644 --- a/apps/metadata-editor/src/app/records/records-list.component.html +++ b/apps/metadata-editor/src/app/records/records-list.component.html @@ -10,6 +10,8 @@

{{ title }}

[records]="results" [totalHits]="searchFacade.resultsHits$ | async" (recordSelect)="editRecord($event)" + (sortByChange)="setSortBy($event)" + [sortBy]="searchFacade.sortBy$ | async" >
{ let fixture: ComponentFixture let router: Router let searchService: SearchService + let searchFacade: SearchFacade beforeEach(() => { TestBed.configureTestingModule({ @@ -89,6 +90,7 @@ describe('RecordsListComponent', () => { }) router = TestBed.inject(Router) searchService = TestBed.inject(SearchService) + searchFacade = TestBed.inject(SearchFacade) fixture = TestBed.createComponent(RecordsListComponent) component = fixture.componentInstance fixture.detectChanges() @@ -116,6 +118,12 @@ describe('RecordsListComponent', () => { expect(pagination.currentPage).toEqual(currentPage) expect(pagination.totalPages).toEqual(totalPages) }) + it('orders the completion column', () => { + expect(searchFacade.setSortBy).toHaveBeenCalledWith([ + 'desc', + 'changeDate', + ]) + }) describe('when click on a record', () => { beforeEach(() => { table.recordSelect.emit({ uniqueIdentifier: 123 }) diff --git a/apps/metadata-editor/src/app/records/records-list.component.ts b/apps/metadata-editor/src/app/records/records-list.component.ts index e11c1f9dbb..f3511d531c 100644 --- a/apps/metadata-editor/src/app/records/records-list.component.ts +++ b/apps/metadata-editor/src/app/records/records-list.component.ts @@ -6,6 +6,7 @@ import { CatalogRecord } from '@geonetwork-ui/common/domain/record' import { SearchFacade, SearchService } from '@geonetwork-ui/feature/search' import { UiSearchModule } from '@geonetwork-ui/ui/search' import { UiElementsModule } from '@geonetwork-ui/ui/elements' +import { SortByField } from '@geonetwork-ui/common/domain/search' const includes = [ 'uuid', @@ -49,4 +50,8 @@ export class RecordsListComponent { editRecord(record: CatalogRecord) { this.router.navigate(['/edit', record.uniqueIdentifier]) } + + setSortBy(newSortBy: SortByField) { + this.searchFacade.setSortBy(newSortBy) + } } diff --git a/apps/metadata-editor/src/styles.css b/apps/metadata-editor/src/styles.css index e3a2850c1c..41d06136c0 100644 --- a/apps/metadata-editor/src/styles.css +++ b/apps/metadata-editor/src/styles.css @@ -21,3 +21,7 @@ body { .menu-title { @apply text-xl px-9 py-3; } + +.mat-mdc-button-base { + line-height: normal; +} diff --git a/libs/ui/search/src/lib/record-table/record-table.component.html b/libs/ui/search/src/lib/record-table/record-table.component.html index 53365b9bb3..750bb3b409 100644 --- a/libs/ui/search/src/lib/record-table/record-table.component.html +++ b/libs/ui/search/src/lib/record-table/record-table.component.html @@ -10,24 +10,97 @@ > results.records.hits.displayedOn
+
-
- record.metadata.title +
+ + record.metadata.title + + expand_more + + expand_less +
-
+
record.metadata.formats
-
- record.metadata.author +
+ + record.metadata.author + + expand_more + + expand_less +
-
- record.metadata.completion +
+ + record.metadata.completion + + expand_more + + expand_less +
-
- record.metadata.createdOn +
+ + record.metadata.createdOn + + expand_more + + expand_less +
{ let component: RecordTableComponent @@ -39,4 +40,41 @@ describe('RecordTableComponent', () => { ).toEqual('#1e5180') // geojson }) }) + + describe('sorting', () => { + describe('#setSortBy', () => { + let newSortBy: SortByField + beforeEach(() => { + newSortBy = null + component.sortByChange.subscribe((v) => (newSortBy = v)) + }) + it('initially sorts by ascending order', () => { + component.setSortBy('title') + expect(newSortBy).toEqual(['asc', 'title']) + }) + it('changes the order if already sorted', () => { + component.sortBy = ['asc', 'title'] + component.setSortBy('title') + expect(newSortBy).toEqual(['desc', 'title']) + }) + }) + describe('#isSortedBy', () => { + it('returns false if not sorted by this column', () => { + component.sortBy = ['desc', 'owner'] + expect(component.isSortedBy('title', 'desc')).toBe(false) + }) + it('returns true if the current sortBy is for this column', () => { + component.sortBy = ['desc', 'title'] + expect(component.isSortedBy('title', 'desc')).toBe(true) + }) + it('returns true if the current sortBy is for this column (multiple sorts)', () => { + component.sortBy = [ + ['asc', 'score'], + ['desc', 'title'], + ] + expect(component.isSortedBy('title', 'desc')).toBe(true) + expect(component.isSortedBy('title', 'asc')).toBe(false) + }) + }) + }) }) diff --git a/libs/ui/search/src/lib/record-table/record-table.component.ts b/libs/ui/search/src/lib/record-table/record-table.component.ts index cf71e88ff5..a64c25f8d8 100644 --- a/libs/ui/search/src/lib/record-table/record-table.component.ts +++ b/libs/ui/search/src/lib/record-table/record-table.component.ts @@ -6,6 +6,7 @@ import { getFileFormat, getFormatPriority, } from '@geonetwork-ui/util/shared' +import { SortByField } from '@geonetwork-ui/common/domain/search' @Component({ selector: 'gn-ui-record-table', @@ -15,7 +16,9 @@ import { export class RecordTableComponent { @Input() records: CatalogRecord[] = [] @Input() totalHits?: number + @Input() sortBy?: SortByField @Output() recordSelect = new EventEmitter() + @Output() sortByChange = new EventEmitter() dateToString(date: Date): string { return date?.toLocaleDateString(undefined, { @@ -54,4 +57,36 @@ export class RecordTableComponent { getBadgeColor(format: FileFormat): string { return getBadgeColor(format) } + + private getOrderForColumn(col: string): 'asc' | 'desc' | null { + if (!this.sortBy) { + return null + } + let order: 'asc' | 'desc' | null = null + const sortedArray = Array.isArray(this.sortBy[0]) + ? this.sortBy + : [this.sortBy] + sortedArray.forEach((sortedCol) => { + if (sortedCol[1] === col) { + order = sortedCol[0] + } + }) + return order + } + + setSortBy(col: string): void { + const sortOrder = this.getOrderForColumn(col) + let newOrder + if (sortOrder) { + newOrder = sortOrder === 'asc' ? 'desc' : 'asc' + } else { + newOrder = 'asc' + } + this.sortByChange.emit([newOrder, col]) + } + + isSortedBy(col: string, order: 'asc' | 'desc'): boolean { + const sortOrder = this.getOrderForColumn(col) + return sortOrder === order + } } diff --git a/libs/ui/search/src/lib/ui-search.module.ts b/libs/ui/search/src/lib/ui-search.module.ts index 39bff79431..4f0fecd261 100644 --- a/libs/ui/search/src/lib/ui-search.module.ts +++ b/libs/ui/search/src/lib/ui-search.module.ts @@ -26,6 +26,7 @@ import { UiElementsModule } from '@geonetwork-ui/ui/elements' import { RecordPreviewFeedComponent } from './record-preview-feed/record-preview-feed.component' import { RecordTableComponent } from './record-table/record-table.component' import { CommonModule } from '@angular/common' +import { UiInputsModule } from '@geonetwork-ui/ui/inputs' @NgModule({ declarations: [ @@ -52,6 +53,7 @@ import { CommonModule } from '@angular/common' TagInputModule, UtilSharedModule, UiWidgetsModule, + UiInputsModule, UiElementsModule, MatIconModule, RouterLink, diff --git a/translations/en.json b/translations/en.json index 5dd715fbd3..0413e33c75 100644 --- a/translations/en.json +++ b/translations/en.json @@ -175,7 +175,7 @@ "record.metadata.catalog": "Catalog", "record.metadata.completion": "Completion", "record.metadata.contact": "Contact", - "record.metadata.createdOn": "created on", + "record.metadata.createdOn": "Created on", "record.metadata.details": "Details", "record.metadata.download": "Downloads", "record.metadata.formats": "Formats", @@ -188,7 +188,7 @@ "record.metadata.publications": "publications", "record.metadata.related": "Related records", "record.metadata.sheet": "Original metadata sheet", - "record.metadata.title": "title", + "record.metadata.title": "Title", "record.metadata.updateFrequency": "Update Frequency", "record.metadata.updateStatus": "Update Status", "record.metadata.updatedOn": "Updated On", diff --git a/translations/fr.json b/translations/fr.json index d74730a09a..ed273ea155 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -171,14 +171,14 @@ "record.externalViewer.open": "Ouvrir dans le visualiseur externe", "record.metadata.about": "À propos", "record.metadata.api": "API", - "record.metadata.author": "", + "record.metadata.author": "Auteur", "record.metadata.catalog": "Catalogue", - "record.metadata.completion": "", + "record.metadata.completion": "Mis à jour", "record.metadata.contact": "Contact", - "record.metadata.createdOn": "", + "record.metadata.createdOn": "Créé le", "record.metadata.details": "Détails", "record.metadata.download": "Téléchargements", - "record.metadata.formats": "", + "record.metadata.formats": "Formats", "record.metadata.isOpenData": "Donnée Ouverte", "record.metadata.keywords": "Mots clés", "record.metadata.links": "Liens", @@ -188,7 +188,7 @@ "record.metadata.publications": "données", "record.metadata.related": "Voir aussi", "record.metadata.sheet": "Fiche de métadonnées d'origine", - "record.metadata.title": "titre", + "record.metadata.title": "Titre", "record.metadata.updateFrequency": "Fréquence de mise à jour", "record.metadata.updateStatus": "Statut de mise à jour", "record.metadata.updatedOn": "Dernière mise à jour",