diff --git a/src/webui/package.json b/src/webui/package.json index f9796d9af3..8d38c62ecf 100644 --- a/src/webui/package.json +++ b/src/webui/package.json @@ -42,6 +42,8 @@ "react-dom": "^16.8.6", "react-json-tree": "^0.11.2", "react-monaco-editor": "^0.32.1", + "react-paginate": "^6.3.2", + "react-pagination": "^1.0.0", "react-router": "^3.2.3", "react-table": "^7.0.0-rc.15", "resolve": "1.10.0", @@ -79,7 +81,7 @@ "eslint-plugin-react-hooks": "^1.5.0", "express": "^4.17.1", "npx": "^10.2.0", - "typescript": "3.4.5" + "typescript": "^3.8.0" }, "proxy": "http://localhost:12138", "scripts": { diff --git a/src/webui/src/components/trial-detail/Intermediate.tsx b/src/webui/src/components/trial-detail/Intermediate.tsx index c54019c1b2..308b4b6acf 100644 --- a/src/webui/src/components/trial-detail/Intermediate.tsx +++ b/src/webui/src/components/trial-detail/Intermediate.tsx @@ -128,7 +128,7 @@ class Intermediate extends React.Component id: 'dataZoomY', type: 'inside', yAxisIndex: [0], - filterMode: 'empty', + filterMode: 'none', start: startMediaY, end: endMediaY } diff --git a/src/webui/src/components/trial-detail/TableList.tsx b/src/webui/src/components/trial-detail/TableList.tsx index 26518ded13..fc39b00133 100644 --- a/src/webui/src/components/trial-detail/TableList.tsx +++ b/src/webui/src/components/trial-detail/TableList.tsx @@ -3,8 +3,9 @@ import axios from 'axios'; import ReactEcharts from 'echarts-for-react'; import { Stack, Dropdown, DetailsList, IDetailsListProps, DetailsListLayoutMode, - PrimaryButton, Modal, IDropdownOption, IColumn, Selection, SelectionMode, IconButton, TooltipHost + PrimaryButton, Modal, IDropdownOption, IColumn, Selection, SelectionMode, IconButton, TooltipHost, IStackTokens } from 'office-ui-fabric-react'; +import ReactPaginate from 'react-paginate'; import { LineChart, blocked, copy } from '../Buttons/Icon'; import { MANAGER_IP, COLUMNPro } from '../../static/const'; import { convertDuration, formatTimestamp, intermediateGraphOption, parseMetrics } from '../../static/function'; @@ -19,10 +20,12 @@ import { contentStyles, iconButtonStyles } from '../Buttons/ModalTheme'; import '../../static/style/search.scss'; import '../../static/style/tableStatus.css'; import '../../static/style/logPath.scss'; -import '../../static/style/search.scss'; import '../../static/style/table.scss'; import '../../static/style/button.scss'; import '../../static/style/openRow.scss'; +import '../../static/style/pagination.scss'; + + const echarts = require('echarts/lib/echarts'); require('echarts/lib/chart/line'); require('echarts/lib/component/tooltip'); @@ -31,6 +34,11 @@ echarts.registerTheme('my_theme', { color: '#3c8dbc' }); +const horizontalGapStackTokens: IStackTokens = { + childrenGap: 20, + padding: 10, +}; + interface TableListProps { pageSize: number; tableSource: Array; @@ -66,6 +74,11 @@ interface TableListState { allColumnList: string[]; tableSourceForSort: Array; sortMessage: SortInfo; + offset: number; + data: Array; + perPage: number; + currentPage: number; + pageCount: number; } class TableList extends React.Component { @@ -96,15 +109,19 @@ class TableList extends React.Component { modalIntermediateHeight: window.innerHeight, tableColumns: this.initTableColumnList(this.props.columnList), allColumnList: this.getAllColumnKeys(), - tableSourceForSort: this.props.tableSource, - sortMessage: { field: '', isDescend: false } + sortMessage: { field: '', isDescend: false }, + offset: 0, + data: [], + perPage: 20, + currentPage: 0, + pageCount: 0, + tableSourceForSort: this.props.tableSource }; } // sort for table column onColumnClick = (ev: React.MouseEvent, getColumn: IColumn): void => { - const { tableColumns } = this.state; - const { tableSource } = this.props; + const { tableColumns, tableSourceForSort } = this.state; const newColumns: IColumn[] = tableColumns.slice(); const currColumn: IColumn = newColumns.filter(item => getColumn.key === item.key)[0]; newColumns.forEach((newCol: IColumn) => { @@ -113,11 +130,11 @@ class TableList extends React.Component { currColumn.isSorted = true; } else { newCol.isSorted = false; - newCol.isSortedDescending = true; + newCol.isSortedDescending = true; } }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const newItems = this.copyAndSort(tableSource, currColumn.fieldName!, currColumn.isSortedDescending); + const newItems = this.copyAndSort(tableSourceForSort, currColumn.fieldName!, currColumn.isSortedDescending); this.setState({ tableColumns: newColumns, tableSourceForSort: newItems, @@ -554,19 +571,53 @@ class TableList extends React.Component { componentDidMount(): void { window.addEventListener('resize', this.onWindowResize); + this.updateData() } componentDidUpdate(prevProps: TableListProps): void { if (this.props.columnList !== prevProps.columnList || this.props.tableSource !== prevProps.tableSource) { - const { columnList, tableSource } = this.props; + const { columnList } = this.props; this.setState({ - tableSourceForSort: tableSource, tableColumns: this.initTableColumnList(columnList), allColumnList: this.getAllColumnKeys() + }, () => {this.updateData(); }); } } + updateData(): void { + const tableSource: Array = JSON.parse(JSON.stringify(this.props.tableSource)); + + const tableSlice = tableSource.slice(this.state.offset, this.state.offset + this.state.perPage) + + this.setState({ + tableSourceForSort: tableSlice, + pageCount: Math.ceil(tableSource.length / this.state.perPage), + }); + } + + handlePageClick = (evt: any): void => { + const selectedPage = evt.selected; + const offset = selectedPage * this.state.perPage; + + this.setState({ + currentPage: selectedPage, + offset: offset }, + () => { this.updateData(); + }); + } + + updateperPage = (event: React.FormEvent, item: IDropdownOption | undefined): void => { + // clear input value and re-render table + if (item !== undefined) { + this.setState({ + perPage: item.key === 'all' ? this.props.tableSource.length: Number(item.key) }, + () => {this.updateData(); + }); + } + } + + render(): React.ReactNode { const { intermediateKey, modalIntermediateWidth, modalIntermediateHeight, tableColumns, allColumnList, isShowColumn, modalVisible, @@ -574,7 +625,15 @@ class TableList extends React.Component { isShowCustomizedModal, copyTrialId, intermediateOption, sortMessage } = this.state; const { columnList } = this.props; - const tableSource: Array = JSON.parse(JSON.stringify(this.state.tableSourceForSort)); + const tableSource = this.state.tableSourceForSort + const perPageOptions = [ + { key: '10', text: '10 items per page'}, + { key: '20', text: '20 items per page'}, + { key: '50', text: '50 items per page'}, + { key: 'all', text: 'All items'}, + ]; + + if (sortMessage.field !== '') { tableSource.sort(function (a, b): any { if (a[sortMessage.field] === undefined) { @@ -586,6 +645,7 @@ class TableList extends React.Component { return (sortMessage.isDescend ? a[sortMessage.field] < b[sortMessage.field] : a[sortMessage.field] > b[sortMessage.field]) ? 1 : -1; }); } + return (
@@ -599,7 +659,32 @@ class TableList extends React.Component { selectionMode={SelectionMode.multiple} selection={this.getSelectedRows} /> - + + + + + {/* this.props.tableSource.length > this.state.perPage && */} + "} + breakLabel={"..."} + breakClassName={"break"} + pageCount={this.state.pageCount} + marginPagesDisplayed={2} + pageRangeDisplayed={2} + onPageChange={this.handlePageClick} + containerClassName={(this.props.tableSource.length == 0 ? "pagination hidden" : "pagination" )} + subContainerClassName={"pages pagination"} + disableInitialCallback={false} + activeClassName={"active"}/> + + + + {/* /> */}
{/* Intermediate Result Modal */} =6.14.4: cmd-shim "^3.0.3" columnify "~1.5.4" config-chain "^1.1.12" - debuglog "*" detect-indent "~5.0.0" detect-newline "^2.1.0" dezalgo "~1.0.3" @@ -7182,7 +7264,6 @@ npm@5.1.0, npm@>=6.14.4: has-unicode "~2.0.1" hosted-git-info "^2.8.8" iferr "^1.0.2" - imurmurhash "*" infer-owner "^1.0.4" inflight "~1.0.6" inherits "^2.0.4" @@ -7201,14 +7282,8 @@ npm@5.1.0, npm@>=6.14.4: libnpx "^10.2.4" lock-verify "^2.1.0" lockfile "^1.0.4" - lodash._baseindexof "*" lodash._baseuniq "~4.6.0" - lodash._bindcallback "*" - lodash._cacheindexof "*" - lodash._createcache "*" - lodash._getnative "*" lodash.clonedeep "~4.5.0" - lodash.restparam "*" lodash.union "~4.6.0" lodash.uniq "~4.5.0" lodash.without "~4.4.0" @@ -7310,6 +7385,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-assign@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" + integrity sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo= + object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -8466,7 +8546,7 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -private@^0.1.6: +private@^0.1.6, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -8515,7 +8595,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" dependencies: @@ -8785,6 +8865,20 @@ react-monaco-editor@^0.32.1: "@types/react" "^15.x || ^16.x" prop-types "^15.0.0" +react-paginate@^6.3.2: + version "6.3.2" + resolved "https://registry.yarnpkg.com/react-paginate/-/react-paginate-6.3.2.tgz#4e18cbdb2654d308566775fa14df11e820188391" + integrity sha512-Ch++Njfv8UHpLtIMiQouAPeJQA5Ki86kIYfCer6c1B96Rvn3UF27se+goCilCP8oHNXNsA2R2kxvzanY1YIkyg== + dependencies: + prop-types "^15.6.1" + +react-pagination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/react-pagination/-/react-pagination-1.0.0.tgz#28e605b844c8033c498d2d9f0f5585daf6b84d55" + integrity sha1-KOYFuETIAzxJjS2fD1WF2va4TVU= + dependencies: + react "^0.13.3" + react-router@^3.2.3: version "3.2.5" resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.5.tgz#6f5ce8f4f0b4ff6a6b2fc6106d7619e342fb57be" @@ -8802,6 +8896,13 @@ react-table@^7.0.0-rc.15: version "7.0.0-rc.15" resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-rc.15.tgz#bb855e4e2abbb4aaf0ed2334404a41f3ada8e13a" +react@^0.13.3: + version "0.13.3" + resolved "https://registry.yarnpkg.com/react/-/react-0.13.3.tgz#a2dfa85335d7dc02b82b482f089582e64cc13356" + integrity sha1-ot+oUzXX3AK4K0gvCJWC5kzBM1Y= + dependencies: + envify "^3.0.0" + react@^16.8.6: version "16.12.0" resolved "https://registry.yarnpkg.com/react/-/react-16.12.0.tgz#0c0a9c6a142429e3614834d5a778e18aa78a0b83" @@ -8971,6 +9072,16 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +recast@^0.11.17: + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= + dependencies: + ast-types "0.9.6" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + recursive-readdir@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" @@ -9666,7 +9777,7 @@ source-map@^0.4.2: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -10143,7 +10254,7 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -"through@>=2.2.7 <3", through@^2.3.6: +"through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -10291,9 +10402,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.4.5: - version "3.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" +typescript@^3.8.0: + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== ua-parser-js@^0.7.18: version "0.7.21"