OIDC: disable multi session signout for OIDC-aware servers in session manager (#11431)
* util for account url * test cases * disable multi session selection on device list * remove sign out all from context menus when oidc-aware * comment * remove unused param * typo
This commit is contained in:
parent
3c52ba0c92
commit
dfded8d4d3
9 changed files with 362 additions and 61 deletions
|
@ -31,6 +31,7 @@ import { DevicesState } from "./useOwnDevices";
|
|||
import FilteredDeviceListHeader from "./FilteredDeviceListHeader";
|
||||
import Spinner from "../../elements/Spinner";
|
||||
import { DeviceSecurityLearnMore } from "./DeviceSecurityLearnMore";
|
||||
import DeviceTile from "./DeviceTile";
|
||||
|
||||
interface Props {
|
||||
devices: DevicesDictionary;
|
||||
|
@ -48,6 +49,11 @@ interface Props {
|
|||
setPushNotifications: (deviceId: string, enabled: boolean) => Promise<void>;
|
||||
setSelectedDeviceIds: (deviceIds: ExtendedDevice["device_id"][]) => void;
|
||||
supportsMSC3881?: boolean | undefined;
|
||||
/**
|
||||
* Only allow sessions to be signed out individually
|
||||
* Removes checkboxes and multi selection header
|
||||
*/
|
||||
disableMultipleSignout?: boolean;
|
||||
}
|
||||
|
||||
const isDeviceSelected = (
|
||||
|
@ -178,6 +184,7 @@ const DeviceListItem: React.FC<{
|
|||
toggleSelected: () => void;
|
||||
setPushNotifications: (deviceId: string, enabled: boolean) => Promise<void>;
|
||||
supportsMSC3881?: boolean | undefined;
|
||||
isSelectDisabled?: boolean;
|
||||
}> = ({
|
||||
device,
|
||||
pusher,
|
||||
|
@ -192,33 +199,47 @@ const DeviceListItem: React.FC<{
|
|||
setPushNotifications,
|
||||
toggleSelected,
|
||||
supportsMSC3881,
|
||||
}) => (
|
||||
<li className="mx_FilteredDeviceList_listItem">
|
||||
<SelectableDeviceTile
|
||||
isSelected={isSelected}
|
||||
onSelect={toggleSelected}
|
||||
onClick={onDeviceExpandToggle}
|
||||
device={device}
|
||||
>
|
||||
isSelectDisabled,
|
||||
}) => {
|
||||
const tileContent = (
|
||||
<>
|
||||
{isSigningOut && <Spinner w={16} h={16} />}
|
||||
<DeviceExpandDetailsButton isExpanded={isExpanded} onClick={onDeviceExpandToggle} />
|
||||
</SelectableDeviceTile>
|
||||
{isExpanded && (
|
||||
<DeviceDetails
|
||||
device={device}
|
||||
pusher={pusher}
|
||||
localNotificationSettings={localNotificationSettings}
|
||||
isSigningOut={isSigningOut}
|
||||
onVerifyDevice={onRequestDeviceVerification}
|
||||
onSignOutDevice={onSignOutDevice}
|
||||
saveDeviceName={saveDeviceName}
|
||||
setPushNotifications={setPushNotifications}
|
||||
supportsMSC3881={supportsMSC3881}
|
||||
className="mx_FilteredDeviceList_deviceDetails"
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<li className="mx_FilteredDeviceList_listItem">
|
||||
{isSelectDisabled ? (
|
||||
<DeviceTile device={device} onClick={onDeviceExpandToggle}>
|
||||
{tileContent}
|
||||
</DeviceTile>
|
||||
) : (
|
||||
<SelectableDeviceTile
|
||||
isSelected={isSelected}
|
||||
onSelect={toggleSelected}
|
||||
onClick={onDeviceExpandToggle}
|
||||
device={device}
|
||||
>
|
||||
{tileContent}
|
||||
</SelectableDeviceTile>
|
||||
)}
|
||||
{isExpanded && (
|
||||
<DeviceDetails
|
||||
device={device}
|
||||
pusher={pusher}
|
||||
localNotificationSettings={localNotificationSettings}
|
||||
isSigningOut={isSigningOut}
|
||||
onVerifyDevice={onRequestDeviceVerification}
|
||||
onSignOutDevice={onSignOutDevice}
|
||||
saveDeviceName={saveDeviceName}
|
||||
setPushNotifications={setPushNotifications}
|
||||
supportsMSC3881={supportsMSC3881}
|
||||
className="mx_FilteredDeviceList_deviceDetails"
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Filtered list of devices
|
||||
|
@ -242,6 +263,7 @@ export const FilteredDeviceList = forwardRef(
|
|||
setPushNotifications,
|
||||
setSelectedDeviceIds,
|
||||
supportsMSC3881,
|
||||
disableMultipleSignout,
|
||||
}: Props,
|
||||
ref: ForwardedRef<HTMLDivElement>,
|
||||
) => {
|
||||
|
@ -302,6 +324,7 @@ export const FilteredDeviceList = forwardRef(
|
|||
selectedDeviceCount={selectedDeviceIds.length}
|
||||
isAllSelected={isAllSelected}
|
||||
toggleSelectAll={toggleSelectAll}
|
||||
isSelectDisabled={disableMultipleSignout}
|
||||
>
|
||||
{selectedDeviceIds.length ? (
|
||||
<>
|
||||
|
@ -351,6 +374,7 @@ export const FilteredDeviceList = forwardRef(
|
|||
isExpanded={expandedDeviceIds.includes(device.device_id)}
|
||||
isSigningOut={signingOutDeviceIds.includes(device.device_id)}
|
||||
isSelected={isDeviceSelected(device.device_id, selectedDeviceIds)}
|
||||
isSelectDisabled={disableMultipleSignout}
|
||||
onDeviceExpandToggle={() => onDeviceExpandToggle(device.device_id)}
|
||||
onSignOutDevice={() => onSignOutDevices([device.device_id])}
|
||||
saveDeviceName={(deviceName: string) => saveDeviceName(device.device_id, deviceName)}
|
||||
|
|
|
@ -24,6 +24,7 @@ import TooltipTarget from "../../elements/TooltipTarget";
|
|||
interface Props extends Omit<HTMLProps<HTMLDivElement>, "className"> {
|
||||
selectedDeviceCount: number;
|
||||
isAllSelected: boolean;
|
||||
isSelectDisabled?: boolean;
|
||||
toggleSelectAll: () => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
@ -31,6 +32,7 @@ interface Props extends Omit<HTMLProps<HTMLDivElement>, "className"> {
|
|||
const FilteredDeviceListHeader: React.FC<Props> = ({
|
||||
selectedDeviceCount,
|
||||
isAllSelected,
|
||||
isSelectDisabled,
|
||||
toggleSelectAll,
|
||||
children,
|
||||
...rest
|
||||
|
@ -38,16 +40,18 @@ const FilteredDeviceListHeader: React.FC<Props> = ({
|
|||
const checkboxLabel = isAllSelected ? _t("Deselect all") : _t("Select all");
|
||||
return (
|
||||
<div className="mx_FilteredDeviceListHeader" {...rest}>
|
||||
<TooltipTarget label={checkboxLabel} alignment={Alignment.Top}>
|
||||
<StyledCheckbox
|
||||
kind={CheckboxStyle.Solid}
|
||||
checked={isAllSelected}
|
||||
onChange={toggleSelectAll}
|
||||
id="device-select-all-checkbox"
|
||||
data-testid="device-select-all-checkbox"
|
||||
aria-label={checkboxLabel}
|
||||
/>
|
||||
</TooltipTarget>
|
||||
{!isSelectDisabled && (
|
||||
<TooltipTarget label={checkboxLabel} alignment={Alignment.Top}>
|
||||
<StyledCheckbox
|
||||
kind={CheckboxStyle.Solid}
|
||||
checked={isAllSelected}
|
||||
onChange={toggleSelectAll}
|
||||
id="device-select-all-checkbox"
|
||||
data-testid="device-select-all-checkbox"
|
||||
aria-label={checkboxLabel}
|
||||
/>
|
||||
</TooltipTarget>
|
||||
)}
|
||||
<span className="mx_FilteredDeviceListHeader_label">
|
||||
{selectedDeviceCount > 0
|
||||
? _t("%(count)s sessions selected", { count: selectedDeviceCount })
|
||||
|
|
|
@ -20,6 +20,7 @@ import { _t } from "../../../../languageHandler";
|
|||
import { KebabContextMenu } from "../../context_menus/KebabContextMenu";
|
||||
import { SettingsSubsectionHeading } from "../shared/SettingsSubsectionHeading";
|
||||
import { IconizedContextMenuOption } from "../../context_menus/IconizedContextMenu";
|
||||
import { filterBoolean } from "../../../../utils/arrays";
|
||||
|
||||
interface Props {
|
||||
// total count of other sessions
|
||||
|
@ -27,7 +28,8 @@ interface Props {
|
|||
// not affected by filters
|
||||
otherSessionsCount: number;
|
||||
disabled?: boolean;
|
||||
signOutAllOtherSessions: () => void;
|
||||
// not provided when sign out all other sessions is not available
|
||||
signOutAllOtherSessions?: () => void;
|
||||
}
|
||||
|
||||
export const OtherSessionsSectionHeading: React.FC<Props> = ({
|
||||
|
@ -35,22 +37,26 @@ export const OtherSessionsSectionHeading: React.FC<Props> = ({
|
|||
disabled,
|
||||
signOutAllOtherSessions,
|
||||
}) => {
|
||||
const menuOptions = [
|
||||
<IconizedContextMenuOption
|
||||
key="sign-out-all-others"
|
||||
label={_t("Sign out of %(count)s sessions", { count: otherSessionsCount })}
|
||||
onClick={signOutAllOtherSessions}
|
||||
isDestructive
|
||||
/>,
|
||||
];
|
||||
const menuOptions = filterBoolean([
|
||||
signOutAllOtherSessions ? (
|
||||
<IconizedContextMenuOption
|
||||
key="sign-out-all-others"
|
||||
label={_t("Sign out of %(count)s sessions", { count: otherSessionsCount })}
|
||||
onClick={signOutAllOtherSessions}
|
||||
isDestructive
|
||||
/>
|
||||
) : null,
|
||||
]);
|
||||
return (
|
||||
<SettingsSubsectionHeading heading={_t("Other sessions")}>
|
||||
<KebabContextMenu
|
||||
disabled={disabled}
|
||||
title={_t("Options")}
|
||||
options={menuOptions}
|
||||
data-testid="other-sessions-menu"
|
||||
/>
|
||||
{!!menuOptions.length && (
|
||||
<KebabContextMenu
|
||||
disabled={disabled}
|
||||
title={_t("Options")}
|
||||
options={menuOptions}
|
||||
data-testid="other-sessions-menu"
|
||||
/>
|
||||
)}
|
||||
</SettingsSubsectionHeading>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue