mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
add notifications for firmware flash errors
This commit is contained in:
@@ -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}"
|
||||
},
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user