diff --git a/packages/datagateway-common/src/api/index.tsx b/packages/datagateway-common/src/api/index.tsx index 8c61ee671..801dcf6c9 100644 --- a/packages/datagateway-common/src/api/index.tsx +++ b/packages/datagateway-common/src/api/index.tsx @@ -260,7 +260,8 @@ export const getApiParams = ( export const useSort = (): (( sortKey: string, order: Order | null, - updateMethod: UpdateMethod + updateMethod: UpdateMethod, + shiftDown?: boolean ) => void) => { const { push, replace } = useHistory(); @@ -268,17 +269,26 @@ export const useSort = (): (( ( sortKey: string, order: Order | null, - updateMethod: UpdateMethod + updateMethod: UpdateMethod, + shiftDown?: boolean ): void => { let query = parseSearchToQuery(window.location.search); + console.log(query); if (order !== null) { - query = { - ...query, - sort: { - ...query.sort, - [sortKey]: order, - }, - }; + query = shiftDown + ? { + ...query, + sort: { + ...query.sort, + [sortKey]: order, + }, + } + : { + ...query, + sort: { + [sortKey]: order, + }, + }; } else { // if order is null, user no longer wants to sort by that column so remove column from sort state const { [sortKey]: order, ...rest } = query.sort; diff --git a/packages/datagateway-common/src/table/headerRenderers/dataHeader.component.tsx b/packages/datagateway-common/src/table/headerRenderers/dataHeader.component.tsx index fafa07dcb..c25203558 100644 --- a/packages/datagateway-common/src/table/headerRenderers/dataHeader.component.tsx +++ b/packages/datagateway-common/src/table/headerRenderers/dataHeader.component.tsx @@ -10,6 +10,9 @@ import { SxProps, } from '@mui/material'; import Draggable from 'react-draggable'; +import SortIcon from '@mui/icons-material/Sort'; +import AddIcon from '@mui/icons-material/Add'; +import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; const DataHeader = React.memo( ( @@ -19,13 +22,15 @@ const DataHeader = React.memo( onSort: ( column: string, order: Order | null, - defaultSort: UpdateMethod + defaultSort: UpdateMethod, + shiftDown?: boolean ) => void; resizeColumn: (dataKey: string, deltaX: number) => void; labelString: string; icon?: React.ComponentType; filterComponent?: (label: string, dataKey: string) => React.ReactElement; defaultSort?: Order; + shiftDown?: boolean; } ): React.ReactElement => { const { @@ -40,15 +45,18 @@ const DataHeader = React.memo( resizeColumn, icon: Icon, filterComponent, + shiftDown, } = props; const currSortDirection = sort[dataKey]; + const [hover, setHover] = React.useState(false); + //Apply default sort on page load (but only if not already defined in URL params) //This will apply them in the order of the column definitions given to a table React.useEffect(() => { if (defaultSort !== undefined && currSortDirection === undefined) - onSort(dataKey, defaultSort, 'replace'); + onSort(dataKey, defaultSort, 'replace', false); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -65,16 +73,45 @@ const DataHeader = React.memo( } const inner = !disableSort ? ( - onSort(dataKey, nextSortDirection, 'push')} - > - - {label} - - + dataKey in sort ? ( + + onSort(dataKey, nextSortDirection, 'replace', shiftDown) + } + > + + {label} + + + ) : ( + { + onSort(dataKey, nextSortDirection, 'replace', shiftDown); + setHover(false); + }} + onMouseEnter={() => setHover(true)} + onMouseLeave={() => setHover(false)} + IconComponent={ + hover ? ArrowUpwardIcon : shiftDown ? AddIcon : SortIcon + } + > + + {label} + + + ) ) : ( {label} diff --git a/packages/datagateway-common/src/table/table.component.tsx b/packages/datagateway-common/src/table/table.component.tsx index 5c5d3d9da..d762f492a 100644 --- a/packages/datagateway-common/src/table/table.component.tsx +++ b/packages/datagateway-common/src/table/table.component.tsx @@ -123,7 +123,8 @@ interface VirtualizedTableProps { onSort: ( column: string, order: Order | null, - updateMethod: UpdateMethod + updateMethod: UpdateMethod, + shiftDown?: boolean ) => void; detailsPanel?: React.ComponentType; actions?: React.ComponentType[]; @@ -163,6 +164,30 @@ const VirtualizedTable = React.memo( disableSelectAll, } = props; + const [shiftDown, setShiftDown] = React.useState(false); + // add event listener to listen for shift key being pressed + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent): void => { + if (event.key === 'Shift') { + setShiftDown(true); + } + }; + + const handleKeyUp = (event: KeyboardEvent): void => { + if (event.key === 'Shift') { + setShiftDown(false); + } + }; + + document.addEventListener('keydown', handleKeyDown); + document.addEventListener('keyup', handleKeyUp); + + return (): void => { + document.removeEventListener('keydown', handleKeyDown); + document.removeEventListener('keyup', handleKeyUp); + }; + }, []); + if ( (props.loadMoreRows && typeof totalRowCount === 'undefined') || (totalRowCount && typeof props.loadMoreRows === 'undefined') @@ -452,6 +477,7 @@ const VirtualizedTable = React.memo( filterComponent={filterComponent} resizeColumn={resizeColumn} defaultSort={defaultSort} + shiftDown={shiftDown} /> )} className={className}