diff --git a/packages/react-table/src/docs/demos/Table.md b/packages/react-table/src/docs/demos/Table.md index aa3afbf8413..36762b6d47d 100644 --- a/packages/react-table/src/docs/demos/Table.md +++ b/packages/react-table/src/docs/demos/Table.md @@ -2107,411 +2107,7 @@ class FilterTableDemo extends React.Component { ### Sortable - responsive -```js isFullscreen -import React from 'react'; -import { - Button, - Card, - Flex, - FlexItem, - InputGroup, - Toolbar, - ToolbarContent, - ToolbarGroup, - ToolbarItem, - ToolbarToggleGroup, - OptionsMenu, - OptionsMenuToggle, - Pagination, - Text, - TextContent, - Select, - SelectVariant, - SelectOption, - Nav, - NavList, - NavItem, - Dropdown, - DropdownItem, - DropdownGroup, - DropdownToggle, - Divider, - KebabToggle, - Avatar, - OptionsMenuItem, - OptionsMenuSeparator, - OptionsMenuItemGroup, - OverflowMenu, - OverflowMenuContent, - OverflowMenuControl, - OverflowMenuDropdownItem, - OverflowMenuGroup, - OverflowMenuItem, - PageSection -} from '@patternfly/react-core'; -import { ActionsColumn, TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table'; - -import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon'; -import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; -import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'; -import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon'; -import EditIcon from '@patternfly/react-icons/dist/esm/icons/edit-icon'; -import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; -import SyncIcon from '@patternfly/react-icons/dist/esm/icons/sync-icon'; -import QuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/question-circle-icon'; -import AttentionBellIcon from '@patternfly/react-icons/dist/esm/icons/attention-bell-icon'; -import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon'; -import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon'; -import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; -import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; - -ComposableTableSortable = () => { - const [navActiveItem, setNavActiveItem] = React.useState(0); - const [isDropdownOpen, setIsDropdownOpen] = React.useState(false); - const [isKebabDropdownOpen, setIsKebabDropdownOpen] = React.useState(false); - const [isSelectOpen, setIsSelectOpen] = React.useState(false); - const [isFullKebabDropdownOpen, setIsFullKebabDropdownOpen] = React.useState(false); - - const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit']; - - const [rows, setRows] = React.useState([ - ['Node 1', 10, 25, 5, 2], - ['Node 2', 8, 30, 2, 2], - ['Node 3', 12, 48, 13, 30], - ['Node 4', 10, 25, 5, 8], - ['Node 5', 34, 21, 26, 2] - ]); - - // index of the currently active column - const [activeSortIndex, setActiveSortIndex] = React.useState(0); - // sort direction of the currently active column - const [activeSortDirection, setActiveSortDirection] = React.useState('asc'); - // sort dropdown expansion - const [isSortDropdownOpen, setIsSortDropdownOpen] = React.useState(false); - - const [selectedNodeNames, setSelectedNodeNames] = React.useState([]); - const setNodeSelected = (node, isSelecting = true) => { - if (!selectedNodeNames.includes(node)) { - setSelectedNodeNames([...selectedNodeNames, node]); - } else { - setSelectedNodeNames(selectedNodeNames.filter(n => n !== node)); - } - }; - - const selectAllNodes = (isSelecting = true) => setSelectedNodeNames(isSelecting ? rows.map(r => r[0]) : []); - const areAllReposSelected = selectedNodeNames.length === rows.length; - const isNodeSelected = node => selectedNodeNames.includes(node[0]); - - // To allow shift+click to select/deselect multiple rows - const [recentSelectedRowIndex, setRecentSelectedRowIndex] = React.useState(null); - const [shifting, setShifting] = React.useState(false); - - const onSelectNode = (node, rowIndex, isSelecting) => { - // If the user is shift + selecting the checkboxes, then all intermediate checkboxes should be selected - if (shifting && recentSelectedRowIndex !== null) { - const numberSelected = rowIndex - recentSelectedRowIndex; - const intermediateIndexes = - numberSelected > 0 - ? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex) - : Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex); - intermediateIndexes.forEach(index => setNodeSelected(rows[index], isSelecting)); - } else { - setNodeSelected(node[0], isSelecting); - } - setRecentSelectedRowIndex(rowIndex); - }; - - const onSort = (event, index, direction) => { - setActiveSortIndex(index); - setActiveSortDirection(direction); - // sorts the rows - const updatedRows = rows.sort((a, b) => { - if (typeof a[index] === 'number') { - // numeric sort - if (direction === 'asc') { - return a[index] - b[index]; - } - return b[index] - a[index]; - } else { - // string sort - if (direction === 'asc') { - return a[index].localeCompare(b[index]); - } - return b[index].localeCompare(a[index]); - } - }); - setRows(updatedRows); - }; - - const PageNav = ( - setNavActiveItem(result.itemId)} aria-label="Nav"> - - - System Panel - - - Policy - - - Authentication - - - Network Services - - - Server - - - - ); - - const kebabDropdownItems = [Some action]; - - const defaultActions = () => [ - { - title: 'Settings', - onClick: () => console.log(`clicked on Settings`) - }, - { - title: 'Help', - onClick: () => console.log(`clicked on Help`) - } - ]; - - const renderPagination = (variant, isCompact) => ( - - ); - - const userDropdownItems = [ - - My profile - - User management - - Logout - - ]; - - const fullKebabItems = [ - - My profile - - User management - - Logout - , - , - - Settings - , - - Help - - ]; - - const tableToolbar = ( - - - - - {columns.map((column, columnIndex) => ( - - onSort(evt, columnIndex, activeSortDirection !== 'none' ? activeSortDirection : 'asc') - } - > - {column} - - ))} - , - , - - onSort(evt, activeSortIndex, 'asc')} - isSelected={activeSortDirection === 'asc'} - id="ascending" - key="ascending" - > - Ascending - - onSort(evt, activeSortIndex, 'desc')} - isSelected={activeSortDirection === 'desc'} - id="descending" - key="descending" - > - Descending - - - ]} - isOpen={isSortDropdownOpen} - toggle={ - setIsSortDropdownOpen(!isSortDropdownOpen)} - toggleTemplate={} - /> - } - isPlain - isGrouped - menuAppendTo="parent" - isFlipEnabled - /> - - - - - - Create instance - - - Action - - - - - setIsKebabDropdownOpen(!isKebabDropdownOpen)} - toggle={ setIsKebabDropdownOpen(!isKebabDropdownOpen)} />} - isOpen={isKebabDropdownOpen} - dropdownItems={kebabDropdownItems} - isFlipEnabled - menuAppendTo="parent" - /> - - - - - } /> - - - } /> - - - } /> - - - {renderPagination('top', true)} - - - ); - - return ( - - - - - Table demos - - Below is an example of a responsive sortable table. When the screen size shrinks the table into a compact - form, the toolbar will display a dropdown menu containing sorting options. - - - - - - {tableToolbar} - - - - - {columns.map((column, columnIndex) => { - const sortParams = { - sort: { - sortBy: { - index: activeSortIndex, - direction: activeSortDirection - }, - onSort, - columnIndex - } - }; - return ( - - {column} - - ); - })} - - - - {rows.map((row, rowIndex) => ( - - <> - onSelectNode(row, rowIndex, isSelecting), - isSelected: isNodeSelected(row) - }} - /> - - {row[0]} - siemur/test-space - - - - - - - {row[1]} - - - - - - - - {row[2]} - - - - - - - - {row[3]} - - - {row[4]} days ago - - Action link - - - - - > - - ))} - - - {renderPagination('bottom', false)} - - - - - ); -}; +```js isFullscreen file="./table-demos/SortableResponsive.jsx" ``` ### Automatic pagination diff --git a/packages/react-table/src/docs/demos/table-demos/SortableResponsive.jsx b/packages/react-table/src/docs/demos/table-demos/SortableResponsive.jsx new file mode 100644 index 00000000000..9ea4a1d2d97 --- /dev/null +++ b/packages/react-table/src/docs/demos/table-demos/SortableResponsive.jsx @@ -0,0 +1,326 @@ +import React from 'react'; +import { + Button, + Card, + Flex, + FlexItem, + Toolbar, + ToolbarContent, + ToolbarGroup, + ToolbarItem, + OptionsMenu, + OptionsMenuToggle, + Pagination, + Text, + TextContent, + Dropdown, + KebabToggle, + OptionsMenuItem, + OptionsMenuSeparator, + OptionsMenuItemGroup, + OverflowMenu, + OverflowMenuContent, + OverflowMenuControl, + OverflowMenuDropdownItem, + OverflowMenuGroup, + OverflowMenuItem, + PageSection +} from '@patternfly/react-core'; +import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table'; +import { rows, columns } from '../../examples/Data.jsx'; +import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; +import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'; +import EditIcon from '@patternfly/react-icons/dist/esm/icons/edit-icon'; +import SyncIcon from '@patternfly/react-icons/dist/esm/icons/sync-icon'; +import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon'; +import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon'; +import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; +import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; + +export const ComposableTableSortable = () => { + const [isKebabDropdownOpen, setIsKebabDropdownOpen] = React.useState(false); + + const sortRows = (r, sortIndex, sortDirection) => { + return [...r].sort((a, b) => { + let returnValue = 0; + if (sortIndex === 0 || sortIndex === 7) { + returnValue = 1 + } else if (typeof Object.values(a)[sortIndex] === 'number') { + // numeric sort + returnValue = Object.values(a)[sortIndex] - Object.values(b)[sortIndex]; + } else { + // string sort + returnValue = Object.values(a)[sortIndex].localeCompare(Object.values(b)[sortIndex]); + } + if (sortDirection === 'desc') { + return returnValue * -1; + } + return returnValue; + }) + }; + +const [sortedData, setSortedData] = React.useState([ + ...sortRows(rows, 0, 'asc') + ]); +const [sortedRows, setSortedRows] = React.useState([ + ...sortedData + ]); + const [page, setPage] = React.useState(1); + const [perPage, setPerPage] = React.useState(10); + + // index of the currently active column + const [activeSortIndex, setActiveSortIndex] = React.useState(0); + // sort direction of the currently active column + const [activeSortDirection, setActiveSortDirection] = React.useState('asc'); + // sort dropdown expansion + const [isSortDropdownOpen, setIsSortDropdownOpen] = React.useState(false); + + const onSort = (event, index, direction) => { + setActiveSortIndex(index); + setActiveSortDirection(direction); + + setSortedData(sortRows(rows, index, direction)); + }; + + const kebabDropdownItems = [Some action]; + + React.useEffect(() => { + setSortedRows(sortedData.slice((page - 1) * perPage, page * perPage -1)); + }, [sortedData, page, perPage]); + + const handleSetPage = (_evt, newPage) => { + setPage(newPage); + } + + const handlePerPageSelect = (_evt, newPerPage) => { + setPerPage(newPerPage); + } + + renderPagination = (variant) => ( + + ); + + const renderLabel = labelText => { + switch (labelText) { + case 'Running': + return {labelText}; + case 'Stopped': + return {labelText}; + case 'Needs Maintenance': + return {labelText}; + case 'Down': + return {labelText}; + } + }; + + const tableToolbar = ( + + + + + {columns.map((column, columnIndex) => ( + + onSort(evt, columnIndex, activeSortDirection !== 'none' ? activeSortDirection : 'asc') + } + > + {column} + + ))} + , + , + + onSort(evt, activeSortIndex, 'asc')} + isSelected={activeSortDirection === 'asc'} + id="ascending" + key="ascending" + > + Ascending + + onSort(evt, activeSortIndex, 'desc')} + isSelected={activeSortDirection === 'desc'} + id="descending" + key="descending" + > + Descending + + + ]} + isOpen={isSortDropdownOpen} + toggle={ + setIsSortDropdownOpen(!isSortDropdownOpen)} + toggleTemplate={} + /> + } + isPlain + isGrouped + menuAppendTo="parent" + isFlipEnabled + /> + + + + + + Create instance + + + Action + + + + + setIsKebabDropdownOpen(!isKebabDropdownOpen)} + toggle={ setIsKebabDropdownOpen(!isKebabDropdownOpen)} />} + isOpen={isKebabDropdownOpen} + dropdownItems={kebabDropdownItems} + isFlipEnabled + menuAppendTo="parent" + /> + + + + + } /> + + + } /> + + + } /> + + + {renderPagination('top', true)} + + + ); + + return ( + + + + + Table demos + + Below is an example of a responsive sortable table. When the screen size shrinks the table into a compact + form, the toolbar will display a dropdown menu containing sorting options. + + + + + + {tableToolbar} + + + + {columns.map((column, columnIndex) => { + const sortParams = { + sort: { + sortBy: { + index: activeSortIndex, + direction: activeSortDirection + }, + onSort, + columnIndex + } + }; + return ( + + {column} + + ); + })} + + + + {sortedRows.map((row, rowIndex) => ( + + <> + + {row.name} + + + + + + + {row.threads} + + + + + + + + {row.applications} + + + + + + + + {row.workspaces} + + + + + {renderLabel(row.status)} + + + + + {row.location} + + + + + {row.lastModified[0]} days ago + + + {row.url} + > + + ))} + + + {renderPagination('bottom', false)} + + + + + ); +};