diff --git a/src/app/constants.ts b/src/app/constants.ts index d85545af..90d4addc 100644 --- a/src/app/constants.ts +++ b/src/app/constants.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2021-2022 The Pybricks Authors +// Copyright (c) 2021-2023 The Pybricks Authors import docsPackage from '@pybricks/ide-docs/package.json'; // Definitions for compile-time UI settings. @@ -81,3 +81,9 @@ export const docsPathPrefix = `static/docs/v${docsPackage.version}/`; /** The index page of the docs. */ export const docsDefaultPage = `${docsPathPrefix}index.html`; + +/** The ZIP file extension ('.zip') */ +export const zipFileExtension = '.zip'; + +/** The ZIP file MIME type ('application/zip') */ +export const zipFileMimeType = 'application/zip'; diff --git a/src/explorer/sagas.ts b/src/explorer/sagas.ts index 5d272c6e..d500c4d9 100644 --- a/src/explorer/sagas.ts +++ b/src/explorer/sagas.ts @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors +// Copyright (c) 2022-2023 The Pybricks Authors import { fileOpen, fileSave } from 'browser-fs-access'; import JSZip from 'jszip'; import { call, put, race, select, take, takeEvery } from 'typed-redux-saga/macro'; import { alertsShowAlert } from '../alerts/actions'; +import { zipFileExtension, zipFileMimeType } from '../app/constants'; import { editorActivateFile, editorCloseFile, @@ -122,14 +123,14 @@ function* handleExplorerArchiveAllFiles(): Generator { const zipData = yield* call(() => zip.generateAsync({ type: 'blob' })); - const fileName = `pybricks-backup-${timestamp()}.zip`; + const fileName = `pybricks-backup-${timestamp()}${zipFileExtension}`; yield* call(() => fileSave(zipData, { id: 'pybricksCodeFileStorageArchive', fileName, - extensions: ['.zip'], - mimeTypes: ['application/zip'], + extensions: [zipFileExtension], + mimeTypes: [zipFileMimeType], // TODO: translate description description: 'Zip Files', }), diff --git a/src/firmware/installPybricksDialog/InstallPybricksDialog.tsx b/src/firmware/installPybricksDialog/InstallPybricksDialog.tsx index 0b438d50..fb9661c5 100644 --- a/src/firmware/installPybricksDialog/InstallPybricksDialog.tsx +++ b/src/firmware/installPybricksDialog/InstallPybricksDialog.tsx @@ -28,7 +28,12 @@ import { useDropzone } from 'react-dropzone'; import { useDispatch } from 'react-redux'; import { useLocalStorage } from 'usehooks-ts'; import { alertsShowAlert } from '../../alerts/actions'; -import { appName, legoMindstormsRegisteredTrademark } from '../../app/constants'; +import { + appName, + legoMindstormsRegisteredTrademark, + zipFileExtension, + zipFileMimeType, +} from '../../app/constants'; import HelpButton from '../../components/HelpButton'; import { Hub, hubBootloaderType } from '../../components/hubPicker'; import { HubPicker } from '../../components/hubPicker/HubPicker'; @@ -201,8 +206,8 @@ const SelectHubPanel: React.VoidFunctionComponent = ({ try { const file = await fileOpen({ id: 'customFirmware', - mimeTypes: ['application/zip'], - extensions: ['.zip'], + mimeTypes: [zipFileMimeType], + extensions: [zipFileExtension], // TODO: translate description description: 'Zip Files', excludeAcceptAllOption: true, @@ -236,7 +241,7 @@ const SelectHubPanel: React.VoidFunctionComponent = ({ ); const { getRootProps, getInputProps } = useDropzone({ - accept: { 'application/zip': ['.zip'] }, + accept: { [zipFileMimeType]: [zipFileExtension] }, multiple: false, // react-dropzone doesn't allow full control of File System API, so we // implement our own using browser-fs-access instead.