Skip to content

Commit

Permalink
feat(editor): rework sorting of records table
Browse files Browse the repository at this point in the history
  • Loading branch information
jahow committed Sep 8, 2023
1 parent 07bbbbc commit 721e0e5
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ <h1 class="text-[56px] font-title grow">{{ title }}</h1>
[records]="results"
[totalHits]="searchFacade.resultsHits$ | async"
(recordSelect)="editRecord($event)"
(sortByChange)="setSortBy($event)"
[sortBy]="searchFacade.sortBy$ | async"
></gn-ui-record-table>
<div
class="px-5 py-5 flex justify-center gap-8 items-baseline"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -48,4 +49,8 @@ export class RecordsListComponent {
editRecord(record: CatalogRecord) {
this.router.navigate(['/edit', record.uniqueIdentifier])
}

setSortBy(newSortBy: SortByField) {
this.searchFacade.setSortBy(newSortBy)
}
}
95 changes: 74 additions & 21 deletions libs/ui/search/src/lib/record-table/record-table.component.html
Original file line number Diff line number Diff line change
@@ -1,44 +1,97 @@
<div>
<div *ngIf="totalHits" class="">
<div translate class="my-8 ml-4 block text-gray-500" [translateParams]="{
<div
translate
class="my-8 ml-4 block text-gray-500"
[translateParams]="{
displayed: records.length,
hits: totalHits
}">
}"
>
results.records.hits.displayedOn
</div>
<div class="grid grid-cols-[repeat(5,minmax(0,max-content))] gap-x-4 gap-y-1">

<div
class="grid grid-cols-[repeat(5,minmax(0,max-content))] gap-x-4 gap-y-1"
>
<div class="contents text-sm">
<div translate="" class="record-table-header text-gray-400 flex gap-1" (click)="activeSortElement = 'title'">
record.metadata.title
<gn-ui-sort *ngIf="activeSortElement === 'title'" [records]="records" activeCol="title"></gn-ui-sort>
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
(buttonClick)="setSortBy('resourceTitleObject.default.keyword')"
>
<span translate>record.metadata.title</span>
<!-- <gn-ui-sort *ngIf="activeSortElement === 'title'" [records]="records" activeCol="title"></gn-ui-sort> -->
<mat-icon
*ngIf="isSortedBy('resourceTitleObject.default.keyword', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
*ngIf="isSortedBy('resourceTitleObject.default.keyword', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400 flex gap-1">
record.metadata.formats
</div>
<div translate="" class="record-table-header text-gray-400 flex gap-1" (click)="activeSortElement = 'admin'">
record.metadata.author
<gn-ui-sort *ngIf="activeSortElement === 'admin'" [records]="records"
activeCol="extras.ownerInfo"></gn-ui-sort>
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
type="light"
extraClass="px-3 py-2"
(buttonClick)="setSortBy('recordOwner')"
>
<span translate>record.metadata.author</span>
<mat-icon
class="!w-[16px] !h-[16px]"
*ngIf="isSortedBy('recordOwner', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
class="!w-[16px] !h-[16px]"
*ngIf="isSortedBy('recordOwner', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400 flex gap-1"
(click)="activeSortElement = 'recordUpdated'">
record.metadata.completion
<gn-ui-sort *ngIf="activeSortElement === 'recordUpdated'" [records]="records"
activeCol="recordUpdated"></gn-ui-sort>
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button (buttonClick)="setSortBy('changeDate')">
<span translate>record.metadata.completion</span>
<mat-icon *ngIf="isSortedBy('changeDate', 'desc')">
expand_more</mat-icon
>
<mat-icon *ngIf="isSortedBy('changeDate', 'asc')">
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400 flex gap-1">
record.metadata.createdOn
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button (buttonClick)="setSortBy('createDate')">
<span translate>record.metadata.createdOn</span>
<mat-icon *ngIf="isSortedBy('createDate', 'desc')">
expand_more</mat-icon
>
<mat-icon *ngIf="isSortedBy('createDate', 'asc')">
expand_less</mat-icon
>
</gn-ui-button>
</div>
</div>
<div class="contents hover:text-gray-900 text-gray-800 cursor-pointer" (click)="recordSelect.emit(record)"
*ngFor="let record of records">
<div
class="contents hover:text-gray-900 text-gray-800 cursor-pointer"
(click)="recordSelect.emit(record)"
*ngFor="let record of records"
>
<div [title]="record.title" class="record-table-col text-16">
{{ record.title }}
</div>
<div class="record-table-col text-16">
<span class="badge-btn btn-active text-sm">{{
getStatus(record.extras?.isPublishedToAll)
}}</span>
}}</span>
</div>
<div class="record-table-col flex items-center gap-2 text-16">
<mat-icon class="material-icons-outlined"> person </mat-icon>
Expand All @@ -53,4 +106,4 @@
</div>
</div>
</div>
</div>
</div>
38 changes: 38 additions & 0 deletions libs/ui/search/src/lib/record-table/record-table.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { RecordTableComponent } from './record-table.component'
import { SortByField } from '@geonetwork-ui/common/domain/search'

describe('RecordTableComponent', () => {
let component: RecordTableComponent
Expand All @@ -19,4 +20,41 @@ describe('RecordTableComponent', () => {
it('should create', () => {
expect(component).toBeTruthy()
})

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)
})
})
})
})
41 changes: 38 additions & 3 deletions libs/ui/search/src/lib/record-table/record-table.component.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures'
import { CatalogRecord } from '@geonetwork-ui/common/domain/record'
import { SortByField } from '@geonetwork-ui/common/domain/search'

@Component({
selector: 'gn-ui-record-table',
templateUrl: './record-table.component.html',
styleUrls: ['./record-table.component.css'],
})
export class RecordTableComponent {
@Input() records: CatalogRecord[] = DATASET_RECORDS
@Input() records: CatalogRecord[] = []
@Input() totalHits?: number
@Input() sortBy?: SortByField
@Output() recordSelect = new EventEmitter<CatalogRecord>()
activeSortElement: string | null = null
@Output() sortByChange = new EventEmitter<SortByField>()

dateToString(date: Date): string {
return date?.toLocaleDateString(undefined, {
Expand All @@ -33,4 +34,38 @@ export class RecordTableComponent {
}
return undefined
}

// single sort: ['asc', 'owner']
// multiple sort: [['asc', 'owner'], ['desc', title]]
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
}
}
2 changes: 2 additions & 0 deletions libs/ui/search/src/lib/ui-search.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand All @@ -52,6 +53,7 @@ import { CommonModule } from '@angular/common'
TagInputModule,
UtilSharedModule,
UiWidgetsModule,
UiInputsModule,
UiElementsModule,
MatIconModule,
RouterLink,
Expand Down

0 comments on commit 721e0e5

Please sign in to comment.