diff --git a/src/components/views/settings/devices/FilteredDeviceList.tsx b/src/components/views/settings/devices/FilteredDeviceList.tsx index be56f92810ba..757f0fda4f5b 100644 --- a/src/components/views/settings/devices/FilteredDeviceList.tsx +++ b/src/components/views/settings/devices/FilteredDeviceList.tsx @@ -14,43 +14,39 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import DeviceTile from './DeviceTile'; import { DevicesDictionary, DeviceWithVerification } from './useOwnDevices'; -export enum DeviceSortOrder { - LatestActivity = 'LatestActivity', -} - interface Props { devices: DevicesDictionary; } +// devices without timestamp metadata should be sorted last const sortDevicesByLatestActivity = (left: DeviceWithVerification, right: DeviceWithVerification) => - left.last_seen_ts - right.last_seen_ts; + (right.last_seen_ts || 0) - (left.last_seen_ts || 0); -const getSortedDeviceIds = (devices: DevicesDictionary) => - Object.values(devices).sort(sortDevicesByLatestActivity).map(device => device.device_id); +const getSortedDevices = (devices: DevicesDictionary) => + Object.values(devices).sort(sortDevicesByLatestActivity); +/** + * Filtered list of devices + * Sorted by latest activity descending + * TODO(kerrya) Filtering to added as part of PSG-648 + */ const FilteredDeviceList: React.FC = ({ devices }) => { - const [sortedIds, setSortedIds] = useState([]); - - useEffect(() => { - setSortedIds(getSortedDeviceIds(devices)); - }, [devices]); + const sortedDevices = getSortedDevices(devices); return
    - { sortedIds.map((deviceId) => -
  1. - - -
  2. - - )} + { sortedDevices.map((device) => +
  3. + +
  4. , + + ) }
; }; diff --git a/src/components/views/settings/tabs/user/SessionManagerTab.tsx b/src/components/views/settings/tabs/user/SessionManagerTab.tsx index c7432f104ef0..fcd519eee52a 100644 --- a/src/components/views/settings/tabs/user/SessionManagerTab.tsx +++ b/src/components/views/settings/tabs/user/SessionManagerTab.tsx @@ -22,13 +22,13 @@ import { useOwnDevices } from '../../devices/useOwnDevices'; import DeviceTile from '../../devices/DeviceTile'; import SettingsSubsection from '../../shared/SettingsSubsection'; import SettingsTab from '../SettingsTab'; -import FilteredDeviceList, { DeviceSortOrder } from '../../devices/FilteredDeviceList'; +import FilteredDeviceList from '../../devices/FilteredDeviceList'; const SessionManagerTab: React.FC = () => { const { devices, currentDeviceId, isLoading } = useOwnDevices(); - const currentDevice = devices[currentDeviceId]; - const shouldShowOtherSessions = Object.keys(devices).length > 1; + const { [currentDeviceId]: currentDevice, ...otherDevices } = devices; + const shouldShowOtherSessions = Object.keys(otherDevices).length > 0; return { - + } ; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index fd364f4aef47..fe18f6af3475 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1565,7 +1565,7 @@ "Sessions": "Sessions", "Current session": "Current session", "Other sessions": "Other sessions", - "For best security, verify your sessions and sign outfrom any session that you don't recognize or use anymore.": "For best security, verify your sessions and sign outfrom any session that you don't recognize or use anymore.", + "For best security, verify your sessions and sign out from any session that you don't recognize or use anymore.": "For best security, verify your sessions and sign out from any session that you don't recognize or use anymore.", "Sidebar": "Sidebar", "Spaces to show": "Spaces to show", "Spaces are ways to group rooms and people. Alongside the spaces you're in, you can use some pre-built ones too.": "Spaces are ways to group rooms and people. Alongside the spaces you're in, you can use some pre-built ones too.", diff --git a/test/components/views/settings/devices/FilteredDeviceList-test.tsx b/test/components/views/settings/devices/FilteredDeviceList-test.tsx index e6cef123bdff..3545e0b261a7 100644 --- a/test/components/views/settings/devices/FilteredDeviceList-test.tsx +++ b/test/components/views/settings/devices/FilteredDeviceList-test.tsx @@ -15,17 +15,51 @@ limitations under the License. */ import React from 'react'; -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import FilteredDeviceList from '../../../../../src/components/views/settings/devices/FilteredDeviceList'; describe('', () => { - const defaultProps = {}; + const noMetaDevice = { device_id: 'no-meta-device', isVerified: true }; + const oldDevice = { device_id: 'old', last_seen_ts: new Date(1993, 7, 3, 4).getTime(), isVerified: true }; + const newDevice = { + device_id: 'new', + last_seen_ts: new Date().getTime() - 500, + last_seen_ip: '123.456.789', + display_name: 'My Device', + isVerified: true, + }; + const defaultProps = { + devices: { + [noMetaDevice.device_id]: noMetaDevice, + [oldDevice.device_id]: oldDevice, + [newDevice.device_id]: newDevice, + }, + }; const getComponent = (props = {}) => - mount(); + (); - it('renders', () => { - const component = getComponent(); - expect(component).toBeTruthy(); + it('renders devices in correct order', () => { + const { container } = render(getComponent()); + const tiles = container.querySelectorAll('.mx_DeviceTile'); + expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.device_id}`); + expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${oldDevice.device_id}`); + expect(tiles[2].getAttribute('data-testid')).toEqual(`device-tile-${noMetaDevice.device_id}`); + }); + + it('updates list order when devices change', () => { + const updatedOldDevice = { ...oldDevice, last_seen_ts: new Date().getTime() }; + const updatedDevices = { + [oldDevice.device_id]: updatedOldDevice, + [newDevice.device_id]: newDevice, + }; + const { container, rerender } = render(getComponent()); + + rerender(getComponent({ devices: updatedDevices })); + + const tiles = container.querySelectorAll('.mx_DeviceTile'); + expect(tiles.length).toBe(2); + expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${oldDevice.device_id}`); + expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.device_id}`); }); });