Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 23 additions & 26 deletions web/packages/shared/components/DesktopSession/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import React from 'react';

import { Flex } from 'design';
import * as Icons from 'design/Icon';
import { MenuIcon, MenuItem, MenuItemIcon } from 'shared/components/MenuAction';

Expand All @@ -27,32 +26,30 @@ export default function ActionMenu(props: Props) {
props;

return (
<Flex alignItems="center">
<MenuIcon
buttonIconProps={{
ml: 4,
size: 0,
color: 'text.slightlyMuted',
style: { fontSize: '20px' },
}}
menuProps={menuProps}
>
{showShareDirectory && (
<MenuItem onClick={onShareDirectory}>
<MenuItemIcon as={Icons.FolderPlus} mr="2" />
Share Directory
</MenuItem>
)}
<MenuItem onClick={onCtrlAltDel}>
<MenuItemIcon as={Icons.Keyboard} mr="2" />
Send Ctrl+Alt+Del
<MenuIcon
buttonIconProps={{
size: 0,
color: 'text.slightlyMuted',
style: { fontSize: '20px' },
title: 'More actions',
}}
menuProps={menuProps}
>
{showShareDirectory && (
<MenuItem onClick={onShareDirectory}>
<MenuItemIcon as={Icons.FolderPlus} mr="2" />
Share Directory
</MenuItem>
<MenuItem onClick={onDisconnect}>
<MenuItemIcon as={Icons.PowerSwitch} mr="2" />
Disconnect
</MenuItem>
</MenuIcon>
</Flex>
)}
<MenuItem onClick={onCtrlAltDel}>
<MenuItemIcon as={Icons.Keyboard} mr="2" />
Send Ctrl+Alt+Del
</MenuItem>
<MenuItem onClick={onDisconnect}>
<MenuItemIcon as={Icons.PowerSwitch} mr="2" />
Disconnect
</MenuItem>
</MenuIcon>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const props: DesktopSessionProps = {
client: fakeClient(),
username: 'user',
desktop: 'windows-11',
browserSupportsSharing: true,
hasAnotherSession: () => Promise.resolve(false),
};

Expand Down
24 changes: 8 additions & 16 deletions web/packages/shared/components/DesktopSession/DesktopSession.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ import { KeyboardHandler } from './KeyboardHandler';
import TopBar from './TopBar';
import useDesktopSession, {
clipboardSharingMessage,
defaultClipboardSharingState,
defaultDirectorySharingState,
directorySharingPossible,
isSharingClipboard,
isSharingDirectory,
Expand All @@ -58,6 +56,8 @@ export interface DesktopSessionProps {
clipboardSharingEnabled: boolean;
directorySharingEnabled: boolean;
}>;
/** Determines if the browser client support directory and clipboard sharing. */
browserSupportsSharing: boolean;
/**
* Injects a custom component that overrides other connection states.
* Useful for per-session MFA, which differs between Web UI and Connect.
Expand All @@ -74,19 +74,19 @@ export function DesktopSession({
desktop,
hasAnotherSession,
customConnectionState,
browserSupportsSharing,
}: DesktopSessionProps) {
const {
directorySharingState,
setDirectorySharingState,
onClipboardData,
sendLocalClipboardToRemote,
clipboardSharingState,
setClipboardSharingState,
clearSharing,
onShareDirectory,
alerts,
onRemoveAlert,
addAlert,
} = useDesktopSession(client, aclAttempt);
} = useDesktopSession(client, aclAttempt, browserSupportsSharing);

const [tdpConnectionStatus, setTdpConnectionStatus] =
useState<TdpConnectionStatus>({ status: '' });
Expand Down Expand Up @@ -127,16 +127,15 @@ export function DesktopSession({

const handleFatalError = useCallback(
(error: Error) => {
setDirectorySharingState(defaultDirectorySharingState);
setClipboardSharingState(defaultClipboardSharingState);
clearSharing();
setTdpConnectionStatus({
status: 'disconnected',
fromTdpError: error instanceof TdpError,
message: error.message,
});
initialTdpConnectionSucceeded.current = false;
},
[setClipboardSharingState, setDirectorySharingState]
[clearSharing]
);
useListener(client.onError, handleFatalError);

Expand Down Expand Up @@ -325,14 +324,7 @@ export function DesktopSession({
>
<TopBar
onDisconnect={() => {
setClipboardSharingState(prevState => ({
...prevState,
isSharing: false,
}));
setDirectorySharingState(prevState => ({
...prevState,
isSharing: false,
}));
clearSharing();
client.shutdown();
}}
userHost={`${username} on ${desktop}`}
Expand Down
50 changes: 23 additions & 27 deletions web/packages/shared/components/DesktopSession/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,35 +52,31 @@ export default function TopBar(props: Props) {
<TopNav
height="40px"
bg="levels.deep"
style={{
justifyContent: 'space-between',
}}
justifyContent="space-between"
gap={3}
px={3}
>
<Text px={3} style={{ color: theme.colors.text.slightlyMuted }}>
{userHost}
</Text>
<Text style={{ color: theme.colors.text.slightlyMuted }}>{userHost}</Text>

<Flex px={3}>
<Flex alignItems="center">
<HoverTooltip
tipContent={directorySharingToolTip(
canShareDirectory,
isSharingDirectory
)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
transformOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<FolderShared style={primaryOnTrue(isSharingDirectory)} pr={3} />
</HoverTooltip>
<HoverTooltip
tipContent={clipboardSharingMessage}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
transformOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<Clipboard style={primaryOnTrue(isSharingClipboard)} pr={3} />
</HoverTooltip>
<WarningDropdown warnings={alerts} onRemoveWarning={onRemoveAlert} />
</Flex>
<Flex gap={3} alignItems="center">
<HoverTooltip
tipContent={directorySharingToolTip(
canShareDirectory,
isSharingDirectory
)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
transformOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<FolderShared style={primaryOnTrue(isSharingDirectory)} />
</HoverTooltip>
<HoverTooltip
tipContent={clipboardSharingMessage}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
transformOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<Clipboard style={primaryOnTrue(isSharingClipboard)} />
</HoverTooltip>
<WarningDropdown warnings={alerts} onRemoveWarning={onRemoveAlert} />
<ActionMenu
onDisconnect={onDisconnect}
showShareDirectory={canShareDirectory && !isSharingDirectory}
Expand Down
83 changes: 41 additions & 42 deletions web/packages/shared/components/DesktopSession/useDesktopSession.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,34 @@ export default function useDesktopSession(
aclAttempt: Attempt<{
clipboardSharingEnabled: boolean;
directorySharingEnabled: boolean;
}>
}>,
browserSupportsSharing: boolean
) {
const encoder = useRef(new TextEncoder());
const latestClipboardDigest = useRef('');
const [directorySharingState, setDirectorySharingState] =
useState<DirectorySharingState>(defaultDirectorySharingState);

const [clipboardSharingState, setClipboardSharingState] =
useState<ClipboardSharingState>(defaultClipboardSharingState);
const [directorySharingState, setDirectorySharingState] = useState<{
directorySelected: boolean;
}>({ directorySelected: false });

const [clipboardSharingState, setClipboardSharingState] = useState<{
readState?: PermissionState;
writeState?: PermissionState;
}>({});

const clipboardSharing: ClipboardSharingState = {
...clipboardSharingState,
browserSupported: browserSupportsSharing,
allowedByAcl:
aclAttempt.status === 'success' &&
aclAttempt.data.clipboardSharingEnabled,
};
const directorySharing: DirectorySharingState = {
...directorySharingState,
browserSupported: browserSupportsSharing,
allowedByAcl:
aclAttempt.status === 'success' &&
aclAttempt.data.directorySharingEnabled,
};

useEffect(() => {
const clearReadListenerPromise = initClipboardPermissionTracking(
Expand All @@ -68,21 +87,6 @@ export default function useDesktopSession(
};
}, []);

//TODO(gzdunek): This is workaround for synchronizing *sharingState with aclAttempt.
//Refactor clipboard and directory sharing so that we won't need allowedByAcl fields in state.
useEffect(() => {
if (aclAttempt.status === 'success') {
setClipboardSharingState(prevState => ({
...prevState,
allowedByAcl: aclAttempt.data.clipboardSharingEnabled,
}));
setDirectorySharingState(prevState => ({
...prevState,
allowedByAcl: aclAttempt.data.directorySharingEnabled,
}));
}
}, [aclAttempt]);

const [alerts, setAlerts] = useState<NotificationItem[]>([]);
const onRemoveAlert = (id: string) => {
setAlerts(prevState => prevState.filter(alert => alert.id !== id));
Expand All @@ -95,7 +99,7 @@ export default function useDesktopSession(
}, []);

async function sendLocalClipboardToRemote() {
if (!(await sysClipboardGuard(clipboardSharingState, 'read'))) {
if (!(await sysClipboardGuard(clipboardSharing, 'read'))) {
return;
}
const text = await navigator.clipboard.readText();
Expand All @@ -111,7 +115,7 @@ export default function useDesktopSession(
async function onClipboardData(clipboardData: ClipboardData) {
if (
clipboardData.data &&
(await sysClipboardGuard(clipboardSharingState, 'write'))
(await sysClipboardGuard(clipboardSharing, 'write'))
) {
await navigator.clipboard.writeText(clipboardData.data);
latestClipboardDigest.current = await sha256Digest(
Expand All @@ -127,10 +131,9 @@ export default function useDesktopSession(
.showDirectoryPicker()
.then(sharedDirHandle => {
// Permissions granted and/or directory selected
setDirectorySharingState(prevState => ({
...prevState,
setDirectorySharingState({
directorySelected: true,
}));
});
tdpClient.addSharedDirectory(sharedDirHandle);
tdpClient.sendSharedDirectoryAnnounce();
})
Expand All @@ -148,10 +151,9 @@ export default function useDesktopSession(
});
});
} catch (e) {
setDirectorySharingState(prevState => ({
...prevState,
setDirectorySharingState({
directorySelected: false,
}));
});
addAlert({
severity: 'warn',
// This is a gross error message, but should be infrequent enough that its worth just telling
Expand All @@ -172,11 +174,17 @@ export default function useDesktopSession(
}
};

/** Clears sharing state. */
const clearSharing = useCallback(() => {
setDirectorySharingState({
directorySelected: false,
});
}, []);

return {
clipboardSharingState,
setClipboardSharingState,
directorySharingState,
setDirectorySharingState,
clipboardSharingState: clipboardSharing,
directorySharingState: directorySharing,
clearSharing,
onShareDirectory,
alerts,
onRemoveAlert,
Expand Down Expand Up @@ -340,15 +348,6 @@ export function isSharingDirectory(
);
}

export const defaultDirectorySharingState: DirectorySharingState = {
browserSupported: navigator.userAgent.includes('Chrome'),
directorySelected: false,
};

export const defaultClipboardSharingState: ClipboardSharingState = {
browserSupported: navigator.userAgent.includes('Chrome'),
};

/**
* To be called before any system clipboard read/write operation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function DesktopSession() {
}
}}
aclAttempt={aclAttempt}
browserSupportsSharing={navigator.userAgent.includes('Chrome')}
hasAnotherSession={hasAnotherSession}
/>
);
Expand Down
Loading