Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 877c95d

Browse files
author
Kerry
authored
device manager - add spinners while devices are signing out (#9433)
1 parent 72d7939 commit 877c95d

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

res/css/components/views/settings/devices/_FilteredDeviceList.pcss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ limitations under the License.
4545

4646
.mx_FilteredDeviceList_headerButton {
4747
flex-shrink: 0;
48+
// override inline button styling
49+
display: flex !important;
50+
flex-direction: row;
51+
gap: $spacing-8;
4852
}

res/css/views/elements/_AccessibleButton.pcss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ limitations under the License.
2525
&.mx_AccessibleButton_kind_primary_sm,
2626
&.mx_AccessibleButton_kind_link,
2727
&.mx_AccessibleButton_kind_link_inline,
28+
&.mx_AccessibleButton_kind_danger_inline,
29+
&.mx_AccessibleButton_kind_content_inline,
2830
&.mx_AccessibleButton_kind_link_sm {
2931
opacity: 0.4;
3032
}

src/components/views/settings/devices/FilteredDeviceList.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
} from './types';
3838
import { DevicesState } from './useOwnDevices';
3939
import FilteredDeviceListHeader from './FilteredDeviceListHeader';
40+
import Spinner from '../../elements/Spinner';
4041

4142
interface Props {
4243
devices: DevicesDictionary;
@@ -183,6 +184,7 @@ const DeviceListItem: React.FC<{
183184
onClick={onDeviceExpandToggle}
184185
device={device}
185186
>
187+
{ isSigningOut && <Spinner w={16} h={16} /> }
186188
<DeviceExpandDetailsButton
187189
isExpanded={isExpanded}
188190
onClick={onDeviceExpandToggle}
@@ -276,6 +278,8 @@ export const FilteredDeviceList =
276278
}
277279
};
278280

281+
const isSigningOut = !!signingOutDeviceIds.length;
282+
279283
return <div className='mx_FilteredDeviceList' ref={ref}>
280284
<FilteredDeviceListHeader
281285
selectedDeviceCount={selectedDeviceIds.length}
@@ -287,14 +291,17 @@ export const FilteredDeviceList =
287291
<AccessibleButton
288292
data-testid='sign-out-selection-cta'
289293
kind='danger_inline'
294+
disabled={isSigningOut}
290295
onClick={() => onSignOutDevices(selectedDeviceIds)}
291296
className='mx_FilteredDeviceList_headerButton'
292297
>
298+
{ isSigningOut && <Spinner w={16} h={16} /> }
293299
{ _t('Sign out') }
294300
</AccessibleButton>
295301
<AccessibleButton
296302
data-testid='cancel-selection-cta'
297303
kind='content_inline'
304+
disabled={isSigningOut}
298305
onClick={() => setSelectedDeviceIds([])}
299306
className='mx_FilteredDeviceList_headerButton'
300307
>

test/components/views/settings/tabs/user/SessionManagerTab-test.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ describe('<SessionManagerTab />', () => {
6969
};
7070

7171
const alicesInactiveDevice = {
72-
device_id: 'alices_older_mobile_device',
72+
device_id: 'alices_older_inactive_mobile_device',
7373
last_seen_ts: Date.now() - (INACTIVE_DEVICE_AGE_MS + 1000),
7474
};
7575

@@ -105,7 +105,7 @@ describe('<SessionManagerTab />', () => {
105105
const toggleDeviceDetails = (
106106
getByTestId: ReturnType<typeof render>['getByTestId'],
107107
deviceId: ExtendedDevice['device_id'],
108-
) => {
108+
): void => {
109109
// open device detail
110110
const tile = getByTestId(`device-tile-${deviceId}`);
111111
const toggle = tile.querySelector('[aria-label="Toggle device details"]') as Element;
@@ -115,11 +115,18 @@ describe('<SessionManagerTab />', () => {
115115
const toggleDeviceSelection = (
116116
getByTestId: ReturnType<typeof render>['getByTestId'],
117117
deviceId: ExtendedDevice['device_id'],
118-
) => {
118+
): void => {
119119
const checkbox = getByTestId(`device-tile-checkbox-${deviceId}`);
120120
fireEvent.click(checkbox);
121121
};
122122

123+
const getDeviceTile = (
124+
getByTestId: ReturnType<typeof render>['getByTestId'],
125+
deviceId: ExtendedDevice['device_id'],
126+
): HTMLElement => {
127+
return getByTestId(`device-tile-${deviceId}`);
128+
};
129+
123130
const setFilter = async (
124131
container: HTMLElement,
125132
option: DeviceSecurityVariation | string,
@@ -749,6 +756,7 @@ describe('<SessionManagerTab />', () => {
749756
it('deletes multiple devices', async () => {
750757
mockClient.getDevices.mockResolvedValue({ devices: [
751758
alicesDevice, alicesMobileDevice, alicesOlderMobileDevice,
759+
alicesInactiveDevice,
752760
] });
753761
mockClient.deleteMultipleDevices.mockResolvedValue({});
754762

@@ -763,6 +771,24 @@ describe('<SessionManagerTab />', () => {
763771

764772
fireEvent.click(getByTestId('sign-out-selection-cta'));
765773

774+
// buttons disabled in list header
775+
expect(getByTestId('sign-out-selection-cta').getAttribute('aria-disabled')).toBeTruthy();
776+
expect(getByTestId('cancel-selection-cta').getAttribute('aria-disabled')).toBeTruthy();
777+
// spinner rendered in list header
778+
expect(getByTestId('sign-out-selection-cta').querySelector('.mx_Spinner')).toBeTruthy();
779+
780+
// spinners on signing out devices
781+
expect(getDeviceTile(
782+
getByTestId, alicesMobileDevice.device_id,
783+
).querySelector('.mx_Spinner')).toBeTruthy();
784+
expect(getDeviceTile(
785+
getByTestId, alicesOlderMobileDevice.device_id,
786+
).querySelector('.mx_Spinner')).toBeTruthy();
787+
// no spinner for device that is not signing out
788+
expect(getDeviceTile(
789+
getByTestId, alicesInactiveDevice.device_id,
790+
).querySelector('.mx_Spinner')).toBeFalsy();
791+
766792
// delete called with both ids
767793
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(
768794
[

0 commit comments

Comments
 (0)