Device manager - add foundation for extended device info (#9344)

* record device client inforamtion events on app start

* matrix-client-information -> matrix_client_information

* fix types

* remove another unused export

* add docs link

* display device client information in device details

* update snapshots

* integration-ish test client information in metadata

* tests

* fix tests

* export helper

* DeviceClientInformation type

* Device manager - select all devices (#9330)

* add device selection that does nothing

* multi select and sign out of sessions

* test multiple selection

* fix type after rebase

* select all sessions

* rename type

* use ExtendedDevice type everywhere

* rename clientName to appName for less collision with UA parser

* fix bad find and replace

* rename ExtendedDeviceInfo to ExtendedDeviceAppInfo

* rename DeviceType comp to DeviceTypeIcon

* update tests for new required property deviceType

* add stubbed user agent parsing
This commit is contained in:
Kerry 2022-10-05 13:41:01 +02:00 committed by GitHub
parent 1032334b20
commit bd270b08df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 319 additions and 187 deletions

View file

@ -112,16 +112,16 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
data-testid="device-tile-device_1"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -235,16 +235,16 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
data-testid="device-tile-device_2"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -317,16 +317,16 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
data-testid="device-tile-device_3"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>

View file

@ -19,6 +19,7 @@ import { fireEvent, render } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import CurrentDeviceSection from '../../../../../src/components/views/settings/devices/CurrentDeviceSection';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
describe('<CurrentDeviceSection />', () => {
const deviceId = 'alices_device';
@ -26,10 +27,12 @@ describe('<CurrentDeviceSection />', () => {
const alicesVerifiedDevice = {
device_id: deviceId,
isVerified: false,
deviceType: DeviceType.Unknown,
};
const alicesUnverifiedDevice = {
device_id: deviceId,
isVerified: false,
deviceType: DeviceType.Unknown,
};
const defaultProps = {

View file

@ -19,6 +19,7 @@ import { fireEvent, render, RenderResult } from '@testing-library/react';
import { DeviceDetailHeading } from '../../../../../src/components/views/settings/devices/DeviceDetailHeading';
import { flushPromisesWithFakeTimers } from '../../../../test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
jest.useFakeTimers();
@ -27,6 +28,7 @@ describe('<DeviceDetailHeading />', () => {
device_id: '123',
display_name: 'My device',
isVerified: true,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
device,

View file

@ -20,11 +20,13 @@ import { PUSHER_ENABLED } from 'matrix-js-sdk/src/@types/event';
import DeviceDetails from '../../../../../src/components/views/settings/devices/DeviceDetails';
import { mkPusher } from '../../../../test-utils/test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
describe('<DeviceDetails />', () => {
const baseDevice = {
device_id: 'my-device',
isVerified: false,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
device: baseDevice,
@ -58,7 +60,7 @@ describe('<DeviceDetails />', () => {
display_name: 'My Device',
last_seen_ip: '123.456.789',
last_seen_ts: now - 60000000,
clientName: 'Element Web',
appName: 'Element Web',
};
const { container } = render(getComponent({ device }));
expect(container).toMatchSnapshot();

View file

@ -19,12 +19,14 @@ import { render } from '@testing-library/react';
import { IMyDevice } from 'matrix-js-sdk/src/matrix';
import DeviceTile from '../../../../../src/components/views/settings/devices/DeviceTile';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
describe('<DeviceTile />', () => {
const defaultProps = {
device: {
device_id: '123',
isVerified: false,
deviceType: DeviceType.Unknown,
},
};
const getComponent = (props = {}) => (

View file

@ -17,15 +17,15 @@ limitations under the License.
import { render } from '@testing-library/react';
import React from 'react';
import { DeviceType } from '../../../../../src/components/views/settings/devices/DeviceType';
import { DeviceTypeIcon } from '../../../../../src/components/views/settings/devices/DeviceTypeIcon';
describe('<DeviceType />', () => {
describe('<DeviceTypeIcon />', () => {
const defaultProps = {
isVerified: false,
isSelected: false,
};
const getComponent = (props = {}) =>
<DeviceType {...defaultProps} {...props} />;
<DeviceTypeIcon {...defaultProps} {...props} />;
it('renders an unverified device', () => {
const { container } = render(getComponent());

View file

@ -20,6 +20,7 @@ import { act, fireEvent, render } from '@testing-library/react';
import { FilteredDeviceList } from '../../../../../src/components/views/settings/devices/FilteredDeviceList';
import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/types';
import { flushPromises, mockPlatformPeg } from '../../../../test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
mockPlatformPeg();
@ -31,14 +32,26 @@ describe('<FilteredDeviceList />', () => {
last_seen_ip: '123.456.789',
display_name: 'My Device',
isVerified: true,
deviceType: DeviceType.Unknown,
};
const unverifiedNoMetadata = { device_id: 'unverified-no-metadata', isVerified: false };
const verifiedNoMetadata = { device_id: 'verified-no-metadata', isVerified: true };
const hundredDaysOld = { device_id: '100-days-old', isVerified: true, last_seen_ts: Date.now() - (MS_DAY * 100) };
const unverifiedNoMetadata = {
device_id: 'unverified-no-metadata',
isVerified: false,
deviceType: DeviceType.Unknown };
const verifiedNoMetadata = {
device_id: 'verified-no-metadata',
isVerified: true,
deviceType: DeviceType.Unknown };
const hundredDaysOld = {
device_id: '100-days-old',
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 100),
deviceType: DeviceType.Unknown };
const hundredDaysOldUnverified = {
device_id: 'unverified-100-days-old',
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
deviceType: DeviceType.Unknown,
};
const defaultProps = {
onFilterChange: jest.fn(),

View file

@ -19,6 +19,7 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import SelectableDeviceTile from '../../../../../src/components/views/settings/devices/SelectableDeviceTile';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
describe('<SelectableDeviceTile />', () => {
const device = {
@ -26,6 +27,7 @@ describe('<SelectableDeviceTile />', () => {
device_id: 'my-device',
last_seen_ip: '123.456.789',
isVerified: false,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
onClick: jest.fn(),

View file

@ -151,16 +151,16 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
data-testid="device-tile-alices_device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -267,16 +267,16 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
data-testid="device-tile-alices_device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>

View file

@ -7,16 +7,16 @@ exports[`<DeviceTile /> renders a device with no metadata 1`] = `
data-testid="device-tile-123"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -58,16 +58,16 @@ exports[`<DeviceTile /> renders a verified device with no metadata 1`] = `
data-testid="device-tile-123"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -109,16 +109,16 @@ exports[`<DeviceTile /> renders display name with a tooltip 1`] = `
data-testid="device-tile-123"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -160,16 +160,16 @@ exports[`<DeviceTile /> separates metadata with a dot 1`] = `
data-testid="device-tile-123"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>

View file

@ -1,58 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<DeviceType /> renders a verified device 1`] = `
<div>
<div
class="mx_DeviceType"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
role="img"
/>
<div
aria-label="Verified"
class="mx_DeviceType_verificationIcon verified"
role="img"
/>
</div>
</div>
`;
exports[`<DeviceType /> renders an unverified device 1`] = `
<div>
<div
class="mx_DeviceType"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
role="img"
/>
</div>
</div>
`;
exports[`<DeviceType /> renders correctly when selected 1`] = `
<div>
<div
class="mx_DeviceType mx_DeviceType_selected"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
role="img"
/>
</div>
</div>
`;

View file

@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<DeviceTypeIcon /> renders a verified device 1`] = `
<div>
<div
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
role="img"
/>
</div>
</div>
`;
exports[`<DeviceTypeIcon /> renders an unverified device 1`] = `
<div>
<div
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
</div>
`;
exports[`<DeviceTypeIcon /> renders correctly when selected 1`] = `
<div>
<div
class="mx_DeviceTypeIcon mx_DeviceTypeIcon_selected"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
</div>
`;

View file

@ -39,16 +39,16 @@ exports[`<SelectableDeviceTile /> renders unselected device tile with checkbox 1
data-testid="device-tile-my-device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>

View file

@ -20,18 +20,38 @@ import {
import {
DeviceSecurityVariation,
} from "../../../../../src/components/views/settings/devices/types";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
const MS_DAY = 86400000;
describe('filterDevicesBySecurityRecommendation()', () => {
const unverifiedNoMetadata = { device_id: 'unverified-no-metadata', isVerified: false };
const verifiedNoMetadata = { device_id: 'verified-no-metadata', isVerified: true };
const hundredDaysOld = { device_id: '100-days-old', isVerified: true, last_seen_ts: Date.now() - (MS_DAY * 100) };
const unverifiedNoMetadata = {
device_id: 'unverified-no-metadata',
isVerified: false,
deviceType: DeviceType.Unknown,
};
const verifiedNoMetadata = {
device_id: 'verified-no-metadata',
isVerified: true,
deviceType: DeviceType.Unknown,
};
const hundredDaysOld = {
device_id: '100-days-old',
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 100),
deviceType: DeviceType.Unknown,
};
const hundredDaysOldUnverified = {
device_id: 'unverified-100-days-old',
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
deviceType: DeviceType.Unknown,
};
const fiftyDaysOld = {
device_id: '50-days-old',
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 50),
deviceType: DeviceType.Unknown,
};
const fiftyDaysOld = { device_id: '50-days-old', isVerified: true, last_seen_ts: Date.now() - (MS_DAY * 50) };
const devices = [
unverifiedNoMetadata,

View file

@ -44,7 +44,7 @@ import Modal from '../../../../../../src/Modal';
import LogoutDialog from '../../../../../../src/components/views/dialogs/LogoutDialog';
import {
DeviceSecurityVariation,
DeviceWithVerification,
ExtendedDevice,
} from '../../../../../../src/components/views/settings/devices/types';
import { INACTIVE_DEVICE_AGE_MS } from '../../../../../../src/components/views/settings/devices/filter';
@ -104,7 +104,7 @@ describe('<SessionManagerTab />', () => {
const toggleDeviceDetails = (
getByTestId: ReturnType<typeof render>['getByTestId'],
deviceId: DeviceWithVerification['device_id'],
deviceId: ExtendedDevice['device_id'],
) => {
// open device detail
const tile = getByTestId(`device-tile-${deviceId}`);
@ -114,7 +114,7 @@ describe('<SessionManagerTab />', () => {
const toggleDeviceSelection = (
getByTestId: ReturnType<typeof render>['getByTestId'],
deviceId: DeviceWithVerification['device_id'],
deviceId: ExtendedDevice['device_id'],
) => {
const checkbox = getByTestId(`device-tile-checkbox-${deviceId}`);
fireEvent.click(checkbox);
@ -135,7 +135,7 @@ describe('<SessionManagerTab />', () => {
const isDeviceSelected = (
getByTestId: ReturnType<typeof render>['getByTestId'],
deviceId: DeviceWithVerification['device_id'],
deviceId: ExtendedDevice['device_id'],
): boolean => !!(getByTestId(`device-tile-checkbox-${deviceId}`) as HTMLInputElement).checked;
const isSelectAllChecked = (

View file

@ -94,16 +94,16 @@ exports[`<SessionManagerTab /> renders current session section with a verified s
data-testid="device-tile-alices_device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Verified"
class="mx_DeviceType_verificationIcon verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
role="img"
/>
</div>
@ -196,16 +196,16 @@ exports[`<SessionManagerTab /> renders current session section with an unverifie
data-testid="device-tile-alices_device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Unverified"
class="mx_DeviceType_verificationIcon unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
@ -298,16 +298,16 @@ exports[`<SessionManagerTab /> sets device verification status correctly 1`] = `
data-testid="device-tile-alices_device"
>
<div
class="mx_DeviceType"
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceType_deviceIcon"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
<div
aria-label="Verified"
class="mx_DeviceType_verificationIcon verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
role="img"
/>
</div>