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 : Sorting catalog #608

Merged
merged 3 commits into from
Sep 11, 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
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ <h2 class="text-xl mr-4 font-title" translate>
*ngIf="!isOpen"
(buttonClick)="open()"
type="outline"
extraClass="!p-[8px]"
extraClass="!px-[8px]"
data-cy="filters-expand"
>
<mat-icon>more_horiz</mat-icon>
Expand Down
33 changes: 31 additions & 2 deletions apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -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)
})
})
})
})
})
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 @@ -60,6 +60,7 @@ describe('RecordsListComponent', () => {
let fixture: ComponentFixture<RecordsListComponent>
let router: Router
let searchService: SearchService
let searchFacade: SearchFacade

beforeEach(() => {
TestBed.configureTestingModule({
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 })
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 @@ -49,4 +50,8 @@ export class RecordsListComponent {
editRecord(record: CatalogRecord) {
this.router.navigate(['/edit', record.uniqueIdentifier])
}

setSortBy(newSortBy: SortByField) {
this.searchFacade.setSortBy(newSortBy)
}
}
4 changes: 4 additions & 0 deletions apps/metadata-editor/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ body {
.menu-title {
@apply text-xl px-9 py-3;
}

.mat-mdc-button-base {
line-height: normal;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { TranslateModule } from '@ngx-translate/core'
import {
componentWrapperDecorator,
Meta,
moduleMetadata,
StoryObj,
} from '@storybook/angular'
import { 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 { ButtonComponent } from '@geonetwork-ui/ui/inputs'
import { PaginationButtonsComponent } from './pagination-buttons.component'
import { FormsModule } from '@angular/forms'
import { action } from '@storybook/addon-actions'
Expand Down
5 changes: 5 additions & 0 deletions libs/ui/inputs/src/lib/button/button.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* makes sure icons will not make the buttons grow vertically */
mat-icon.mat-icon {
margin-top: -0.3em;
margin-bottom: -0.3em;
}
21 changes: 19 additions & 2 deletions libs/ui/inputs/src/lib/button/button.component.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
TRANSLATE_DEFAULT_CONFIG,
UtilI18nModule,
} from '@geonetwork-ui/util/i18n'
import { MatIconModule } from '@angular/material/icon'

export default {
title: 'Inputs/ButtonComponent',
Expand All @@ -14,6 +15,7 @@ export default {
imports: [
UtilI18nModule,
TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG),
MatIconModule,
],
}),
],
Expand All @@ -36,7 +38,22 @@ export const Primary: StoryObj<ButtonComponentWithContent> = {
},
render: (args) => ({
props: args,
template:
'<gn-ui-button [type]="type" [disabled]="disabled" [extraClass]="extraClass">{{ content }}</gn-ui-button>',
template: `<div class='flex flex-row gap-5'>
<gn-ui-button [type]="type" [disabled]="disabled" [extraClass]="extraClass">
{{ content }}
</gn-ui-button>
<gn-ui-button [type]="type" [disabled]="disabled" [extraClass]="extraClass">
with an icon&nbsp;<mat-icon class="material-symbols-outlined">downloading</mat-icon>
</gn-ui-button>
<gn-ui-button class="text-[1.5em]" [type]="type" [disabled]="disabled" [extraClass]="extraClass">
<mat-icon class='material-symbols-outlined'>globe_asia</mat-icon>&nbsp;bigger
</gn-ui-button>
<gn-ui-button class="text-[0.7em]" [type]="type" [disabled]="disabled" [extraClass]="extraClass">
<mat-icon class='material-symbols-outlined'>pest_control</mat-icon>&nbsp;smaller
</gn-ui-button>
<gn-ui-button [type]="type" [disabled]="disabled" [extraClass]="extraClass + ' !px-[3em] !py-[0.5em]'">
different&nbsp;<mat-icon class="material-symbols-outlined">waves</mat-icon>&nbsp;shape
</gn-ui-button>
</div>`,
}),
}
2 changes: 1 addition & 1 deletion libs/ui/inputs/src/lib/button/button.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class ButtonComponent {
case 'primary':
return 'focus:ring-4 focus:ring-primary-lightest'
case 'outline':
return 'border border-gray-300 hover:border-primary-lighter focus:border-primary-lighter focus:ring-4 focus:ring-primary-lightest active:border-primary-darker'
return 'border border-gray-300 -m-[1px] hover:border-primary-lighter focus:border-primary-lighter focus:ring-4 focus:ring-primary-lightest active:border-primary-darker'
case 'light':
return 'focus:ring-4 focus:ring-gray-300'
}
Expand Down
91 changes: 82 additions & 9 deletions libs/ui/search/src/lib/record-table/record-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,97 @@
>
results.records.hits.displayedOn
</div>

<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">
record.metadata.title
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
type="light"
extraClass="px-3 py-2 space-x-1"
(buttonClick)="setSortBy('resourceTitleObject.default.keyword')"
>
<span translate>record.metadata.title</span>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('resourceTitleObject.default.keyword', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('resourceTitleObject.default.keyword', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400">
<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">
record.metadata.author
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
type="light"
extraClass="px-3 py-2 space-x-1"
(buttonClick)="setSortBy('recordOwner')"
>
<span translate>record.metadata.author</span>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('recordOwner', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('recordOwner', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400">
record.metadata.completion
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
type="light"
extraClass="px-3 py-2 space-x-1"
(buttonClick)="setSortBy('changeDate')"
>
<span translate>record.metadata.updatedOn</span>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('changeDate', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('changeDate', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
<div translate="" class="record-table-header text-gray-400">
record.metadata.createdOn
<div class="record-table-header text-gray-400 flex gap-1">
<gn-ui-button
type="light"
extraClass="px-3 py-2 space-x-1"
(buttonClick)="setSortBy('createDate')"
>
<span translate>record.metadata.createdOn</span>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('createDate', 'desc')"
>
expand_more</mat-icon
>
<mat-icon
class="material-symbols-outlined"
*ngIf="isSortedBy('createDate', 'asc')"
>
expand_less</mat-icon
>
</gn-ui-button>
</div>
</div>
<div
Expand Down
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
Expand Up @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'
import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures'

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

describe('RecordTableComponent', () => {
let component: RecordTableComponent
Expand Down Expand Up @@ -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)
})
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Meta, StoryObj } from '@storybook/angular'
import { moduleMetadata } from '@storybook/angular'
import { RecordTableComponent } from './record-table.component'
import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures'
import { action } from '@storybook/addon-actions'
import { MatIconModule } from '@angular/material/icon'
import { UiInputsModule } from '@geonetwork-ui/ui/inputs'

const meta: Meta<RecordTableComponent> = {
component: RecordTableComponent,
title: 'Search/RecordTableComponent',
decorators: [
moduleMetadata({
declarations: [RecordTableComponent],
imports: [UiInputsModule, MatIconModule],
}),
],
render: (args: RecordTableComponent) => ({
props: {
...args,
recordSelect: action('recordSelect'),
sortByChange: action('sortByChange'),
},
}),
}
export default meta
type Story = StoryObj<RecordTableComponent>

export const Primary: Story = {
args: {
records: DATASET_RECORDS.concat(DATASET_RECORDS, DATASET_RECORDS),
totalHits: 1234,
},
}
Loading
Loading