add options to delete sessions

This commit is contained in:
Ajay Bura 2025-01-19 15:26:09 +05:30
parent a2103a301a
commit e2dbf2e68b
3 changed files with 138 additions and 8 deletions
src/app
components/image-pack-view
features/settings
emojis-stickers
sessions

View file

@ -280,7 +280,7 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
variant="Success"
radii="300"
disabled={!canApplyChanges || applying}
before={applying && <Spinner variant="Success" fill="Soft" size="100" />}
before={applying && <Spinner variant="Success" fill="Solid" size="100" />}
onClick={applyChanges}
>
<Text size="B300">Apply Changes</Text>

View file

@ -474,7 +474,7 @@ export function GlobalPacks({ onViewPack }: GlobalPacksProps) {
variant="Success"
radii="300"
disabled={applyingChanges}
before={applyingChanges && <Spinner variant="Success" fill="Soft" size="100" />}
before={applyingChanges && <Spinner variant="Success" fill="Solid" size="100" />}
onClick={applyChanges}
>
<Text size="B300">Apply Changes</Text>

View file

@ -12,8 +12,10 @@ import {
color,
Spinner,
toRem,
Menu,
config,
} from 'folds';
import { IMyDevice, MatrixError } from 'matrix-js-sdk';
import { AuthDict, IMyDevice, MatrixError } from 'matrix-js-sdk';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
@ -22,7 +24,14 @@ import { useDeviceList } from '../../../hooks/useDeviceList';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { timeDayMonYear, timeHourMinute, today, yesterday } from '../../../utils/time';
import { BreakWord } from '../../../styles/Text.css';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import {
AsyncState,
AsyncStatus,
useAsync,
useAsyncCallback,
} from '../../../hooks/useAsyncCallback';
import { ActionUIA, ActionUIAFlowsLoader } from '../../../components/ActionUIA';
import { useUIAMatrixError } from '../../../hooks/useUIAFlows';
function DevicesPlaceholder() {
return (
@ -179,10 +188,12 @@ function DeviceRename({ device, onCancel, onRename, refreshDeviceList }: DeviceR
</Button>
</Box>
</Box>
{renameState.status === AsyncStatus.Error && (
{renameState.status === AsyncStatus.Error ? (
<Text size="T200" style={{ color: color.Critical.Main }}>
{renameState.error.message}
</Text>
) : (
<Text size="T200">Session names are visible to public.</Text>
)}
</Box>
);
@ -193,8 +204,15 @@ type DeviceTileProps = {
deleted: boolean;
onDeleteToggle: (deviceId: string) => void;
refreshDeviceList: () => Promise<void>;
disabled?: boolean;
};
function DeviceTile({ device, deleted, onDeleteToggle, refreshDeviceList }: DeviceTileProps) {
function DeviceTile({
device,
deleted,
onDeleteToggle,
refreshDeviceList,
disabled,
}: DeviceTileProps) {
const activeTs = device.last_seen_ts;
const [details, setDetails] = useState(false);
const [edit, setEdit] = useState(false);
@ -213,7 +231,7 @@ function DeviceTile({ device, deleted, onDeleteToggle, refreshDeviceList }: Devi
radii="300"
onClick={() => setDetails(!details)}
>
<Icon size="50" src={details ? Icons.ChevronTop : Icons.ChevronBottom} />
<Icon size="50" src={details ? Icons.ChevronBottom : Icons.ChevronRight} />
</IconButton>
}
after={
@ -225,6 +243,7 @@ function DeviceTile({ device, deleted, onDeleteToggle, refreshDeviceList }: Devi
fill="None"
radii="Pill"
onClick={() => onDeleteToggle?.(device.device_id)}
disabled={disabled}
>
<Text size="B300">Undo</Text>
</Chip>
@ -235,10 +254,16 @@ function DeviceTile({ device, deleted, onDeleteToggle, refreshDeviceList }: Devi
fill="None"
radii="Pill"
onClick={() => onDeleteToggle?.(device.device_id)}
disabled={disabled}
>
<Icon size="50" src={Icons.Delete} />
</Chip>
<Chip variant="Secondary" radii="Pill" onClick={() => setEdit(true)}>
<Chip
variant="Secondary"
radii="Pill"
onClick={() => setEdit(true)}
disabled={disabled}
>
<Text size="B300">Edit</Text>
</Chip>
</>
@ -291,6 +316,38 @@ export function Sessions({ requestClose }: SessionsProps) {
});
}, []);
const [deleteState, setDeleteState] = useState<AsyncState<void, MatrixError>>({
status: AsyncStatus.Idle,
});
const deleteDevices = useAsync(
useCallback(
async (authDict?: AuthDict) => {
await mx.deleteMultipleDevices(Array.from(deleted), authDict);
},
[mx, deleted]
),
useCallback(
(state: typeof deleteState) => {
if (state.status === AsyncStatus.Success) {
setDeleted(new Set());
refreshDeviceList();
}
setDeleteState(state);
},
[refreshDeviceList]
)
);
const [authData, deleteError] = useUIAMatrixError(
deleteState.status === AsyncStatus.Error ? deleteState.error : undefined
);
const deleting = deleteState.status === AsyncStatus.Loading || authData !== undefined;
const handleCancelDelete = () => setDeleted(new Set());
const handleCancelAuth = useCallback(() => {
setDeleteState({ status: AsyncStatus.Idle });
}, []);
return (
<Page>
<PageHeader outlined={false}>
@ -311,6 +368,77 @@ export function Sessions({ requestClose }: SessionsProps) {
<Scroll hideTrack visibility="Hover">
<PageContent>
<Box direction="Column" gap="700">
{deleted.size > 0 && (
<Menu
style={{
position: 'sticky',
padding: config.space.S200,
paddingLeft: config.space.S400,
top: config.space.S400,
left: config.space.S400,
right: 0,
zIndex: 1,
}}
variant="Critical"
>
<Box alignItems="Center" gap="400">
<Box grow="Yes" direction="Column">
{deleteError ? (
<Text size="T200">
<b>Failed to logout sessions! Please try again. {deleteError.message}</b>
</Text>
) : (
<Text size="T200">
<b>Logout from selected sessions. ({deleted.size} selected)</b>
</Text>
)}
{authData && (
<ActionUIAFlowsLoader
authData={authData}
unsupported={() => (
<Text size="T200">
Authentication steps to perform this action are not supported by
client.
</Text>
)}
>
{(ongoingFlow) => (
<ActionUIA
userId={mx.getUserId()!}
authData={authData}
ongoingFlow={ongoingFlow}
action={deleteDevices}
onCancel={handleCancelAuth}
/>
)}
</ActionUIAFlowsLoader>
)}
</Box>
<Box shrink="No" gap="200">
<Button
size="300"
variant="Critical"
fill="None"
radii="300"
disabled={deleting}
onClick={handleCancelDelete}
>
<Text size="B300">Cancel</Text>
</Button>
<Button
size="300"
variant="Critical"
radii="300"
disabled={deleting}
before={deleting && <Spinner variant="Critical" fill="Solid" size="100" />}
onClick={() => deleteDevices()}
>
<Text size="B300">Logout</Text>
</Button>
</Box>
</Box>
</Menu>
)}
{devices === null && <DevicesPlaceholder />}
{currentDevice && (
<Box direction="Column" gap="100">
@ -326,6 +454,7 @@ export function Sessions({ requestClose }: SessionsProps) {
deleted={deleted.has(currentDevice.device_id)}
onDeleteToggle={handleToggleDelete}
refreshDeviceList={refreshDeviceList}
disabled={deleting}
/>
</SequenceCard>
</Box>
@ -351,6 +480,7 @@ export function Sessions({ requestClose }: SessionsProps) {
deleted={deleted.has(device.device_id)}
onDeleteToggle={handleToggleDelete}
refreshDeviceList={refreshDeviceList}
disabled={deleting}
/>
</SequenceCard>
))}