mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 10:35:11 +00:00
pybricksMicropython/lib: add module
This creates a new module for dealing with stuff specific to Pybricks MicroPython.
This commit is contained in:
@@ -14,72 +14,19 @@ import {
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
FileNameValidationResult,
|
||||
pythonFileExtension,
|
||||
validateFileName,
|
||||
} from '../pybricksMicropython/lib';
|
||||
import { useSelector } from '../reducers';
|
||||
import { FileExtension, Hub, explorerCreateNewFile } from './actions';
|
||||
import { Hub, explorerCreateNewFile } from './actions';
|
||||
import { NewFileWizardStringId } from './i18n';
|
||||
import en from './i18n.en.json';
|
||||
|
||||
// This should be set to the most commonly used hub.
|
||||
const defaultHub = Hub.Technic;
|
||||
|
||||
/** File name validation results. */
|
||||
enum FileNameValidationResult {
|
||||
/** The file name is acceptable. */
|
||||
IsOk,
|
||||
/** The file name is an empty string. */
|
||||
IsEmpty,
|
||||
/** The file name contains spaces. */
|
||||
HasSpaces,
|
||||
/** The file name include the file file extension. */
|
||||
HasFileExtension,
|
||||
/** The first character is not a letter or underscore. */
|
||||
HasInvalidFirstCharacter,
|
||||
/** The file name has invalid characters. */
|
||||
HasInvalidCharacters,
|
||||
/** A file with the same name already exists. */
|
||||
AlreadyExists,
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the file name according to a number of criteria.
|
||||
*
|
||||
* @param fileName The file name (without extension).
|
||||
* @param extension The file extension (include ".").
|
||||
* @param existingFiles List of existing files.
|
||||
* @returns The result of the validation.
|
||||
*/
|
||||
function validateFileName(
|
||||
fileName: string,
|
||||
extension: string,
|
||||
existingFiles: ReadonlyArray<string>,
|
||||
): FileNameValidationResult {
|
||||
if (existingFiles.includes(`${fileName}${extension}`)) {
|
||||
return FileNameValidationResult.AlreadyExists;
|
||||
}
|
||||
|
||||
if (fileName.length === 0) {
|
||||
return FileNameValidationResult.IsEmpty;
|
||||
}
|
||||
|
||||
if (fileName.match(/\s/)) {
|
||||
return FileNameValidationResult.HasSpaces;
|
||||
}
|
||||
|
||||
if (fileName.endsWith(extension)) {
|
||||
return FileNameValidationResult.HasFileExtension;
|
||||
}
|
||||
|
||||
if (!fileName.match(/^[a-zA-Z_]/)) {
|
||||
return FileNameValidationResult.HasInvalidFirstCharacter;
|
||||
}
|
||||
|
||||
if (!fileName.match(/^[a-zA-Z0-9_-]+$/)) {
|
||||
return FileNameValidationResult.HasInvalidCharacters;
|
||||
}
|
||||
|
||||
return FileNameValidationResult.IsOk;
|
||||
}
|
||||
|
||||
type FileNameHelpTextProps = {
|
||||
validation: FileNameValidationResult;
|
||||
};
|
||||
@@ -169,7 +116,7 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
|
||||
|
||||
const handleFileNameChanged = (fileName: string) => {
|
||||
setFileNameValidation(
|
||||
validateFileName(fileName, FileExtension.Python, fileNames),
|
||||
validateFileName(fileName, pythonFileExtension, fileNames),
|
||||
);
|
||||
setFileName(fileName);
|
||||
};
|
||||
@@ -194,7 +141,7 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
|
||||
value={fileName}
|
||||
inputRef={fileNameInputRef}
|
||||
intent={fileNameIntent}
|
||||
rightElement={<Tag>{FileExtension.Python}</Tag>}
|
||||
rightElement={<Tag>{pythonFileExtension}</Tag>}
|
||||
onChange={(e) => handleFileNameChanged(e.target.value)}
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -224,7 +171,7 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
|
||||
dispatch(
|
||||
explorerCreateNewFile(
|
||||
fileName,
|
||||
FileExtension.Python,
|
||||
pythonFileExtension,
|
||||
hubType,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { createAction } from '../actions';
|
||||
import { pythonFileExtension } from '../pybricksMicropython/lib';
|
||||
|
||||
/** Supported file extensions. */
|
||||
export enum FileExtension {
|
||||
/** Python (.py) */
|
||||
Python = '.py',
|
||||
}
|
||||
type SupportedFileExtension = typeof pythonFileExtension;
|
||||
|
||||
/** Supported hub types. */
|
||||
export enum Hub {
|
||||
@@ -32,7 +30,7 @@ export enum Hub {
|
||||
* @param hub The type of hub this file is for.
|
||||
*/
|
||||
export const explorerCreateNewFile = createAction(
|
||||
(fileName: string, fileExtension: FileExtension, hub: Hub) => ({
|
||||
(fileName: string, fileExtension: SupportedFileExtension, hub: Hub) => ({
|
||||
type: 'explorer.action.createNewFile',
|
||||
fileName,
|
||||
fileExtension,
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { AsyncSaga } from '../../test';
|
||||
import { FileExtension, Hub, explorerCreateNewFile } from './actions';
|
||||
import { pythonFileExtension } from '../pybricksMicropython/lib';
|
||||
import { Hub, explorerCreateNewFile } from './actions';
|
||||
import explorer from './sagas';
|
||||
|
||||
describe('handleExplorerCreateNewFile', () => {
|
||||
it('should dispatch fileStorage action', async () => {
|
||||
const saga = new AsyncSaga(explorer);
|
||||
|
||||
saga.put(explorerCreateNewFile('test', FileExtension.Python, Hub.Technic));
|
||||
saga.put(explorerCreateNewFile('test', pythonFileExtension, Hub.Technic));
|
||||
|
||||
const action = await saga.take();
|
||||
expect(action).toMatchInlineSnapshot(`
|
||||
|
||||
Reference in New Issue
Block a user