add notifications for firmware flash errors

This commit is contained in:
David Lechner
2021-01-23 15:27:36 -06:00
parent 1a6f77ece3
commit 5d1311216c
4 changed files with 130 additions and 0 deletions
+15
View File
@@ -13,6 +13,21 @@
"action": "Reload"
}
},
"flashFirmware": {
"connectionFailed": "Could not connect to the hub. Restart the hub and try again.",
"timedOut": "The hub took too long to respond. Restart the hub and try again.",
"bleError": "There was a problem with Bluetooth.",
"disconnected": "The hub was disconnected before flashing was completed. Restart the hub and try again.",
"hubError": "The hub said something went wrong.",
"unsupportedDevice": "The connected hub is not supported.",
"deviceMismatch": "The firmware is for a different kind of hub from the connected hub.",
"failToFetch": "Failed to fetch firmware from the server: {status}",
"badZipFile": "The firmware.zip file is missing required files or is corrupt.",
"badMetadata": "The firmware.metadata.py file contains missing or invalid entries. Fix it then try again.",
"compileError": "The included main.py file could not be compiled. Fix it then try again.",
"sizeTooBig": "The combined firmware and main.py are too big to fit in the flash memory.",
"unexpectedError": "Unexpected error while trying to flash firmware: {errorMessage}"
},
"mpy": {
"error": "{errorMessage}"
},
+13
View File
@@ -10,6 +10,19 @@ export enum MessageId {
BleGattPermission = 'ble.gattPermission',
BleGattServiceNotFound = 'ble.gattServiceNotFound',
BleNoWebBluetooth = 'ble.noWebBluetooth',
FlashFirmwareConnectionFailed = 'flashFirmware.connectionFailed',
FlashFirmwareTimedOut = 'flashFirmware.timedOut',
FlashFirmwareBleError = 'flashFirmware.bleError',
FlashFirmwareDisconnected = 'flashFirmware.disconnected',
FlashFirmwareHubError = 'flashFirmware.hubError',
FlashFirmwareUnsupportedDevice = 'flashFirmware.unsupportedDevice',
FlashFirmwareDeviceMismatch = 'flashFirmware.deviceMismatch',
FlashFirmwareFailToFetch = 'flashFirmware.failToFetch',
FlashFirmwareBadZipFile = 'flashFirmware.badZipFile',
FlashFirmwareBadMetadata = 'flashFirmware.badMetadata',
FlashFirmwareCompileError = 'flashFirmware.compileError',
FlashFirmwareSizeTooBig = 'flashFirmware.sizeTooBig',
FlashFirmwareUnexpectedError = 'flashFirmware.unexpectedError',
ProgramChangedMessage = 'editor.programChanged.message',
ProgramChangedAction = 'editor.programChanged.action',
ServiceWorkerUpdateMessage = 'serviceWorker.update.message',
+33
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2021 The Pybricks Authors
import { IToaster } from '@blueprintjs/core';
import { FirmwareReaderError, FirmwareReaderErrorCode } from '@pybricks/firmware';
import { AsyncSaga } from '../../test';
import { Action } from '../actions';
import {
@@ -9,6 +10,12 @@ import {
didFailToConnect as bleDidFailToConnect,
} from '../actions/ble';
import { storageChanged } from '../actions/editor';
import {
FailToFinishReasonType,
HubError,
MetadataProblem,
didFailToFinish,
} from '../actions/flash-firmware';
import {
BootloaderConnectionFailureReason,
didFailToConnect as bootloaderDidFailToConnect,
@@ -37,6 +44,32 @@ test.each([
add('warning', 'message'),
add('error', 'message', 'url'),
didUpdate({} as ServiceWorkerRegistration),
didFailToFinish(FailToFinishReasonType.FailedToConnect),
didFailToFinish(FailToFinishReasonType.TimedOut),
didFailToFinish(
FailToFinishReasonType.BleError,
new DOMException('test error', 'NetworkError'),
),
didFailToFinish(FailToFinishReasonType.Disconnected),
didFailToFinish(FailToFinishReasonType.HubError, HubError.UnknownCommand),
didFailToFinish(FailToFinishReasonType.NoFirmware),
didFailToFinish(FailToFinishReasonType.DeviceMismatch),
didFailToFinish(
FailToFinishReasonType.FailedToFetch,
new Response(undefined, { status: 404 }),
),
didFailToFinish(
FailToFinishReasonType.ZipError,
new FirmwareReaderError(FirmwareReaderErrorCode.ZipError),
),
didFailToFinish(
FailToFinishReasonType.BadMetadata,
'device-id',
MetadataProblem.NotSupported,
),
didFailToFinish(FailToFinishReasonType.FailedToCompile),
didFailToFinish(FailToFinishReasonType.FirmwareSize),
didFailToFinish(FailToFinishReasonType.Unknown, new Error('test error')),
])('actions that should show notification: %o', async (action: Action) => {
const getToasts = jest.fn().mockReturnValue([]);
const show = jest.fn();
+69
View File
@@ -21,6 +21,11 @@ import {
BleDeviceFailToConnectReasonType,
} from '../actions/ble';
import { EditorActionType, reloadProgram } from '../actions/editor';
import {
FailToFinishReasonType,
FlashFirmwareActionType,
FlashFirmwareDidFailToFinishAction,
} from '../actions/flash-firmware';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidFailToConnectAction,
@@ -226,6 +231,69 @@ function* showEditorStorageChanged(): Generator {
yield put(reloadProgram());
}
function* showFlashFirmwareError(
action: FlashFirmwareDidFailToFinishAction,
): Generator {
switch (action.reason.reason) {
case FailToFinishReasonType.FailedToConnect:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareConnectionFailed);
break;
case FailToFinishReasonType.TimedOut:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareTimedOut);
break;
case FailToFinishReasonType.BleError:
yield* showUnexpectedError(
MessageId.FlashFirmwareBleError,
action.reason.err,
);
break;
case FailToFinishReasonType.Disconnected:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareDisconnected);
break;
case FailToFinishReasonType.HubError:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareHubError);
if (process.env.NODE_ENV !== 'test') {
console.error(action.reason.hubError);
}
break;
case FailToFinishReasonType.NoFirmware:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareUnsupportedDevice);
break;
case FailToFinishReasonType.DeviceMismatch:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareDeviceMismatch);
break;
case FailToFinishReasonType.FailedToFetch:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareFailToFetch, {
status: action.reason.response.statusText,
});
break;
case FailToFinishReasonType.ZipError:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareBadZipFile);
if (process.env.NODE_ENV !== 'test') {
console.error(action.reason.err);
}
break;
case FailToFinishReasonType.BadMetadata:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareBadMetadata);
if (process.env.NODE_ENV !== 'test') {
console.error(action.reason.property, action.reason.problem);
}
break;
case FailToFinishReasonType.FailedToCompile:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareCompileError);
break;
case FailToFinishReasonType.FirmwareSize:
yield* showSingleton(Level.Error, MessageId.FlashFirmwareSizeTooBig);
break;
case FailToFinishReasonType.Unknown:
yield* showUnexpectedError(
MessageId.FlashFirmwareUnexpectedError,
action.reason.err,
);
break;
}
}
function* dismissCompilerError(): Generator {
const { toaster } = (yield getContext('notification')) as NotificationContext;
toaster.dismiss(MessageId.MpyError);
@@ -282,6 +350,7 @@ export default function* (): Generator {
showBootloaderDidFailToConnectError,
);
yield takeEvery(EditorActionType.StorageChanged, showEditorStorageChanged);
yield takeEvery(FlashFirmwareActionType.DidFailToFinish, showFlashFirmwareError);
yield takeEvery(MpyActionType.DidCompile, dismissCompilerError);
yield takeEvery(MpyActionType.DidFailToCompile, showCompilerError);
yield takeEvery(NotificationActionType.Add, addNotification);