= ({ i18n }) => {
const [isNewFileWizardOpen, setIsNewFileWizardOpen] = useState(false);
const dispatch = useDispatch();
- const files = useSelector((s) => s.fileStorage.files);
+ const files = useSelector((s) => s.explorer.files);
return (
@@ -281,7 +281,7 @@ type FileTreeProps = {
const FileTree: React.VoidFunctionComponent = ({ i18n }) => {
const [focusedItem, setFocusedItem] = useState();
- const files = useSelector((s) => s.fileStorage.files);
+ const files = useSelector((s) => s.explorer.files);
const liveDescriptors = useLiveDescriptors(i18n);
const rootItemIndex = 'root';
diff --git a/src/explorer/newFileWizard/NewFileWizard.tsx b/src/explorer/newFileWizard/NewFileWizard.tsx
index b6d3e1df..d09b5bd0 100644
--- a/src/explorer/newFileWizard/NewFileWizard.tsx
+++ b/src/explorer/newFileWizard/NewFileWizard.tsx
@@ -41,7 +41,7 @@ const NewFileWizard: React.VoidFunctionComponent = ({
const dispatch = useDispatch();
const [fileName, setFileName] = useState('');
- const files = useSelector((s) => s.fileStorage.files);
+ const files = useSelector((s) => s.explorer.files);
const fileNameValidation = validateFileName(
fileName,
pythonFileExtension,
diff --git a/src/explorer/reducers.test.ts b/src/explorer/reducers.test.ts
new file mode 100644
index 00000000..f65e2c8c
--- /dev/null
+++ b/src/explorer/reducers.test.ts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2022 The Pybricks Authors
+
+import { uuid } from '../../test';
+import {
+ FileMetadata,
+ fileStorageDidAddItem,
+ fileStorageDidChangeItem,
+ fileStorageDidInitialize,
+ fileStorageDidRemoveItem,
+} from '../fileStorage/actions';
+import reducers from './reducers';
+
+type State = ReturnType;
+
+test('files', () => {
+ const testFile: FileMetadata = {
+ uuid: uuid(0),
+ path: 'test.file',
+ sha256: '',
+ };
+
+ const modifiedFile: FileMetadata = { ...testFile, path: 'modified.file' };
+
+ expect(testFile).not.toEqual(modifiedFile);
+
+ // initialization populates file list
+ expect(
+ reducers(
+ { files: [] as readonly FileMetadata[] } as State,
+ fileStorageDidInitialize([testFile]),
+ ).files,
+ ).toEqual([testFile]);
+
+ // adding appends an item
+ expect(
+ reducers(
+ { files: [] as readonly FileMetadata[] } as State,
+ fileStorageDidAddItem(testFile),
+ ).files,
+ ).toEqual([testFile]);
+
+ // changing replaces an item
+ expect(
+ reducers(
+ { files: [testFile] as readonly FileMetadata[] } as State,
+ fileStorageDidChangeItem(testFile, modifiedFile),
+ ).files,
+ ).toEqual([modifiedFile]);
+
+ // removing deletes an item
+ expect(
+ reducers(
+ { files: [testFile] as readonly FileMetadata[] } as State,
+ fileStorageDidRemoveItem(testFile),
+ ).files,
+ ).not.toContain(testFile);
+});
diff --git a/src/explorer/reducers.ts b/src/explorer/reducers.ts
index 03f36dfd..d820af8c 100644
--- a/src/explorer/reducers.ts
+++ b/src/explorer/reducers.ts
@@ -1,8 +1,35 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
-import { combineReducers } from 'redux';
+import { Reducer, combineReducers } from 'redux';
+import {
+ FileMetadata,
+ fileStorageDidAddItem,
+ fileStorageDidChangeItem,
+ fileStorageDidInitialize,
+ fileStorageDidRemoveItem,
+} from '../fileStorage/actions';
import renameFileDialog from './renameFileDialog/reducers';
-export default combineReducers({ renameFileDialog });
+const files: Reducer = (state = [], action) => {
+ if (fileStorageDidInitialize.matches(action)) {
+ return [...action.files];
+ }
+
+ if (fileStorageDidAddItem.matches(action)) {
+ return [...state, action.file];
+ }
+
+ if (fileStorageDidChangeItem.matches(action)) {
+ return [...state].map((f) => (f.uuid === action.file.uuid ? action.file : f));
+ }
+
+ if (fileStorageDidRemoveItem.matches(action)) {
+ return [...state].filter((value) => value.uuid !== action.file.uuid);
+ }
+
+ return state;
+};
+
+export default combineReducers({ files, renameFileDialog });
diff --git a/src/explorer/renameFileDialog/RenameFileDialog.tsx b/src/explorer/renameFileDialog/RenameFileDialog.tsx
index acf42cee..34ba7672 100644
--- a/src/explorer/renameFileDialog/RenameFileDialog.tsx
+++ b/src/explorer/renameFileDialog/RenameFileDialog.tsx
@@ -24,7 +24,7 @@ const RenameFileDialog: React.VFC = () => {
const [baseName, extension] = oldName.split(/(\.\w+)$/);
const [newName, setNewName] = useState(baseName);
- const files = useSelector((s) => s.fileStorage.files);
+ const files = useSelector((s) => s.explorer.files);
const result = validateFileName(
newName,
extension,
diff --git a/src/explorer/sagas.ts b/src/explorer/sagas.ts
index 5bcac7e9..bcfc7e47 100644
--- a/src/explorer/sagas.ts
+++ b/src/explorer/sagas.ts
@@ -120,7 +120,7 @@ function* handleExplorerImportFiles(): Generator {
const text = yield* call(() => file.text());
const [baseName] = file.name.split(pythonFileExtensionRegex);
- const existingFiles = yield* select((s: RootState) => s.fileStorage.files);
+ const existingFiles = yield* select((s: RootState) => s.explorer.files);
const result = validateFileName(
baseName,
diff --git a/src/fileStorage/reducers.test.ts b/src/fileStorage/reducers.test.ts
index 8ea27596..27278f46 100644
--- a/src/fileStorage/reducers.test.ts
+++ b/src/fileStorage/reducers.test.ts
@@ -2,14 +2,7 @@
// Copyright (c) 2022 The Pybricks Authors
import { AnyAction } from 'redux';
-import { uuid } from '../../test';
-import {
- FileMetadata,
- fileStorageDidAddItem,
- fileStorageDidChangeItem,
- fileStorageDidInitialize,
- fileStorageDidRemoveItem,
-} from './actions';
+import { fileStorageDidInitialize } from './actions';
import reducers from './reducers';
type State = ReturnType;
@@ -17,7 +10,6 @@ type State = ReturnType;
test('initial state', () => {
expect(reducers(undefined, {} as AnyAction)).toMatchInlineSnapshot(`
Object {
- "files": Array [],
"isInitialized": false,
}
`);
@@ -29,47 +21,3 @@ test('isInitialized', () => {
.isInitialized,
).toBeTruthy();
});
-
-test('fileNames', () => {
- const testFile: FileMetadata = {
- uuid: uuid(0),
- path: 'test.file',
- sha256: '',
- };
-
- const modifiedFile: FileMetadata = { ...testFile, path: 'modified.file' };
-
- expect(testFile).not.toEqual(modifiedFile);
-
- // initialization populates file list
- expect(
- reducers(
- { files: [] as readonly FileMetadata[] } as State,
- fileStorageDidInitialize([testFile]),
- ).files,
- ).toEqual([testFile]);
-
- // adding appends an item
- expect(
- reducers(
- { files: [] as readonly FileMetadata[] } as State,
- fileStorageDidAddItem(testFile),
- ).files,
- ).toEqual([testFile]);
-
- // changing replaces an item
- expect(
- reducers(
- { files: [testFile] as readonly FileMetadata[] } as State,
- fileStorageDidChangeItem(testFile, modifiedFile),
- ).files,
- ).toEqual([modifiedFile]);
-
- // removing deletes an item
- expect(
- reducers(
- { files: [testFile] as readonly FileMetadata[] } as State,
- fileStorageDidRemoveItem(testFile),
- ).files,
- ).not.toContain(testFile);
-});
diff --git a/src/fileStorage/reducers.ts b/src/fileStorage/reducers.ts
index 723be334..84676062 100644
--- a/src/fileStorage/reducers.ts
+++ b/src/fileStorage/reducers.ts
@@ -2,13 +2,7 @@
// Copyright (c) 2022 The Pybricks Authors
import { Reducer, combineReducers } from 'redux';
-import {
- FileMetadata,
- fileStorageDidAddItem,
- fileStorageDidChangeItem,
- fileStorageDidInitialize,
- fileStorageDidRemoveItem,
-} from './actions';
+import { fileStorageDidInitialize } from './actions';
const isInitialized: Reducer = (state = false, action) => {
if (fileStorageDidInitialize.matches(action)) {
@@ -18,24 +12,4 @@ const isInitialized: Reducer = (state = false, action) => {
return state;
};
-const files: Reducer = (state = [], action) => {
- if (fileStorageDidInitialize.matches(action)) {
- return [...action.files];
- }
-
- if (fileStorageDidAddItem.matches(action)) {
- return [...state, action.file];
- }
-
- if (fileStorageDidChangeItem.matches(action)) {
- return [...state].map((f) => (f.uuid === action.file.uuid ? action.file : f));
- }
-
- if (fileStorageDidRemoveItem.matches(action)) {
- return [...state].filter((value) => value.uuid !== action.file.uuid);
- }
-
- return state;
-};
-
-export default combineReducers({ isInitialized, files });
+export default combineReducers({ isInitialized });