diff --git a/src/ble/alerts/NoGatt.tsx b/src/ble/alerts/NoGatt.tsx new file mode 100644 index 00000000..78649013 --- /dev/null +++ b/src/ble/alerts/NoGatt.tsx @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 The Pybricks Authors + +import { Intent } from '@blueprintjs/core'; +import React from 'react'; +import { CreateToast } from '../../i18nToaster'; +import { I18nId, useI18n } from './i18n'; + +const NoGatt: React.VoidFunctionComponent = () => { + const i18n = useI18n(); + return

{i18n.translate(I18nId.NoGattMessage)}

; +}; + +export const noGatt: CreateToast = (onAction) => { + return { + message: , + icon: 'error', + intent: Intent.DANGER, + onDismiss: () => onAction('dismiss'), + }; +}; diff --git a/src/ble/alerts/i18n.ts b/src/ble/alerts/i18n.ts index 192a6ca8..c48428f5 100644 --- a/src/ble/alerts/i18n.ts +++ b/src/ble/alerts/i18n.ts @@ -15,4 +15,5 @@ export enum I18nId { NoWebBluetoothLinux = 'noWebBluetooth.linux', BluetoothNotAvailableMessage = 'bluetoothNotAvailable.message', BluetoothNotAvailableSuggestion = 'bluetoothNotAvailable.suggestion', + NoGattMessage = 'noGatt.message', } diff --git a/src/ble/alerts/index.ts b/src/ble/alerts/index.ts index 53b93b33..d3f08281 100644 --- a/src/ble/alerts/index.ts +++ b/src/ble/alerts/index.ts @@ -2,7 +2,8 @@ // Copyright (c) 2022 The Pybricks Authors import { bluetoothNotAvailable } from './BluetoothNotAvailable'; +import { noGatt } from './NoGatt'; import { noWebBluetooth } from './NoWebBluetooth'; // gathers all of the alert creation functions for passing up to the top level -export default { bluetoothNotAvailable, noWebBluetooth }; +export default { bluetoothNotAvailable, noGatt, noWebBluetooth }; diff --git a/src/ble/alerts/translations/en.json b/src/ble/alerts/translations/en.json index 22090626..c1acbf34 100644 --- a/src/ble/alerts/translations/en.json +++ b/src/ble/alerts/translations/en.json @@ -8,5 +8,8 @@ "bluetoothNotAvailable": { "message": "No Bluetooth adapter could be found.", "suggestion": "Please connect or enable a Bluetooth Low Energy adapter and restart the browser." + }, + "noGatt": { + "message": "The web browser did not give permission to use Bluetooth Low Energy." } } diff --git a/src/ble/sagas.test.ts b/src/ble/sagas.test.ts index 2ee72c6d..ddccf7b3 100644 --- a/src/ble/sagas.test.ts +++ b/src/ble/sagas.test.ts @@ -314,6 +314,9 @@ describe('connect action is dispatched', () => { await runConnectUntil(saga, ConnectRunPoint.Connect); + await expect(saga.take()).resolves.toEqual( + alertsShowAlert('ble', 'noGatt'), + ); await expect(saga.take()).resolves.toEqual( bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.NoGatt, diff --git a/src/ble/sagas.ts b/src/ble/sagas.ts index e6622b18..f9549b59 100644 --- a/src/ble/sagas.ts +++ b/src/ble/sagas.ts @@ -149,6 +149,7 @@ function* handleBleConnectPybricks(): Generator { const gatt = device.gatt; if (!gatt) { + yield* put(alertsShowAlert('ble', 'noGatt')); yield* put(bleDidFailToConnectPybricks({ reason: Reason.NoGatt })); return; } diff --git a/src/notifications/i18n.ts b/src/notifications/i18n.ts index c6354e29..e8fd902d 100644 --- a/src/notifications/i18n.ts +++ b/src/notifications/i18n.ts @@ -14,7 +14,6 @@ export function useI18n(): I18n { export enum I18nId { AppNoUpdateFound = 'app.noUpdateFound', BleUnexpectedError = 'ble.unexpectedError', - BleGattPermission = 'ble.gattPermission', BleGattServiceNotFound = 'ble.gattServiceNotFound', EditorFailedToOpenFile = 'editor.failedToOpenFile', EditorFailedToSaveFile = 'editor.failedToSaveFile', diff --git a/src/notifications/sagas.test.ts b/src/notifications/sagas.test.ts index 0d84a6e1..bc1543e2 100644 --- a/src/notifications/sagas.test.ts +++ b/src/notifications/sagas.test.ts @@ -61,7 +61,6 @@ function createTestToasterSaga(): { toaster: IToaster; saga: AsyncSaga } { } test.each([ - bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.NoGatt }), bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.NoDeviceInfoService, }), @@ -130,6 +129,7 @@ test.each([ reason: BleDeviceFailToConnectReasonType.NoBluetooth, }), bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.Canceled }), + bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.NoGatt }), bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.Unknown, err: { name: 'test', message: 'unknown' }, diff --git a/src/notifications/sagas.ts b/src/notifications/sagas.ts index 002b0a19..e7c3a09a 100644 --- a/src/notifications/sagas.ts +++ b/src/notifications/sagas.ts @@ -174,10 +174,6 @@ function* showBleDeviceDidFailToConnectError( action: ReturnType, ): Generator { switch (action.reason) { - case BleDeviceFailToConnectReasonType.NoGatt: - yield* showSingleton(Level.Error, I18nId.BleGattPermission); - break; - case BleDeviceFailToConnectReasonType.NoPybricksService: yield* showSingleton(Level.Error, I18nId.BleGattServiceNotFound, { serviceName: 'Pybricks', diff --git a/src/notifications/translations/en.json b/src/notifications/translations/en.json index 798a726f..f2d956aa 100644 --- a/src/notifications/translations/en.json +++ b/src/notifications/translations/en.json @@ -3,7 +3,6 @@ "noUpdateFound": "{appName} is already up to date." }, "ble": { - "gattPermission": "The web browser did not give permission to use Bluetooth Low Energy", "gattServiceNotFound": "Connected to hub but failed to get {serviceName} service.\nEnsure that you are using the most recent firmware.\nIf the problem persists, try removing the \"{hubName}\" device in your OS Bluetooth settings, then try connecting again.", "unexpectedError": "Unexpected error while trying to connect: {errorMessage}" },