diff --git a/frontend/src/js/components/auditlogs/__snapshots__/auditlogs.test.js.snap b/frontend/src/js/components/auditlogs/__snapshots__/auditlogs.test.js.snap index 5005824c..fa5f2321 100644 --- a/frontend/src/js/components/auditlogs/__snapshots__/auditlogs.test.js.snap +++ b/frontend/src/js/components/auditlogs/__snapshots__/auditlogs.test.js.snap @@ -346,43 +346,39 @@ exports[`Auditlogs Component renders correctly 1`] = ` >
Performed by
Action
Type
Changed
More details
Time
Performed by
Action
Type
Changed
More details
Time
{auditLogColumns.map((column, index) => (
(column.sortable ? onChangeSorting() : null)} - style={column.sortable ? {} : { cursor: 'initial' }} > {column.title} - {column.sortable ? : null} + {column.sortable && }
))}
diff --git a/frontend/src/js/components/common/detailstable.js b/frontend/src/js/components/common/detailstable.js index 40557675..8ac5cdf9 100644 --- a/frontend/src/js/components/common/detailstable.js +++ b/frontend/src/js/components/common/detailstable.js @@ -11,14 +11,16 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react'; +import React, { useEffect, useState } from 'react'; // material ui -import { Sort as SortIcon } from '@mui/icons-material'; import { Checkbox, Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material'; import { makeStyles } from 'tss-react/mui'; -import { SORTING_OPTIONS } from '@northern.tech/store/constants'; +import { SORTING_OPTIONS, SORT_DIRECTIONS, TIMEOUTS } from '@northern.tech/store/constants'; + +import { useDebounce } from '../../utils/debouncehook'; +import SortIcon from './sorticon'; const useStyles = makeStyles()(() => ({ header: { @@ -32,16 +34,50 @@ const useStyles = makeStyles()(() => ({ } })); +const HeaderItem = ({ columnKey, hasMultiSort, extras, renderTitle, sortable, onSort, sortOptions, title }) => { + const { direction, key: sortKey } = sortOptions.find(({ key: sortKey }) => columnKey === sortKey) ?? {}; + const [sortState, setSortState] = useState({ disabled: !sortKey, direction }); + const [resetDirection] = useState(hasMultiSort ? '' : SORT_DIRECTIONS[0]); + + const debouncedSortState = useDebounce(sortState, TIMEOUTS.debounceShort); + + useEffect(() => { + if (!onSort) { + return; + } + onSort({ key: columnKey, direction: debouncedSortState.direction, disabled: debouncedSortState.disabled }); + }, [columnKey, debouncedSortState.direction, debouncedSortState.disabled, onSort]); + + const onSortClick = () => { + if (!sortable) { + return; + } + const nextDirectionIndex = SORT_DIRECTIONS.indexOf(sortState.direction) + 1; + const direction = SORT_DIRECTIONS[nextDirectionIndex] ?? resetDirection; + setSortState({ direction, disabled: !direction }); + }; + + const sortDown = sortKey && direction === SORTING_OPTIONS.desc; + + return ( + + {renderTitle ? renderTitle(extras) : title} + {sortable && } + + ); +}; + export const DetailsTable = ({ className = '', columns, + hasMultiSort = false, items, onChangeSorting, onItemClick, - sort = {}, + sort = [], style = {}, tableRef, - onRowSelected = undefined, + onRowSelected, selectedRows = [] }) => { const { classes } = useStyles(); @@ -69,23 +105,20 @@ export const DetailsTable = ({ - {onRowSelected !== undefined && ( + {!!onRowSelected && ( )} - {columns.map(({ extras, key, renderTitle, sortable, title }) => ( - (sortable ? onChangeSorting(key) : null)}> - {renderTitle ? renderTitle(extras) : title} - {sortable && } - + {columns.map(column => ( + ))} {items.map((item, index) => ( - {onRowSelected !== undefined && ( + {onRowSelected && ( onRowSelection(index)} /> diff --git a/frontend/src/js/components/common/sorticon.js b/frontend/src/js/components/common/sorticon.js new file mode 100644 index 00000000..0bcbbad6 --- /dev/null +++ b/frontend/src/js/components/common/sorticon.js @@ -0,0 +1,39 @@ +// Copyright 2024 Northern.tech AS +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import React, { useEffect, useRef, useState } from 'react'; + +// material ui +import { Sort } from '@mui/icons-material'; + +import { TIMEOUTS } from '@northern.tech/store/commonConstants'; + +const SortIcon = ({ columnKey, disabled = false, sortDown = false }) => { + const timer = useRef(); + const [fadeIcon, setFadeIcon] = useState(true); + + useEffect(() => { + if (disabled) { + timer.current = setTimeout(() => setFadeIcon(true), TIMEOUTS.oneSecond); + } else { + timer.current = setTimeout(() => setFadeIcon(false), TIMEOUTS.debounceShort); + } + return () => { + clearTimeout(timer.current); + }; + }, [disabled]); + + return ; +}; + +export default SortIcon; diff --git a/frontend/src/js/components/devices/__snapshots__/device-groups.test.js.snap b/frontend/src/js/components/devices/__snapshots__/device-groups.test.js.snap index 300f1459..c27f09fd 100644 --- a/frontend/src/js/components/devices/__snapshots__/device-groups.test.js.snap +++ b/frontend/src/js/components/devices/__snapshots__/device-groups.test.js.snap @@ -381,7 +381,7 @@ exports[`DeviceGroups Component renders correctly 1`] = `