Skip to content

Commit 19fab61

Browse files
committed
Adding pagination for solution tables (assignment solutions and user-group solutions).
1 parent 9c6a057 commit 19fab61

5 files changed

Lines changed: 56 additions & 10 deletions

File tree

src/components/widgets/SortableTable/SortableTable.js

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@ import { FormattedMessage } from 'react-intl';
44
import { Table } from 'react-bootstrap';
55
import { lruMemoize } from 'reselect';
66

7+
import PaginationButtons from '../PaginationButtons';
78
import { UserUIDataContext } from '../../../helpers/contexts.js';
89
import { CloseIcon, SortedIcon } from '../../icons';
910
import withRouter, { withRouterProps } from '../../../helpers/withRouter.js';
1011
import { storageGetItem, storageSetItem } from '../../../helpers/localStorage.js';
1112

1213
const localStorageKeyPrefix = 'SortableTable';
1314

15+
const _sortData = lruMemoize((data, column, ascendant) =>
16+
column === null || column.comparator === null
17+
? data
18+
: ascendant
19+
? data.sort(column.comparator)
20+
: data.sort(column.comparator).reverse()
21+
);
22+
1423
class SortableTable extends Component {
1524
constructor(props) {
1625
super(props);
17-
this.state = { sortColumn: props.defaultOrder || null, ascendant: true };
26+
this.state = { sortColumn: props.defaultOrder || null, ascendant: true, page: 0 };
1827
}
1928

2029
setSortColumnFromLocalStorage = () => {
@@ -34,6 +43,9 @@ class SortableTable extends Component {
3443
componentDidUpdate(prevProps) {
3544
if (prevProps.id !== this.props.id) {
3645
this.setSortColumnFromLocalStorage();
46+
this.setState({ page: 0 });
47+
} else if (prevProps.data.length !== this.props.data.length || prevProps.maxAmount !== this.props.maxAmount) {
48+
this.setState({ page: 0 });
3749
}
3850
}
3951

@@ -87,15 +99,16 @@ class SortableTable extends Component {
8799
this.setState({ sortColumn, ascendant });
88100
};
89101

102+
selectPage = page => {
103+
this.setState({ page: page - 1 });
104+
};
105+
90106
// Helper function that actually sorts the data according to internal state
91-
sortData = lruMemoize((data, colId, ascendant) => {
107+
sortData = lruMemoize((data, colId, ascendant, offset, amount) => {
92108
const { columns } = this.props;
93109
const column = columns && columns.find(({ id }) => id === colId);
94-
return column === null || column.comparator === null
95-
? data
96-
: ascendant
97-
? data.sort(column.comparator)
98-
: data.sort(column.comparator).reverse();
110+
const allData = _sortData(data, column, ascendant);
111+
return allData.slice(offset, offset + amount);
99112
});
100113

101114
getHeaderSuffixRow = () => {
@@ -125,9 +138,12 @@ class SortableTable extends Component {
125138
openLinkGenerator = null,
126139
staticContext /* avoid capturing static context in the rest of ...props */,
127140
navigate /* avoid capturing injected function by ...props */,
141+
maxAmount = null,
128142
...props
129143
} = this.props;
130-
const { sortColumn, ascendant } = this.state;
144+
const { sortColumn, ascendant, page } = this.state;
145+
const offset = maxAmount ? page * maxAmount : 0;
146+
const amount = maxAmount || data.length;
131147

132148
return (
133149
<UserUIDataContext.Consumer>
@@ -164,7 +180,7 @@ class SortableTable extends Component {
164180
)}
165181
<tbody>
166182
{data.length > 0 ? (
167-
this.sortData(data, sortColumn, ascendant).map((row, idx) =>
183+
this.sortData(data, sortColumn, ascendant, offset, amount).map((row, idx) =>
168184
rowRenderer(row, idx, columns, openOnDoubleclick ? openLinkGenerator : null)
169185
)
170186
) : (
@@ -180,6 +196,31 @@ class SortableTable extends Component {
180196
</tr>
181197
)}
182198
</tbody>
199+
{maxAmount && maxAmount < data.length && (
200+
<tfoot>
201+
<tr>
202+
<td colSpan={columns.length} className="pt-3 px-4">
203+
<small className="float-end text-muted">
204+
<FormattedMessage
205+
id="app.sortableTable.showingEntries"
206+
defaultMessage="showing entries {from} – {to} of {total}"
207+
values={{ from: offset + 1, to: Math.min(offset + maxAmount, data.length), total: data.length }}
208+
/>
209+
</small>
210+
<PaginationButtons
211+
prev
212+
next
213+
maxButtons={10}
214+
boundaryLinks
215+
items={Math.ceil(data.length / maxAmount)}
216+
activePage={this.state.page + 1}
217+
size="small"
218+
onSelect={this.selectPage}
219+
/>
220+
</td>
221+
</tr>
222+
</tfoot>
223+
)}
183224
</Table>
184225
)}
185226
</UserUIDataContext.Consumer>
@@ -197,6 +238,7 @@ SortableTable.propTypes = {
197238
openLinkGenerator: PropTypes.func,
198239
staticContext: PropTypes.any,
199240
navigate: withRouterProps.navigate,
241+
maxAmount: PropTypes.number,
200242
};
201243

202244
export default withRouter(SortableTable);

src/locales/cs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,7 @@
19491949
"app.solutionsTable.submissionDate": "Datum odevzdání",
19501950
"app.solutionsTable.submitNewSolution": "Odevzdat nové řešení",
19511951
"app.solutionsTable.title": "Odevzdaná řešení",
1952+
"app.sortableTable.showingEntries": "zobrazuji položky {from} – {to} z {total}",
19521953
"app.sourceCodeViewer.deleteCommentConfirm": "Opravdu si přejete odstranit tento komentář? Tuto operaci nelze vrátit.",
19531954
"app.sourceCodeViewer.downloadButton": "Stáhnout soubor",
19541955
"app.sourceCodeViewer.incompleteWarning": "Zdrojový soubor je příliš velký, a proto zde nemůže být zobrazen. Použijte tlačítko 'Stáhnout soubor', pokud si jej chcete prohlédnout celý.",

src/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,7 @@
19491949
"app.solutionsTable.submissionDate": "Date of submission",
19501950
"app.solutionsTable.submitNewSolution": "Submit New Solution",
19511951
"app.solutionsTable.title": "Submitted Solutions",
1952+
"app.sortableTable.showingEntries": "showing entries {from} – {to} of {total}",
19521953
"app.sourceCodeViewer.deleteCommentConfirm": "Do you really wish to remove this comment? This operation cannot be undone.",
19531954
"app.sourceCodeViewer.downloadButton": "Download file",
19541955
"app.sourceCodeViewer.incompleteWarning": "The selected source file is too large. Only a leading part of the file is displayed here. Use the download button to get the whole file.",
@@ -2186,4 +2187,4 @@
21862187
"recodex-judge-shuffle-all": "Unordered-tokens-and-rows judge",
21872188
"recodex-judge-shuffle-newline": "Unordered-tokens judge (ignoring ends of lines)",
21882189
"recodex-judge-shuffle-rows": "Unordered-rows judge"
2189-
}
2190+
}

src/pages/AssignmentSolutions/AssignmentSolutions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ class AssignmentSolutions extends Component {
693693
links
694694
)}
695695
defaultOrder="date"
696+
maxAmount={100}
696697
data={prepareTableData(
697698
assignmentSolutions,
698699
getStudents(group.id),

src/pages/GroupUserSolutions/GroupUserSolutions.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ class GroupUserSolutions extends Component {
563563
hover
564564
columns={prepareTableColumnDescriptors(assignments, groupId, locale, links)}
565565
defaultOrder="date"
566+
maxAmount={100}
566567
data={prepareTableData(
567568
assignments,
568569
getAssignmentSolutions,

0 commit comments

Comments
 (0)