mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-02-13 17:10:06 +00:00
add options to delete sessions
This commit is contained in:
parent
a2103a301a
commit
e2dbf2e68b
src/app
components/image-pack-view
features/settings
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
))}
|
||||
|
|
Loading…
Reference in a new issue