From c2cdc92cd7babb064bc2fcd05aa15ca2cc002063 Mon Sep 17 00:00:00 2001 From: Martin Varmuza Date: Tue, 1 Oct 2024 17:55:40 +0200 Subject: [PATCH] chore(suite): rework UnreadableDevice troubleshooting --- .../Preloader/__tests__/Preloader.test.tsx | 14 ++++++- .../PrerequisitesGuide/DeviceUnreadable.tsx | 40 +++++++++---------- .../PrerequisitesGuide/PrerequisitesGuide.tsx | 4 +- .../suite/troubleshooting/tips/BridgeTip.tsx | 35 +++++++++++++++- .../suite/troubleshooting/tips/index.tsx | 30 +++++++++++++- packages/suite/src/support/messages.ts | 24 ++++++++--- packages/urls/src/urls.ts | 2 + 7 files changed, 117 insertions(+), 32 deletions(-) diff --git a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx index 1561665e9377..3e57e258ce8e 100644 --- a/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx +++ b/packages/suite/src/components/suite/Preloader/__tests__/Preloader.test.tsx @@ -20,6 +20,18 @@ jest.mock('cross-fetch', () => ({ default: () => Promise.resolve({ ok: false }), })); +// mock desktopApi +jest.mock('@trezor/suite-desktop-api', () => ({ + __esModule: true, + desktopApi: { + getBridgeStatus: () => + Promise.resolve({ success: true, payload: { service: true, process: true } }), + getBridgeSettings: () => Promise.resolve({ success: true, payload: { enabled: true } }), + on: (_event: string, _cb: any) => {}, + removeAllListeners: (_event: string) => {}, + }, +})); + // jest.mock('@firmware-components/ReconnectDevicePrompt', () => ({ // __esModule: true, // export as module // default: ({ children }: any) =>
{children}
, @@ -224,7 +236,7 @@ describe('Preloader component', () => { const { unmount } = renderWithProviders(store, ); expect(findByTestId('@connect-device-prompt')).not.toBeNull(); - expect(findByTestId('@connect-device-prompt/unreadable-hid')).not.toBeNull(); + expect(findByTestId('@connect-device-prompt/unreadable-unknown')).not.toBeNull(); unmount(); }); diff --git a/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx b/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx index 6bdfddd9b847..6a6da83533c3 100644 --- a/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx +++ b/packages/suite/src/components/suite/PrerequisitesGuide/DeviceUnreadable.tsx @@ -4,11 +4,11 @@ import { desktopApi } from '@trezor/suite-desktop-api'; import { isDesktop, isLinux } from '@trezor/env-utils'; import { Translation, TroubleshootingTips, UdevDownload } from 'src/components/suite'; import { - TROUBLESHOOTING_TIP_BRIDGE_STATUS, TROUBLESHOOTING_TIP_SUITE_DESKTOP, - TROUBLESHOOTING_TIP_CABLE, - TROUBLESHOOTING_TIP_USB, TROUBLESHOOTING_TIP_DIFFERENT_COMPUTER, + TROUBLESHOOTING_TIP_UNREADABLE_HID, + TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE, + TROUBLESHOOTING_TIP_RECONNECT, } from 'src/components/suite/troubleshooting/tips'; import { useDispatch } from 'src/hooks/suite'; import { notificationsActions } from '@suite-common/toast-notifications'; @@ -99,23 +99,12 @@ const UdevDesktop = () => { interface DeviceUnreadableProps { device?: TrezorDevice; // this should be actually UnreadableDevice, but it is not worth type casting - isWebUsbTransport: boolean; } -// We don't really know what happened, show some generic help and provide link to contact a support -export const DeviceUnreadable = ({ device, isWebUsbTransport }: DeviceUnreadableProps) => { - if (isWebUsbTransport) { - // only install bridge will help (webusb + HID device) - return ( - } - items={[TROUBLESHOOTING_TIP_BRIDGE_STATUS, TROUBLESHOOTING_TIP_SUITE_DESKTOP]} - offerWebUsb - data-testid="@connect-device-prompt/unreadable-hid" - /> - ); - } - +/** + * Device was detected but App can't communicate with it. + */ +export const DeviceUnreadable = ({ device }: DeviceUnreadableProps) => { // this error is dispatched by trezord when udev rules are missing if (isLinux() && device?.error === 'LIBUSB_ERROR_ACCESS') { return <> {isDesktop() ? : }; @@ -130,11 +119,20 @@ export const DeviceUnreadable = ({ device, isWebUsbTransport }: DeviceUnreadable /> } items={[ - TROUBLESHOOTING_TIP_CABLE, - TROUBLESHOOTING_TIP_USB, + // closing other apps and reloading should be the first step. Either we might have made a bug and let two apps to talk + // to device at the same time or there might be another application in the wild not really playing according to our rules + TROUBLESHOOTING_TIP_RECONNECT, + // if on web - try installing desktop. this takes you to using bridge which should be more powerful than WebUSB + TROUBLESHOOTING_TIP_SUITE_DESKTOP, + // you might have a very old device which is no longer supported current bridge + // if on desktop - try toggling between the 2 bridges we have available + TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE, + // If even this did not work, go to support or knowledge base + TROUBLESHOOTING_TIP_UNREADABLE_HID, + // unfortunately we have seen reports that even old bridge might not be enough for some Windows users. So the only chance + // is using another computer, or maybe it would be better to say another OS TROUBLESHOOTING_TIP_DIFFERENT_COMPUTER, ]} - offerWebUsb={isWebUsbTransport} data-testid="@connect-device-prompt/unreadable-unknown" /> ); diff --git a/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx b/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx index 799e663cd56f..e4818461649e 100644 --- a/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx +++ b/packages/suite/src/components/suite/PrerequisitesGuide/PrerequisitesGuide.tsx @@ -61,9 +61,7 @@ export const PrerequisitesGuide = ({ allowSwitchDevice }: PrerequisitesGuideProp case 'device-unacquired': return ; case 'device-unreadable': - return ( - - ); + return ; case 'device-unknown': return ; case 'device-seedless': diff --git a/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx b/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx index 662718c29681..14a29f06d7b5 100644 --- a/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx +++ b/packages/suite/src/components/suite/troubleshooting/tips/BridgeTip.tsx @@ -5,8 +5,10 @@ import { typography } from '@trezor/theme'; import { TrezorLink } from 'src/components/suite'; import { Translation } from 'src/components/suite/Translation'; import { useOpenSuiteDesktop } from 'src/hooks/suite/useOpenSuiteDesktop'; +import { useBridgeDesktopApi } from 'src/hooks/suite/useBridgeDesktopApi'; +import { useSelector } from 'src/hooks/suite'; -const Wrapper = styled.div` +export const Wrapper = styled.div` a { ${typography.hint}; } @@ -45,3 +47,34 @@ export const BridgeStatus = () => ( /> ); + +export const BridgeToggle = () => { + const { changeBridgeSettings, bridgeSettings } = useBridgeDesktopApi(); + const transport = useSelector(state => state.suite.transport); + + if (!bridgeSettings) return null; + + return ( + + ( + { + changeBridgeSettings({ + ...bridgeSettings, + legacy: !bridgeSettings?.legacy, + }); + }} + > + {chunks} + + ), + }} + /> + + ); +}; diff --git a/packages/suite/src/components/suite/troubleshooting/tips/index.tsx b/packages/suite/src/components/suite/troubleshooting/tips/index.tsx index ebb148a77a3c..b94fe12bc96c 100644 --- a/packages/suite/src/components/suite/troubleshooting/tips/index.tsx +++ b/packages/suite/src/components/suite/troubleshooting/tips/index.tsx @@ -1,9 +1,11 @@ import { isWeb, isDesktop, isLinux, isAndroid } from '@trezor/env-utils'; +import { OLD_FW_UPDATE_URL } from '@trezor/urls'; +import { TrezorLink } from 'src/components/suite'; import { Translation } from 'src/components/suite/Translation'; import { isWebUsb } from 'src/utils/suite/transport'; -import { BridgeStatus, BridgeInstall } from './BridgeTip'; +import { BridgeStatus, BridgeInstall, BridgeToggle, Wrapper } from './BridgeTip'; import { UdevDescription } from './UdevDescription'; export const TROUBLESHOOTING_TIP_BRIDGE_STATUS = { @@ -20,6 +22,25 @@ export const TROUBLESHOOTING_TIP_WEBUSB_ENVIRONMENT = { hide: isWebUsb() || !isWeb(), }; +export const TROUBLESHOOTING_TIP_UNREADABLE_HID = { + key: 'unreadable-hid', + heading: , + description: ( + + ( + + {chunks} + + ), + }} + /> + + ), +}; + export const TROUBLESHOOTING_TIP_SUITE_DESKTOP = { key: 'suite-desktop', heading: , @@ -27,6 +48,13 @@ export const TROUBLESHOOTING_TIP_SUITE_DESKTOP = { hide: !isWeb(), }; +export const TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE = { + key: 'suite-desktop', + heading: , + description: , + hide: isWebUsb() || isWeb() || isAndroid(), +}; + export const TROUBLESHOOTING_TIP_CABLE = { key: 'cable', heading: , diff --git a/packages/suite/src/support/messages.ts b/packages/suite/src/support/messages.ts index 996079f9d1b7..9fc848d524c0 100644 --- a/packages/suite/src/support/messages.ts +++ b/packages/suite/src/support/messages.ts @@ -7235,6 +7235,15 @@ export default defineMessages({ 'Only Chromium-based browsers currently allow direct communication with USB devices', id: 'TR_TROUBLESHOOTING_TIP_BROWSER_WEBUSB_DESCRIPTION', }, + TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_TITLE: { + defaultMessage: 'You may be using a very old Trezor model', + id: 'TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_TITLE', + }, + TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_DESCRIPTION: { + defaultMessage: + 'If the last time you updated your device firmware was in 2019 and earlier please follow instructions in the knowledge base', + id: 'TR_TROUBLESHOOTING_TIP_UNREADABLE_HID_DESCRIPTION', + }, TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TITLE: { id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TITLE', defaultMessage: 'Use the Trezor Suite desktop app', @@ -7243,6 +7252,15 @@ export default defineMessages({ id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_DESCRIPTION', defaultMessage: 'Run the Trezor Suite desktop app', }, + TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_TITLE: { + id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_TITLE', + defaultMessage: 'Use another version of Trezor Bridge', + }, + TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_DESCRIPTION: { + id: 'TR_TROUBLESHOOTING_TIP_SUITE_DESKTOP_TOGGLE_BRIDGE_DESCRIPTION', + defaultMessage: + 'Click to toggle an alternative bridge implementation. Current version: ({currentVersion})', + }, TR_TROUBLESHOOTING_TIP_UDEV_INSTALL_DESCRIPTION: { id: 'TR_TROUBLESHOOTING_TIP_UDEV_INSTALL_DESCRIPTION', defaultMessage: @@ -7261,6 +7279,7 @@ export default defineMessages({ 'After closing other browser tabs and windows, try quitting and reopening Trezor Suite.', id: 'TR_TROUBLESHOOTING_CLOSE_TABS_DESCRIPTION_DESKTOP', }, + TR_TROUBLESHOOTING_TIP_CABLE_TITLE: { id: 'TR_TROUBLESHOOTING_TIP_CABLE_TITLE', defaultMessage: 'Try a different cable', @@ -7295,11 +7314,6 @@ export default defineMessages({ id: 'TR_TROUBLESHOOTING_TIP_RESTART_COMPUTER_DESCRIPTION', defaultMessage: 'Just in case', }, - TR_TROUBLESHOOTING_UNREADABLE_WEBUSB: { - id: 'TR_TROUBLESHOOTING_UNREADABLE_WEBUSB', - defaultMessage: - "Your device is connected properly, but your browser can't communicate with it at the moment. You need to install Trezor Bridge.", - }, TR_TROUBLESHOOTING_UNREADABLE_UDEV: { id: 'TR_TROUBLESHOOTING_UNREADABLE_UDEV', defaultMessage: 'Missing udev rules', diff --git a/packages/urls/src/urls.ts b/packages/urls/src/urls.ts index 21fc334d76c9..109345e0d775 100644 --- a/packages/urls/src/urls.ts +++ b/packages/urls/src/urls.ts @@ -141,3 +141,5 @@ export const ESHOP_KEEP_METAL_SINGLE_SHARE_URL: Url = 'https://trezor.io/trezor-keep-metal-single-share'; export const COINMARKET_DOWNLOAD_INVITY_APP_URL: Url = 'https://get.invity.io'; + +export const OLD_FW_UPDATE_URL: Url = 'https://wiki.trezor.io/todo';