mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Merge pull request #158 from acelaya-forks/feature/improved-pagination
Feature/improved pagination
This commit is contained in:
commit
2c93e9a587
9 changed files with 381 additions and 30 deletions
|
@ -15,7 +15,7 @@ install:
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- echo "Building commit range ${TRAVIS_COMMIT_RANGE}"
|
- echo "Building commit range ${TRAVIS_COMMIT_RANGE}"
|
||||||
- export MUTATION_FILES=$(git diff ${TRAVIS_COMMIT_RANGE:-origin/master} --name-only | grep src/ | paste -sd ",")
|
- export MUTATION_FILES=$(git diff ${TRAVIS_COMMIT_RANGE:-origin/master} --name-only | grep -E 'src\/(.*).(js|ts|jsx|tsx)' | paste -sd ",")
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- npm run lint
|
- npm run lint
|
||||||
|
|
|
@ -24,7 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
|
|
||||||
* [#151](https://github.com/shlinkio/shlink-web-client/issues/151) Bugfix: When no order is specified, the order by indicator(triangle) still indicate ASC on column header.
|
* [#151](https://github.com/shlinkio/shlink-web-client/issues/151) Fixed "order by" indicator (caret) still indicate ASC on column header when no order is specified.
|
||||||
|
* [#157](https://github.com/shlinkio/shlink-web-client/issues/157) Fixed pagination control on graphs expanding too much when lots of pages need to be rendered.
|
||||||
|
|
||||||
|
|
||||||
## 2.1.0 - 2019-05-19
|
## 2.1.0 - 2019-05-19
|
||||||
|
|
252
package-lock.json
generated
252
package-lock.json
generated
|
@ -905,6 +905,110 @@
|
||||||
"resolved": "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz",
|
"resolved": "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz",
|
||||||
"integrity": "sha1-6QyfcXaLNzbnbX3WeD/Gwq+oi8g="
|
"integrity": "sha1-6QyfcXaLNzbnbX3WeD/Gwq+oi8g="
|
||||||
},
|
},
|
||||||
|
"@jest/console": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/source-map": "^24.9.0",
|
||||||
|
"chalk": "^2.0.1",
|
||||||
|
"slash": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"slash": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@jest/fake-timers": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
|
"jest-message-util": "^24.9.0",
|
||||||
|
"jest-mock": "^24.9.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jest-message-util": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/code-frame": "^7.0.0",
|
||||||
|
"@jest/test-result": "^24.9.0",
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
|
"@types/stack-utils": "^1.0.1",
|
||||||
|
"chalk": "^2.0.1",
|
||||||
|
"micromatch": "^3.1.10",
|
||||||
|
"slash": "^2.0.0",
|
||||||
|
"stack-utils": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jest-mock": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^24.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slash": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@jest/source-map": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"callsites": "^3.0.0",
|
||||||
|
"graceful-fs": "^4.1.15",
|
||||||
|
"source-map": "^0.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"callsites": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@jest/test-result": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/console": "^24.9.0",
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
|
"@types/istanbul-lib-coverage": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@jest/types": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/istanbul-lib-coverage": "^2.0.0",
|
||||||
|
"@types/istanbul-reports": "^1.1.1",
|
||||||
|
"@types/yargs": "^13.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@mrmlnc/readdir-enhanced": {
|
"@mrmlnc/readdir-enhanced": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
"resolved": "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||||
|
@ -1176,6 +1280,31 @@
|
||||||
"loader-utils": "^1.1.0"
|
"loader-utils": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/istanbul-lib-coverage": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/istanbul-lib-report": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/istanbul-lib-coverage": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/istanbul-reports": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/istanbul-lib-coverage": "*",
|
||||||
|
"@types/istanbul-lib-report": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "10.12.18",
|
"version": "10.12.18",
|
||||||
"resolved": "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz",
|
"resolved": "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz",
|
||||||
|
@ -1188,6 +1317,27 @@
|
||||||
"integrity": "sha1-SP2YwVYf5xi2FzPa7Ub/EVtJbhg=",
|
"integrity": "sha1-SP2YwVYf5xi2FzPa7Ub/EVtJbhg=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/stack-utils": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/yargs": {
|
||||||
|
"version": "13.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz",
|
||||||
|
"integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/yargs-parser": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/yargs-parser": {
|
||||||
|
"version": "13.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz",
|
||||||
|
"integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@webassemblyjs/ast": {
|
"@webassemblyjs/ast": {
|
||||||
"version": "1.7.11",
|
"version": "1.7.11",
|
||||||
"resolved": "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz",
|
"resolved": "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz",
|
||||||
|
@ -9772,13 +9922,95 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jest-each": {
|
"jest-each": {
|
||||||
"version": "23.6.0",
|
"version": "24.9.0",
|
||||||
"resolved": "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz",
|
||||||
"integrity": "sha1-ugw6gqgFQ4cBYTnHM6BSQtPXFXU=",
|
"integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"pretty-format": "^23.6.0"
|
"jest-get-type": "^24.9.0",
|
||||||
|
"jest-util": "^24.9.0",
|
||||||
|
"pretty-format": "^24.9.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"callsites": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"ci-info": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-ci": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ci-info": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jest-get-type": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"jest-util": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/console": "^24.9.0",
|
||||||
|
"@jest/fake-timers": "^24.9.0",
|
||||||
|
"@jest/source-map": "^24.9.0",
|
||||||
|
"@jest/test-result": "^24.9.0",
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
|
"callsites": "^3.0.0",
|
||||||
|
"chalk": "^2.0.1",
|
||||||
|
"graceful-fs": "^4.1.15",
|
||||||
|
"is-ci": "^2.0.0",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"slash": "^2.0.0",
|
||||||
|
"source-map": "^0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pretty-format": {
|
||||||
|
"version": "24.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz",
|
||||||
|
"integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^24.9.0",
|
||||||
|
"ansi-regex": "^4.0.0",
|
||||||
|
"ansi-styles": "^3.2.0",
|
||||||
|
"react-is": "^16.8.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-is": {
|
||||||
|
"version": "16.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz",
|
||||||
|
"integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"slash": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jest-environment-jsdom": {
|
"jest-environment-jsdom": {
|
||||||
|
@ -9909,6 +10141,18 @@
|
||||||
"jest-snapshot": "^23.6.0",
|
"jest-snapshot": "^23.6.0",
|
||||||
"jest-util": "^23.4.0",
|
"jest-util": "^23.4.0",
|
||||||
"pretty-format": "^23.6.0"
|
"pretty-format": "^23.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jest-each": {
|
||||||
|
"version": "23.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz",
|
||||||
|
"integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^2.0.1",
|
||||||
|
"pretty-format": "^23.6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jest-leak-detector": {
|
"jest-leak-detector": {
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
"html-webpack-plugin": "^4.0.0-alpha.2",
|
"html-webpack-plugin": "^4.0.0-alpha.2",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^23.6.0",
|
"jest": "^23.6.0",
|
||||||
|
"jest-each": "^24.9.0",
|
||||||
"jest-pnp-resolver": "^1.0.1",
|
"jest-pnp-resolver": "^1.0.1",
|
||||||
"jest-resolve": "^23.6.0",
|
"jest-resolve": "^23.6.0",
|
||||||
"mini-css-extract-plugin": "^0.4.3",
|
"mini-css-extract-plugin": "^0.4.3",
|
||||||
|
|
65
src/common/SimplePaginator.js
Normal file
65
src/common/SimplePaginator.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
||||||
|
import { range, max, min } from 'ramda';
|
||||||
|
import './SimplePaginator.scss';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
pagesCount: PropTypes.number.isRequired,
|
||||||
|
currentPage: PropTypes.number.isRequired,
|
||||||
|
setCurrentPage: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ellipsis = '...';
|
||||||
|
|
||||||
|
const pagination = (currentPage, pageCount) => {
|
||||||
|
const delta = 2;
|
||||||
|
const pages = range(
|
||||||
|
max(delta, currentPage - delta),
|
||||||
|
min(pageCount - 1, currentPage + delta) + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentPage - delta > delta) {
|
||||||
|
pages.unshift(ellipsis);
|
||||||
|
}
|
||||||
|
if (currentPage + delta < pageCount - 1) {
|
||||||
|
pages.push(ellipsis);
|
||||||
|
}
|
||||||
|
|
||||||
|
pages.unshift(1);
|
||||||
|
pages.push(pageCount);
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SimplePaginator = ({ pagesCount, currentPage, setCurrentPage }) => {
|
||||||
|
if (pagesCount < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick = (page) => () => setCurrentPage(page);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pagination listClassName="flex-wrap justify-content-center mb-0 simple-paginator">
|
||||||
|
<PaginationItem disabled={currentPage <= 1}>
|
||||||
|
<PaginationLink previous tag="span" onClick={onClick(currentPage - 1)} />
|
||||||
|
</PaginationItem>
|
||||||
|
{pagination(currentPage, pagesCount).map((page, index) => (
|
||||||
|
<PaginationItem
|
||||||
|
key={page !== ellipsis ? page : `${page}_${index}`}
|
||||||
|
active={page === currentPage}
|
||||||
|
disabled={page === ellipsis}
|
||||||
|
>
|
||||||
|
<PaginationLink tag="span" onClick={onClick(page)}>{page}</PaginationLink>
|
||||||
|
</PaginationItem>
|
||||||
|
))}
|
||||||
|
<PaginationItem disabled={currentPage >= pagesCount}>
|
||||||
|
<PaginationLink next tag="span" onClick={onClick(currentPage + 1)} />
|
||||||
|
</PaginationItem>
|
||||||
|
</Pagination>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SimplePaginator.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default SimplePaginator;
|
3
src/common/SimplePaginator.scss
Normal file
3
src/common/SimplePaginator.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.simple-paginator {
|
||||||
|
user-select: none;
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { fromPairs, head, keys, pipe, prop, reverse, sortBy, splitEvery, toLower, toPairs, type } from 'ramda';
|
import { fromPairs, head, keys, pipe, prop, reverse, sortBy, splitEvery, toLower, toPairs, type } from 'ramda';
|
||||||
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
|
||||||
import SortingDropdown from '../utils/SortingDropdown';
|
import SortingDropdown from '../utils/SortingDropdown';
|
||||||
import PaginationDropdown from '../utils/PaginationDropdown';
|
import PaginationDropdown from '../utils/PaginationDropdown';
|
||||||
import { rangeOf, roundTen } from '../utils/utils';
|
import { rangeOf, roundTen } from '../utils/utils';
|
||||||
|
import SimplePaginator from '../common/SimplePaginator';
|
||||||
import GraphCard from './GraphCard';
|
import GraphCard from './GraphCard';
|
||||||
|
|
||||||
const { max } = Math;
|
const { max } = Math;
|
||||||
|
@ -66,22 +66,9 @@ export default class SortableBarGraph extends React.Component {
|
||||||
|
|
||||||
renderPagination(pagesCount) {
|
renderPagination(pagesCount) {
|
||||||
const { currentPage } = this.state;
|
const { currentPage } = this.state;
|
||||||
|
const setCurrentPage = (currentPage) => this.setState({ currentPage });
|
||||||
|
|
||||||
return (
|
return <SimplePaginator currentPage={currentPage} pagesCount={pagesCount} setCurrentPage={setCurrentPage} />;
|
||||||
<Pagination listClassName="flex-wrap mb-0">
|
|
||||||
<PaginationItem disabled={currentPage === 1}>
|
|
||||||
<PaginationLink previous tag="span" onClick={() => this.setState({ currentPage: currentPage - 1 })} />
|
|
||||||
</PaginationItem>
|
|
||||||
{rangeOf(pagesCount, (page) => (
|
|
||||||
<PaginationItem key={page} active={page === currentPage}>
|
|
||||||
<PaginationLink tag="span" onClick={() => this.setState({ currentPage: page })}>{page}</PaginationLink>
|
|
||||||
</PaginationItem>
|
|
||||||
))}
|
|
||||||
<PaginationItem disabled={currentPage >= pagesCount}>
|
|
||||||
<PaginationLink next tag="span" onClick={() => this.setState({ currentPage: currentPage + 1 })} />
|
|
||||||
</PaginationItem>
|
|
||||||
</Pagination>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
53
test/common/SimplePaginator.test.js
Normal file
53
test/common/SimplePaginator.test.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import { identity } from 'ramda';
|
||||||
|
import each from 'jest-each';
|
||||||
|
import { PaginationItem } from 'reactstrap';
|
||||||
|
import SimplePaginator, { ellipsis } from '../../src/common/SimplePaginator';
|
||||||
|
|
||||||
|
describe('<SimplePaginator />', () => {
|
||||||
|
let wrapper;
|
||||||
|
const createWrapper = (pagesCount, currentPage = 1) => {
|
||||||
|
wrapper = shallow(<SimplePaginator pagesCount={pagesCount} currentPage={currentPage} setCurrentPage={identity} />);
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => wrapper && wrapper.unmount());
|
||||||
|
|
||||||
|
each([ -3, -2, 0, 1 ]).it('renders empty when the amount of pages is smaller than 2', (pagesCount) => {
|
||||||
|
expect(createWrapper(pagesCount).text()).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ellipsis are rendered where expected', () => {
|
||||||
|
const getItemsForPages = (pagesCount, currentPage) => {
|
||||||
|
const paginator = createWrapper(pagesCount, currentPage);
|
||||||
|
const items = paginator.find(PaginationItem);
|
||||||
|
const itemsWithEllipsis = items.filterWhere((item) => item.key() && item.key().includes(ellipsis));
|
||||||
|
|
||||||
|
return { items, itemsWithEllipsis };
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders first ellipsis', () => {
|
||||||
|
const { items, itemsWithEllipsis } = getItemsForPages(9, 7);
|
||||||
|
|
||||||
|
expect(items.at(2).html()).toContain(ellipsis);
|
||||||
|
expect(itemsWithEllipsis).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders last ellipsis', () => {
|
||||||
|
const { items, itemsWithEllipsis } = getItemsForPages(9, 2);
|
||||||
|
|
||||||
|
expect(items.at(items.length - 3).html()).toContain(ellipsis);
|
||||||
|
expect(itemsWithEllipsis).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders both ellipsis', () => {
|
||||||
|
const { items, itemsWithEllipsis } = getItemsForPages(20, 9);
|
||||||
|
|
||||||
|
expect(items.at(2).html()).toContain(ellipsis);
|
||||||
|
expect(items.at(items.length - 3).html()).toContain(ellipsis);
|
||||||
|
expect(itemsWithEllipsis).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -49,12 +49,10 @@ describe('<SortableBarGraph />', () => {
|
||||||
assert = (sortName, sortDir, expectedKeys, expectedValues, done) => {
|
assert = (sortName, sortDir, expectedKeys, expectedValues, done) => {
|
||||||
dropdown.prop('onChange')(sortName, sortDir);
|
dropdown.prop('onChange')(sortName, sortDir);
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
const graphCard = wrapper.find(GraphCard);
|
const stats = wrapper.find(GraphCard).prop('stats');
|
||||||
const statsKeys = keys(graphCard.prop('stats'));
|
|
||||||
const statsValues = values(graphCard.prop('stats'));
|
|
||||||
|
|
||||||
expect(statsKeys).toEqual(expectedKeys);
|
expect(keys(stats)).toEqual(expectedKeys);
|
||||||
expect(statsValues).toEqual(expectedValues);
|
expect(values(stats)).toEqual(expectedValues);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -80,10 +78,9 @@ describe('<SortableBarGraph />', () => {
|
||||||
assert = (itemsPerPage, expectedStats, done) => {
|
assert = (itemsPerPage, expectedStats, done) => {
|
||||||
dropdown.prop('setValue')(itemsPerPage);
|
dropdown.prop('setValue')(itemsPerPage);
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
const graphCard = wrapper.find(GraphCard);
|
const stats = wrapper.find(GraphCard).prop('stats');
|
||||||
const statsKeys = keys(graphCard.prop('stats'));
|
|
||||||
|
|
||||||
expect(statsKeys).toEqual(expectedStats);
|
expect(keys(stats)).toEqual(expectedStats);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue