editor: use file system api for save as

This makes use of the new web file system api for a better user
experience when saving a file. It now shows a proper save as dialog
instead of just downloading the file automatically.

Fixes: https://github.com/pybricks/support/issues/84
This commit is contained in:
David Lechner
2021-12-27 12:38:51 -06:00
parent 653c03404d
commit f704d4d612
10 changed files with 199 additions and 28 deletions
+2 -1
View File
@@ -15,7 +15,8 @@
"programChanged": {
"message": "The program was changed in another window.\nDo you want to delete this program and replace it with the new program?",
"action": "Reload"
}
},
"failedToSaveFile": "Failed to save the program."
},
"flashFirmware": {
"timedOut": "The hub took too long to respond. Restart the hub and try again.",
+1
View File
@@ -12,6 +12,7 @@ export enum MessageId {
BleGattServiceNotFound = 'ble.gattServiceNotFound',
BleNoWebBluetooth = 'ble.noWebBluetooth',
BleNoBluetooth = 'ble.noBluetooth',
EditorFailedToSaveFile = 'editor.failedToSaveFile',
FlashFirmwareTimedOut = 'flashFirmware.timedOut',
FlashFirmwareBleError = 'flashFirmware.bleError',
FlashFirmwareDisconnected = 'flashFirmware.disconnected',
+3 -1
View File
@@ -15,7 +15,7 @@ import {
didFailToConnect as bleDidFailToConnect,
didConnect,
} from '../ble/actions';
import { storageChanged } from '../editor/actions';
import { didFailToSaveAs, storageChanged } from '../editor/actions';
import {
FailToFinishReasonType,
HubError,
@@ -82,6 +82,7 @@ test.each([
didFailToFinish(FailToFinishReasonType.Unknown, new Error('test error')),
didCheckForUpdate(false),
didConnect('3.0.0'),
didFailToSaveAs(new DOMException('test message', 'NotAllowedError')),
])('actions that should show notification: %o', async (action: Action) => {
const getToasts = jest.fn().mockReturnValue([]);
const show = jest.fn();
@@ -113,6 +114,7 @@ test.each([
didSucceed({} as ServiceWorkerRegistration),
didCheckForUpdate(true),
didConnect(firmwareVersion),
didFailToSaveAs(new DOMException('test message', 'AbortError')),
])('actions that should not show a notification: %o', async (action: Action) => {
const getToasts = jest.fn().mockReturnValue([]);
const show = jest.fn();
+15 -1
View File
@@ -24,7 +24,11 @@ import {
BleDeviceDidFailToConnectAction,
BleDeviceFailToConnectReasonType,
} from '../ble/actions';
import { EditorActionType, reloadProgram } from '../editor/actions';
import {
EditorActionType,
EditorDidFailToSaveAsAction,
reloadProgram,
} from '../editor/actions';
import {
FailToFinishReasonType,
FlashFirmwareActionType,
@@ -236,6 +240,15 @@ function* showBootloaderDidFailToConnectError(
}
}
function* showEditorFailToSaveFile(action: EditorDidFailToSaveAsAction): Generator {
if (action.err.name === 'AbortError') {
// user clicked cancel button - not an error
return;
}
yield* showUnexpectedError(MessageId.EditorFailedToSaveFile, action.err);
}
function* showEditorStorageChanged(): Generator {
const ch = channel<React.MouseEvent<HTMLElement>>();
@@ -408,6 +421,7 @@ export default function* (): Generator {
BootloaderConnectionActionType.DidFailToConnect,
showBootloaderDidFailToConnectError,
);
yield* takeEvery(EditorActionType.DidFailToSaveAs, showEditorFailToSaveFile);
yield* takeEvery(EditorActionType.StorageChanged, showEditorStorageChanged);
yield* takeEvery(FlashFirmwareActionType.DidFailToFinish, showFlashFirmwareError);
yield* takeEvery(MpyActionType.DidCompile, dismissCompilerError);