ble/alerts: move and improve no web bluetooth message

This commit is contained in:
David Lechner
2022-07-15 13:16:53 -05:00
parent b2b173e103
commit f86a9ad051
13 changed files with 106 additions and 26 deletions
+2
View File
@@ -3,12 +3,14 @@
import { IToastProps } from '@blueprintjs/core';
import alerts from './alerts/alerts';
import ble from './ble/alerts';
import explorer from './explorer/alerts';
import { CreateToast } from './i18nToaster';
/** This collects alerts from all of the subsystems of the app */
const alertDomains = {
alerts,
ble,
explorer,
};
+49
View File
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { Button, Intent } from '@blueprintjs/core';
import React from 'react';
import { CreateToast } from '../../i18nToaster';
import { isIOS, isLinux } from '../../utils/os';
import { I18nId, useI18n } from './i18n';
const NoWebBluetooth: React.VoidFunctionComponent = () => {
const i18n = useI18n();
return (
<>
<p>{i18n.translate(I18nId.NoWebBluetoothMessage)}</p>
{!isLinux() && !isIOS() && (
<p>{i18n.translate(I18nId.NoWebBluetoothSuggestion)}</p>
)}
{isLinux() && (
<>
<p>{i18n.translate(I18nId.NoWebBluetoothLinux)}</p>
<p>
<code>
chrome://flags/#enable-experimental-web-platform-features
</code>
<Button
icon="duplicate"
small={true}
minimal={true}
onClick={() =>
navigator.clipboard.writeText(
'chrome://flags/#enable-experimental-web-platform-features',
)
}
/>
</p>
</>
)}
</>
);
};
export const noWebBluetooth: CreateToast = (onAction) => {
return {
message: <NoWebBluetooth />,
icon: 'error',
intent: Intent.DANGER,
onDismiss: () => onAction('dismiss'),
};
};
+12
View File
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { lookup } from '../../../test';
import { I18nId } from './i18n';
import en from './translations/en.json';
describe('Ensure .json file has matches for I18nId', () => {
test.each(Object.values(I18nId))('%s', (id) => {
expect(lookup(en, id)).toBeDefined();
});
});
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { I18n, useI18n as useShopifyI18n } from '@shopify/react-i18n';
export function useI18n(): I18n {
// istanbul ignore next: babel-loader rewrites this line
const [i18n] = useShopifyI18n();
return i18n;
}
export enum I18nId {
NoWebBluetoothMessage = 'noWebBluetooth.message',
NoWebBluetoothSuggestion = 'noWebBluetooth.suggestion',
NoWebBluetoothLinux = 'noWebBluetooth.linux',
}
+7
View File
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { noWebBluetooth } from './NoWebBluetooth';
// gathers all of the alert creation functions for passing up to the top level
export default { noWebBluetooth };
+8
View File
@@ -0,0 +1,8 @@
{
"noWebBluetooth": {
"message": "This browser does not support Web Bluetooth or it is not enabled.",
"suggestion": "Use a supported browser such as Google Chrome or Microsoft Edge.",
"linux": "Web Bluetooth is experimental on Linux and must be manually enabled. Copy the link below and paste it in the address bar.",
"action": "More Info"
}
}
+4
View File
@@ -4,6 +4,7 @@
import { HubType } from '@pybricks/firmware';
import { MockProxy, mock } from 'jest-mock-extended';
import { AsyncSaga } from '../../test';
import { alertsShowAlert } from '../alerts/actions';
import {
bleDIServiceDidReceiveFirmwareRevision,
bleDIServiceDidReceivePnPId,
@@ -241,6 +242,9 @@ describe('connect action is dispatched', () => {
it('should fail if no web bluetooth', async () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
alertsShowAlert('ble', 'noWebBluetooth'),
);
await expect(saga.take()).resolves.toEqual(
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoWebBluetooth,
+2
View File
@@ -15,6 +15,7 @@ import {
takeEvery,
takeMaybe,
} from 'typed-redux-saga/macro';
import { alertsShowAlert } from '../alerts/actions';
import {
bleDIServiceDidReceiveFirmwareRevision,
bleDIServiceDidReceivePnPId,
@@ -101,6 +102,7 @@ function* handleWriteUart(
function* handleBleConnectPybricks(): Generator {
if (navigator.bluetooth === undefined) {
yield* put(alertsShowAlert('ble', 'noWebBluetooth'));
yield* put(bleDidFailToConnectPybricks({ reason: Reason.NoWebBluetooth }));
return;
}
+2
View File
@@ -5,6 +5,7 @@
import { END, eventChannel } from 'redux-saga';
import { call, cancel, put, spawn, takeEvery, takeMaybe } from 'typed-redux-saga/macro';
import { alertsShowAlert } from '../alerts/actions';
import { ensureError } from '../utils';
import {
BootloaderConnectionFailureReason as Reason,
@@ -42,6 +43,7 @@ function* write(
function* handleConnect(): Generator {
if (navigator.bluetooth === undefined) {
yield* put(alertsShowAlert('ble', 'noWebBluetooth'));
yield* put(didFailToConnect(Reason.NoWebBluetooth));
return;
}
-1
View File
@@ -16,7 +16,6 @@ export enum I18nId {
BleUnexpectedError = 'ble.unexpectedError',
BleGattPermission = 'ble.gattPermission',
BleGattServiceNotFound = 'ble.gattServiceNotFound',
BleNoWebBluetooth = 'ble.noWebBluetooth',
BleNoBluetooth = 'ble.noBluetooth',
EditorFailedToOpenFile = 'editor.failedToOpenFile',
EditorFailedToSaveFile = 'editor.failedToSaveFile',
+4 -4
View File
@@ -61,9 +61,6 @@ function createTestToasterSaga(): { toaster: IToaster; saga: AsyncSaga } {
}
test.each([
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoWebBluetooth,
}),
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoBluetooth,
}),
@@ -81,7 +78,6 @@ test.each([
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.Unknown, <Error>{
message: 'test',
}),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.NoWebBluetooth),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.NoBluetooth),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.GattServiceNotFound),
didFailToCompile(['reason']),
@@ -135,7 +131,11 @@ test.each([
});
test.each([
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoWebBluetooth,
}),
bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.Canceled }),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.NoWebBluetooth),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.Canceled),
didFailToFinish(FailToFinishReasonType.FailedToConnect),
serviceWorkerDidSucceed(),
-20
View File
@@ -193,16 +193,6 @@ function* showBleDeviceDidFailToConnectError(
case BleDeviceFailToConnectReasonType.NoBluetooth:
yield* showSingleton(Level.Error, I18nId.BleNoBluetooth);
break;
case BleDeviceFailToConnectReasonType.NoWebBluetooth:
yield* showSingleton(
Level.Error,
I18nId.BleNoWebBluetooth,
undefined,
helpAction(
'https://github.com/WebBluetoothCG/web-bluetooth/blob/master/implementation-status.md',
),
);
break;
case BleDeviceFailToConnectReasonType.Unknown:
yield* showUnexpectedError(I18nId.BleUnexpectedError, action.err);
break;
@@ -219,16 +209,6 @@ function* showBootloaderDidFailToConnectError(
hubName: 'LEGO Bootloader',
});
break;
case BootloaderConnectionFailureReason.NoWebBluetooth:
yield* showSingleton(
Level.Error,
I18nId.BleNoWebBluetooth,
undefined,
helpAction(
'https://github.com/WebBluetoothCG/web-bluetooth/blob/master/implementation-status.md',
),
);
break;
case BootloaderConnectionFailureReason.NoBluetooth:
yield* showSingleton(Level.Error, I18nId.BleNoBluetooth);
break;
-1
View File
@@ -5,7 +5,6 @@
"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.",
"noWebBluetooth": "This web browser does not support Web Bluetooth or it is not enabled.",
"noBluetooth": "No Bluetooth adapter could be found. Please connect or enable a Bluetooth Low Energy adapter and restart the browser.",
"unexpectedError": "Unexpected error while trying to connect: {errorMessage}"
},