diff --git a/openbis_ng_ui/src/js/components/common/grid/GridController.js b/openbis_ng_ui/src/js/components/common/grid/GridController.js index 77957493c3775287f8dab0e868d5f7aed9b14a32..834cb7c654d9635748d228b610849810b0810fb4 100644 --- a/openbis_ng_ui/src/js/components/common/grid/GridController.js +++ b/openbis_ng_ui/src/js/components/common/grid/GridController.js @@ -154,14 +154,20 @@ export default class GridController { } = this.context.getState() const filteredRows = this._filter(allRows, columns, filters) + + const pageCount = Math.max(Math.ceil(filteredRows.length / pageSize), 1) + const newPage = Math.min(page, pageCount - 1) + const sortedRows = this._sort(filteredRows, columns, sort, sortDirection) - const currentRows = this._page(sortedRows, page, pageSize) + const currentRows = this._page(sortedRows, newPage, pageSize) await this.context.setState({ filteredRows, sortedRows, - currentRows + currentRows, + page: newPage }) + if (selectedRowId) { await this._recalculateSelectedRow() } diff --git a/openbis_ng_ui/src/js/components/common/grid/GridPaging.jsx b/openbis_ng_ui/src/js/components/common/grid/GridPaging.jsx index ef64775218e7431ec378f86955a1a8e1a64d8553..ced6b40187e57141924dc57ff3a4dcc1fb59738b 100644 --- a/openbis_ng_ui/src/js/components/common/grid/GridPaging.jsx +++ b/openbis_ng_ui/src/js/components/common/grid/GridPaging.jsx @@ -106,6 +106,7 @@ class GridPaging extends React.PureComponent { onClick={this.handleFirstPageButtonClick} disabled={page === 0} aria-label='First Page' + data-part='firstPage' > <FirstPageIcon fontSize='small' /> </IconButton> @@ -113,6 +114,7 @@ class GridPaging extends React.PureComponent { onClick={this.handleBackButtonClick} disabled={page === 0} aria-label='Previous Page' + data-part='prevPage' > <KeyboardArrowLeft fontSize='small' /> </IconButton> @@ -120,6 +122,7 @@ class GridPaging extends React.PureComponent { onClick={this.handleNextButtonClick} disabled={page >= Math.ceil(count / pageSize) - 1} aria-label='Next Page' + data-part='nextPage' > <KeyboardArrowRight fontSize='small' /> </IconButton> @@ -127,6 +130,7 @@ class GridPaging extends React.PureComponent { onClick={this.handleLastPageButtonClick} disabled={page >= Math.ceil(count / pageSize) - 1} aria-label='Last Page' + data-part='lastPage' > <LastPageIcon fontSize='small' /> </IconButton> diff --git a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridPagingWrapper.js b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridPagingWrapper.js index 7877a738b582fde16613d545afe8497978846378..d208c05bb9dc72d64a25579d861abc848a559544 100644 --- a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridPagingWrapper.js +++ b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridPagingWrapper.js @@ -1,13 +1,39 @@ import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js' import SelectField from '@src/js/components/common/form/SelectField.jsx' import SelectFieldWrapper from '@srcTest/js/components/common/form/wrapper/SelectFieldWrapper.js' +import IconWrapper from '@srcTest/js/components/common/form/wrapper/IconWrapper.js' import Typography from '@material-ui/core/Typography' +import IconButton from '@material-ui/core/IconButton' export default class GridPagingWrapper extends BaseWrapper { getPageSize() { return new SelectFieldWrapper(this.findComponent(SelectField)) } + getPrevPage() { + return new IconWrapper( + this.findComponent(IconButton).filter({ 'data-part': 'prevPage' }) + ) + } + + getNextPage() { + return new IconWrapper( + this.findComponent(IconButton).filter({ 'data-part': 'nextPage' }) + ) + } + + getFirstPage() { + return new IconWrapper( + this.findComponent(IconButton).filter({ 'data-part': 'firstPage' }) + ) + } + + getLastPage() { + return new IconWrapper( + this.findComponent(IconButton).filter({ 'data-part': 'lastPage' }) + ) + } + getRange() { return this.getStringValue( this.findComponent(Typography) diff --git a/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js b/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js index 68d5c03ae0f29fa1a18075f6ec71af429ef2aee3..e7036d66f06d9c467a5c6921150022f3513a81ca 100644 --- a/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js +++ b/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js @@ -29,6 +29,7 @@ describe('VocabularyFormComponent', () => { test('load existing', testLoadExisting) test('select term', testSelectTerm) test('add term', testAddTerm) + test('remove term', testRemoveTerm) }) async function testLoadNew() { @@ -131,6 +132,7 @@ async function testLoadExisting() { grid: gridJSON, parameters: { vocabulary: { + title: 'Vocabulary', code: { label: 'Code', value: fixture.TEST_VOCABULARY_DTO.getCode(), @@ -377,6 +379,111 @@ async function testAddTerm() { }) } +async function testRemoveTerm() { + const form = await mountExisting() + + form.getGrid().getPaging().getPageSize().change(5) + form.getGrid().getPaging().getNextPage().click() + await form.update() + + form.getGrid().getRows()[0].click() + await form.update() + + form.expectJSON({ + grid: { + rows: [fixture.TEST_TERM_6_DTO].map(term => ({ + values: { + 'code.value': term.getCode(), + 'label.value': term.getLabel(), + 'description.value': term.getDescription(), + 'official.value': String(term.isOfficial()) + }, + selected: true + })), + paging: { + pageSize: { + value: 5 + }, + range: '6-6 of 6' + } + } + }) + + form.getButtons().getEdit().click() + await form.update() + + form.getButtons().getRemoveTerm().click() + await form.update() + + form.expectJSON({ + grid: { + rows: [ + fixture.TEST_TERM_1_DTO, + fixture.TEST_TERM_2_DTO, + fixture.TEST_TERM_3_DTO, + fixture.TEST_TERM_4_DTO, + fixture.TEST_TERM_5_DTO + ].map(term => ({ + values: { + 'code.value': term.getCode(), + 'label.value': term.getLabel(), + 'description.value': term.getDescription(), + 'official.value': String(term.isOfficial()) + }, + selected: false + })), + paging: { + pageSize: { + value: 5 + }, + range: '1-5 of 5' + } + }, + parameters: { + vocabulary: { + title: 'Vocabulary', + code: { + label: 'Code', + value: fixture.TEST_VOCABULARY_DTO.getCode(), + enabled: false, + mode: 'edit' + }, + description: { + label: 'Description', + value: fixture.TEST_VOCABULARY_DTO.getDescription(), + enabled: true, + mode: 'edit' + }, + urlTemplate: { + label: 'URL template', + value: fixture.TEST_VOCABULARY_DTO.getUrlTemplate(), + enabled: true, + mode: 'edit' + } + } + }, + buttons: { + addTerm: { + enabled: true + }, + removeTerm: { + enabled: false + }, + save: { + enabled: true + }, + cancel: { + enabled: true + }, + edit: null, + message: { + text: 'You have unsaved changes.', + type: 'warning' + } + } + }) +} + async function mountNew() { return await common.mount({ type: objectTypes.NEW_VOCABULARY_TYPE