Device manager - device type icon (#9355)

* 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

* add icons

* set device type icon

* device type icon tets

* update snapshots for device type icon changes

* desktop icon viewbox

* i18n
pull/28217/head
Kerry 2022-10-06 12:34:11 +02:00 committed by GitHub
parent 8399b63e7a
commit 5e18abe7f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 222 additions and 90 deletions

View File

@ -22,7 +22,7 @@ limitations under the License.
padding: 0 $spacing-8 $spacing-8 0;
}
.mx_DeviceTypeIcon_deviceIcon {
.mx_DeviceTypeIcon_deviceIconWrapper {
--background-color: $system;
--icon-color: $secondary-content;
@ -36,11 +36,16 @@ limitations under the License.
background-color: var(--background-color);
}
.mx_DeviceTypeIcon_selected .mx_DeviceTypeIcon_deviceIcon {
.mx_DeviceTypeIcon_selected .mx_DeviceTypeIcon_deviceIconWrapper {
--background-color: $primary-content;
--icon-color: $background;
}
.mx_DeviceTypeIcon_deviceIcon {
height: 24px;
width: 24px;
}
.mx_DeviceTypeIcon_verificationIcon {
position: absolute;
bottom: 0;

View File

@ -0,0 +1,3 @@
<svg width="22" height="19" viewBox="0 0 22 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 15.5C2.45 15.5 1.97933 15.3043 1.588 14.913C1.196 14.521 1 14.05 1 13.5V2.5C1 1.95 1.196 1.479 1.588 1.087C1.97933 0.695667 2.45 0.5 3 0.5H19C19.55 0.5 20.021 0.695667 20.413 1.087C20.8043 1.479 21 1.95 21 2.5V13.5C21 14.05 20.8043 14.521 20.413 14.913C20.021 15.3043 19.55 15.5 19 15.5H3ZM3 13.5H19V2.5H3V13.5ZM1 18.5C0.716667 18.5 0.479333 18.404 0.288 18.212C0.096 18.0207 0 17.7833 0 17.5C0 17.2167 0.096 16.9793 0.288 16.788C0.479333 16.596 0.716667 16.5 1 16.5H21C21.2833 16.5 21.5207 16.596 21.712 16.788C21.904 16.9793 22 17.2167 22 17.5C22 17.7833 21.904 18.0207 21.712 18.212C21.5207 18.404 21.2833 18.5 21 18.5H1ZM3 13.5V2.5V13.5Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 780 B

View File

@ -0,0 +1,3 @@
<svg width="14" height="23" viewBox="0 0 14 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 0.51L2 0.5C0.9 0.5 0 1.4 0 2.5V20.5C0 21.6 0.9 22.5 2 22.5H12C13.1 22.5 14 21.6 14 20.5V2.5C14 1.4 13.1 0.51 12 0.51ZM12 18.5H2V4.5H12V18.5Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 280 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 16.5H2C1.45 16.5 0.979333 16.3043 0.588 15.913C0.196 15.521 0 15.05 0 14.5V2.5C0 1.95 0.196 1.47933 0.588 1.088C0.979333 0.696 1.45 0.5 2 0.5H18C18.55 0.5 19.021 0.696 19.413 1.088C19.8043 1.47933 20 1.95 20 2.5V14.5C20 15.05 19.8043 15.521 19.413 15.913C19.021 16.3043 18.55 16.5 18 16.5ZM2 4.5V14.5H18V4.5H2Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B

View File

@ -18,6 +18,9 @@ import React from 'react';
import classNames from 'classnames';
import { Icon as UnknownDeviceIcon } from '../../../../../res/img/element-icons/settings/unknown-device.svg';
import { Icon as DesktopIcon } from '../../../../../res/img/element-icons/settings/desktop.svg';
import { Icon as WebIcon } from '../../../../../res/img/element-icons/settings/web.svg';
import { Icon as MobileIcon } from '../../../../../res/img/element-icons/settings/mobile.svg';
import { Icon as VerifiedIcon } from '../../../../../res/img/e2e/verified.svg';
import { Icon as UnverifiedIcon } from '../../../../../res/img/e2e/warning.svg';
import { _t } from '../../../../languageHandler';
@ -30,33 +33,51 @@ interface Props {
deviceType?: DeviceType;
}
const deviceTypeIcon: Record<DeviceType, React.FC<React.SVGProps<SVGSVGElement>>> = {
[DeviceType.Desktop]: DesktopIcon,
[DeviceType.Mobile]: MobileIcon,
[DeviceType.Web]: WebIcon,
[DeviceType.Unknown]: UnknownDeviceIcon,
};
const deviceTypeLabel: Record<DeviceType, string> = {
[DeviceType.Desktop]: _t('Desktop session'),
[DeviceType.Mobile]: _t('Mobile session'),
[DeviceType.Web]: _t('Web session'),
[DeviceType.Unknown]: _t('Unknown session type'),
};
export const DeviceTypeIcon: React.FC<Props> = ({
isVerified,
isSelected,
deviceType,
}) => (
<div className={classNames('mx_DeviceTypeIcon', {
mx_DeviceTypeIcon_selected: isSelected,
})}
>
{ /* TODO(kerrya) all devices have an unknown type until PSG-650 */ }
<UnknownDeviceIcon
className='mx_DeviceTypeIcon_deviceIcon'
role='img'
aria-label={_t('Unknown device type')}
/>
{
isVerified
? <VerifiedIcon
className={classNames('mx_DeviceTypeIcon_verificationIcon', 'verified')}
}) => {
const Icon = deviceTypeIcon[deviceType] || deviceTypeIcon[DeviceType.Unknown];
const label = deviceTypeLabel[deviceType] || deviceTypeLabel[DeviceType.Unknown];
return (
<div className={classNames('mx_DeviceTypeIcon', {
mx_DeviceTypeIcon_selected: isSelected,
})}
>
<div className='mx_DeviceTypeIcon_deviceIconWrapper'>
<Icon
className='mx_DeviceTypeIcon_deviceIcon'
role='img'
aria-label={_t('Verified')}
aria-label={label}
/>
: <UnverifiedIcon
className={classNames('mx_DeviceTypeIcon_verificationIcon', 'unverified')}
role='img'
aria-label={_t('Unverified')}
/>
}
</div>);
</div>
{
isVerified
? <VerifiedIcon
className={classNames('mx_DeviceTypeIcon_verificationIcon', 'verified')}
role='img'
aria-label={_t('Verified')}
/>
: <UnverifiedIcon
className={classNames('mx_DeviceTypeIcon_verificationIcon', 'unverified')}
role='img'
aria-label={_t('Unverified')}
/>
}
</div>);
};

View File

@ -1729,7 +1729,10 @@
"Inactive for %(inactiveAgeDays)s+ days": "Inactive for %(inactiveAgeDays)s+ days",
"Verified": "Verified",
"Unverified": "Unverified",
"Unknown device type": "Unknown device type",
"Desktop session": "Desktop session",
"Mobile session": "Mobile session",
"Web session": "Web session",
"Unknown session type": "Unknown session type",
"Verified session": "Verified session",
"This session is ready for secure messaging.": "This session is ready for secure messaging.",
"Unverified session": "Unverified session",

View File

@ -115,10 +115,14 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -238,10 +242,14 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -320,10 +328,14 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"

View File

@ -18,6 +18,7 @@ import { render } from '@testing-library/react';
import React from 'react';
import { DeviceTypeIcon } from '../../../../../src/components/views/settings/devices/DeviceTypeIcon';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
describe('<DeviceTypeIcon />', () => {
const defaultProps = {
@ -41,4 +42,33 @@ describe('<DeviceTypeIcon />', () => {
const { container } = render(getComponent({ isSelected: true }));
expect(container).toMatchSnapshot();
});
it('renders an unknown device icon when no device type given', () => {
const { getByLabelText } = render(getComponent());
expect(getByLabelText('Unknown session type')).toBeTruthy();
});
it('renders a desktop device type', () => {
const deviceType = DeviceType.Desktop;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Desktop session')).toBeTruthy();
});
it('renders a web device type', () => {
const deviceType = DeviceType.Web;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Web session')).toBeTruthy();
});
it('renders a mobile device type', () => {
const deviceType = DeviceType.Mobile;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Mobile session')).toBeTruthy();
});
it('renders an unknown device type', () => {
const deviceType = DeviceType.Unknown;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Unknown session type')).toBeTruthy();
});
});

View File

@ -154,10 +154,14 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -270,10 +274,14 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"

View File

@ -10,10 +10,14 @@ exports[`<DeviceTile /> renders a device with no metadata 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -61,10 +65,14 @@ exports[`<DeviceTile /> renders a verified device with no metadata 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -112,10 +120,14 @@ exports[`<DeviceTile /> renders display name with a tooltip 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -163,10 +175,14 @@ exports[`<DeviceTile /> separates metadata with a dot 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"

View File

@ -6,10 +6,14 @@ exports[`<DeviceTypeIcon /> renders a verified device 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
@ -25,10 +29,14 @@ exports[`<DeviceTypeIcon /> renders an unverified device 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -44,10 +52,14 @@ exports[`<DeviceTypeIcon /> renders correctly when selected 1`] = `
class="mx_DeviceTypeIcon mx_DeviceTypeIcon_selected"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"

View File

@ -42,10 +42,14 @@ exports[`<SelectableDeviceTile /> renders unselected device tile with checkbox 1
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"

View File

@ -97,10 +97,14 @@ exports[`<SessionManagerTab /> renders current session section with a verified s
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
@ -199,10 +203,14 @@ exports[`<SessionManagerTab /> renders current session section with an unverifie
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
@ -301,10 +309,14 @@ exports[`<SessionManagerTab /> sets device verification status correctly 1`] = `
class="mx_DeviceTypeIcon"
>
<div
aria-label="Unknown device type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"