Skip to content

Commit 8bd5a46

Browse files
committed
Add functionality for renaming folders instant sync Google Drive
1 parent ebe1f37 commit 8bd5a46

File tree

4 files changed

+145
-21
lines changed

4 files changed

+145
-21
lines changed

src/commons/fileSystem/FileSystemActions.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import {
1313
SET_PERSISTENCE_FILE_LAST_EDIT_BY_PATH,
1414
UPDATE_PERSISTENCE_FILE_PATH_AND_NAME_BY_PATH,
1515
UPDATE_LAST_EDITED_FILE_PATH,
16-
UPDATE_REFRESH_FILE_VIEW_KEY } from './FileSystemTypes';
16+
UPDATE_REFRESH_FILE_VIEW_KEY,
17+
UPDATE_PERSISTENCE_FOLDER_PATH_AND_NAME_BY_PATH} from './FileSystemTypes';
1718

1819
export const setInBrowserFileSystem = createAction(
1920
SET_IN_BROWSER_FILE_SYSTEM,
@@ -50,6 +51,11 @@ export const updatePersistenceFilePathAndNameByPath = createAction(
5051
(oldPath: string, newPath: string, newFileName: string) => ({ payload: {oldPath, newPath, newFileName}})
5152
);
5253

54+
export const updatePersistenceFolderPathAndNameByPath = createAction(
55+
UPDATE_PERSISTENCE_FOLDER_PATH_AND_NAME_BY_PATH,
56+
(oldPath: string, newPath: string, oldFolderName: string, newFolderName: string) => ({ payload: {oldPath, newPath, oldFolderName, newFolderName}})
57+
);
58+
5359
export const deleteAllPersistenceFiles = createAction(
5460
DELETE_ALL_PERSISTENCE_FILES,
5561
() => ({ payload: {} })

src/commons/fileSystem/FileSystemReducer.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
updateLastEditedFilePath,
1515
updateRefreshFileViewKey,
1616
updatePersistenceFilePathAndNameByPath,
17+
updatePersistenceFolderPathAndNameByPath,
1718
} from './FileSystemActions';
1819
import { FileSystemState } from './FileSystemTypes';
1920

@@ -98,6 +99,43 @@ export const FileSystemReducer: Reducer<FileSystemState, SourceActionType> = cre
9899
filesState[persistenceFileFindIndex] = newPersistenceFile;
99100
state.persistenceFileArray = filesState;
100101
})
102+
.addCase(updatePersistenceFolderPathAndNameByPath, (state, action) => {
103+
const filesState = state['persistenceFileArray'];
104+
const persistenceFileFindIndex = filesState.findIndex(e => e.path === action.payload.oldPath);
105+
if (persistenceFileFindIndex === -1) {
106+
return;
107+
}
108+
// get current level of folder
109+
const regexResult = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(action.payload.newPath)!;
110+
111+
const currFolderSplit: string[] = regexResult[0].slice(1).split("/");
112+
const currFolderIndex = currFolderSplit.length - 1;
113+
114+
// /fold1/ becomes ["fold1"]
115+
// /fold1/fold2/ becomes ["fold1", "fold2"]
116+
// If in top level folder, becomes [""]
117+
118+
console.log(regexResult, currFolderSplit, "a1");
119+
120+
// update all files that are its children
121+
state.persistenceFileArray = filesState.filter(e => e.path).map((e => {
122+
const r = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(e.path!)!;
123+
const currParentFolders = r[0].slice(1).split("/");
124+
console.log("currParentFolders", currParentFolders, "folderLevel", currFolderIndex);
125+
if (currParentFolders.length <= currFolderIndex) {
126+
return e; // not a child of folder
127+
}
128+
if (currParentFolders[currFolderIndex] !== action.payload.oldFolderName) {
129+
return e; // not a child of folder
130+
}
131+
// only children remain
132+
currParentFolders[currFolderIndex] = action.payload.newFolderName;
133+
currParentFolders[0] = "/" + currParentFolders[0];
134+
const newPath = currParentFolders.join("/");
135+
console.log("from", e.path, "to", newPath);
136+
return {...e, path: newPath};
137+
}));
138+
})
101139
.addCase(setPersistenceFileLastEditByPath, (state, action) => {
102140
const filesState = state['persistenceFileArray'];
103141
const persistenceFileFindIndex = filesState.findIndex(e => e.path === action.payload.path);

src/commons/fileSystem/FileSystemTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const DELETE_PERSISTENCE_FILE = 'DELETE_PERSISTENCE_FILE';
99
export const DELETE_ALL_GITHUB_SAVE_INFO = 'DELETE_ALL_GITHUB_SAVE_INFO';
1010
export const DELETE_ALL_PERSISTENCE_FILES = 'DELETE_ALL_PERSISTENCE_FILES';
1111
export const UPDATE_PERSISTENCE_FILE_PATH_AND_NAME_BY_PATH = 'UPDATE_PERSISTENCE_FILE_PATH_AND_NAME_BY_PATH';
12+
export const UPDATE_PERSISTENCE_FOLDER_PATH_AND_NAME_BY_PATH = 'UPDATE_PERSISTENCE_FOLDER_PATH_AND_NAME_BY_PATH';
1213
export const SET_PERSISTENCE_FILE_LAST_EDIT_BY_PATH = 'SET_PERSISTENCE_FILE_LAST_EDIT_BY_PATH';
1314
export const UPDATE_LAST_EDITED_FILE_PATH = 'UPDATE_LAST_EDITED_FILE_PATH';
1415
export const UPDATE_REFRESH_FILE_VIEW_KEY = 'UPDATE_REFRESH_FILE_VIEW_KEY';

src/commons/sagas/PersistenceSaga.tsx

Lines changed: 99 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
import { AsyncReturnType } from '../utils/TypeHelper';
3737
import { safeTakeEvery as takeEvery, safeTakeLatest as takeLatest } from './SafeEffects';
3838
import { WORKSPACE_BASE_PATHS } from 'src/pages/fileSystem/createInBrowserFileSystem';
39+
import { EditorTabState } from '../workspace/WorkspaceTypes';
3940

4041
const DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'];
4142
const SCOPES =
@@ -195,7 +196,7 @@ export function* persistenceSaga(): SagaIterator {
195196
// TODO find a file to open instead of deleting all active tabs?
196197
// TODO without modifying WorkspaceReducer in one function this would cause errors - called by onChange of Playground.tsx?
197198
// TODO change behaviour of WorkspaceReducer to not create program.js every time folder mode changes with 0 tabs existing?
198-
yield call(store.dispatch, actions.updateRefreshFileViewKey()); // refreshes folder view TODO super jank?
199+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
199200

200201
yield call(showSuccessMessage, `Loaded folder ${name}.`, 1000);
201202

@@ -553,25 +554,32 @@ export function* persistenceSaga(): SagaIterator {
553554
PERSISTENCE_SAVE_FILE,
554555
function* ({ payload: { id, name } }: ReturnType<typeof actions.persistenceSaveFile>) {
555556
let toastKey: string | undefined;
557+
558+
const [currFolderObject] = yield select( // TODO resolve type here?
559+
(state: OverallState) => [
560+
state.playground.persistenceFile
561+
]
562+
);
563+
564+
yield call(ensureInitialisedAndAuthorised);
565+
566+
const [activeEditorTabIndex, editorTabs, chapter, variant, external] = yield select(
567+
(state: OverallState) => [
568+
state.workspaces.playground.activeEditorTabIndex,
569+
state.workspaces.playground.editorTabs,
570+
state.workspaces.playground.context.chapter,
571+
state.workspaces.playground.context.variant,
572+
state.workspaces.playground.externalLibrary
573+
]
574+
);
575+
556576
try {
557577
toastKey = yield call(showMessage, {
558578
message: `Saving as ${name}...`,
559579
timeout: 0,
560580
intent: Intent.PRIMARY
561581
});
562582

563-
yield call(ensureInitialisedAndAuthorised);
564-
565-
const [activeEditorTabIndex, editorTabs, chapter, variant, external] = yield select(
566-
(state: OverallState) => [
567-
state.workspaces.playground.activeEditorTabIndex,
568-
state.workspaces.playground.editorTabs,
569-
state.workspaces.playground.context.chapter,
570-
state.workspaces.playground.context.variant,
571-
state.workspaces.playground.externalLibrary
572-
]
573-
);
574-
575583
if (activeEditorTabIndex === null) {
576584
throw new Error('No active editor tab found.');
577585
}
@@ -582,6 +590,20 @@ export function* persistenceSaga(): SagaIterator {
582590
variant,
583591
external
584592
};
593+
if ((currFolderObject as PersistenceFile).isFolder) {
594+
yield call(console.log, "folder opened! updating pers specially");
595+
const persistenceFileArray: PersistenceFile[] = yield select((state: OverallState) => state.fileSystem.persistenceFileArray);
596+
const currPersistenceFile = persistenceFileArray.find(e => e.path === (editorTabs[activeEditorTabIndex] as EditorTabState).filePath);
597+
if (!currPersistenceFile) {
598+
throw new Error('Persistence file not found');
599+
}
600+
yield call(updateFile, currPersistenceFile.id, currPersistenceFile.name, MIME_SOURCE, code, config);
601+
currPersistenceFile.lastSaved = new Date();
602+
yield put(actions.addPersistenceFile(currPersistenceFile));
603+
yield call(showSuccessMessage, `${name} successfully saved to Google Drive.`, 1000);
604+
return;
605+
}
606+
585607
yield call(updateFile, id, name, MIME_SOURCE, code, config);
586608
yield put(actions.playgroundUpdatePersistenceFile({ id, name, lastSaved: new Date() }));
587609
yield call(showSuccessMessage, `${name} successfully saved to Google Drive.`, 1000);
@@ -599,12 +621,12 @@ export function* persistenceSaga(): SagaIterator {
599621
yield takeEvery(
600622
PERSISTENCE_CREATE_FILE,
601623
function* ({ payload }: ReturnType<typeof actions.persistenceCreateFile>) {
624+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
625+
602626
const newFilePath = payload;
603627
yield call(console.log, "create file ", newFilePath);
604628

605-
// const persistenceFileArray: PersistenceFile[] = yield select((state: OverallState) => state.fileSystem.persistenceFileArray);
606-
607-
// look for parent folder persistenceFile
629+
// look for parent folder persistenceFile TODO modify action so name is supplied?
608630
const regexResult = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(newFilePath);
609631
const parentFolderPath = regexResult ? regexResult[1].slice(0, -1) : undefined;
610632
if (!parentFolderPath) {
@@ -638,6 +660,8 @@ export function* persistenceSaga(): SagaIterator {
638660
};
639661
const newFilePersistenceFile: PersistenceFile = yield call(createFile, newFileName, parentFolderId, MIME_SOURCE, '', config);
640662
yield put(actions.addPersistenceFile({ ...newFilePersistenceFile, lastSaved: new Date(), path: newFilePath }));
663+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
664+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
641665
yield call(
642666
showSuccessMessage,
643667
`${newFileName} successfully saved to Google Drive.`,
@@ -649,13 +673,15 @@ export function* persistenceSaga(): SagaIterator {
649673
yield takeEvery(
650674
PERSISTENCE_CREATE_FOLDER,
651675
function* ({ payload }: ReturnType<typeof actions.persistenceCreateFolder>) {
676+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
677+
652678
const newFolderPath = payload;
653679
yield call(console.log, "create folder ", newFolderPath);
654680

655681

656682
// const persistenceFileArray: PersistenceFile[] = yield select((state: OverallState) => state.fileSystem.persistenceFileArray);
657683

658-
// look for parent folder persistenceFile
684+
// look for parent folder persistenceFile TODO modify action so name is supplied?
659685
const regexResult = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(newFolderPath);
660686
const parentFolderPath = regexResult ? regexResult[1].slice(0, -1) : undefined;
661687
if (!parentFolderPath) {
@@ -677,6 +703,8 @@ export function* persistenceSaga(): SagaIterator {
677703

678704
const newFolderId: string = yield call(createFolderAndReturnId, parentFolderId, newFolderName);
679705
yield put(actions.addPersistenceFile({ lastSaved: new Date(), path: newFolderPath, id: newFolderId, name: newFolderName, parentId: parentFolderId }));
706+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
707+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
680708
yield call(
681709
showSuccessMessage,
682710
`Folder ${newFolderName} successfully saved to Google Drive.`,
@@ -688,6 +716,8 @@ export function* persistenceSaga(): SagaIterator {
688716
yield takeEvery(
689717
PERSISTENCE_DELETE_FILE,
690718
function* ({ payload }: ReturnType<typeof actions.persistenceDeleteFile>) {
719+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
720+
691721
const filePath = payload;
692722
yield call(console.log, "delete file ", filePath);
693723

@@ -698,8 +728,10 @@ export function* persistenceSaga(): SagaIterator {
698728
yield call(console.log, "cannot find pers file for ", filePath);
699729
return;
700730
}
701-
yield call(deleteFileOrFolder, persistenceFile.id); // assume this succeeds all the time
731+
yield call(deleteFileOrFolder, persistenceFile.id); // assume this succeeds all the time? TODO
702732
yield put(actions.deletePersistenceFile(persistenceFile));
733+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
734+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
703735
yield call(
704736
showSuccessMessage,
705737
`${persistenceFile.name} successfully deleted from Google Drive.`,
@@ -711,6 +743,8 @@ export function* persistenceSaga(): SagaIterator {
711743
yield takeEvery(
712744
PERSISTENCE_DELETE_FOLDER,
713745
function* ({ payload }: ReturnType<typeof actions.persistenceDeleteFolder>) {
746+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
747+
714748
const folderPath = payload;
715749
yield call(console.log, "delete folder ", folderPath);
716750

@@ -721,8 +755,10 @@ export function* persistenceSaga(): SagaIterator {
721755
yield call(console.log, "cannot find pers file for ", folderPath);
722756
return;
723757
}
724-
yield call(deleteFileOrFolder, persistenceFile.id); // assume this succeeds all the time
758+
yield call(deleteFileOrFolder, persistenceFile.id); // assume this succeeds all the time? TODO
725759
yield put(actions.deletePersistenceFile(persistenceFile));
760+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
761+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
726762
yield call(
727763
showSuccessMessage,
728764
`Folder ${persistenceFile.name} successfully deleted from Google Drive.`,
@@ -734,6 +770,8 @@ export function* persistenceSaga(): SagaIterator {
734770
yield takeEvery(
735771
PERSISTENCE_RENAME_FILE,
736772
function* ({ payload : {oldFilePath, newFilePath} }: ReturnType<typeof actions.persistenceRenameFile>) {
773+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
774+
737775
yield call(console.log, "rename file ", oldFilePath, " to ", newFilePath);
738776

739777
// look for file
@@ -744,7 +782,7 @@ export function* persistenceSaga(): SagaIterator {
744782
return;
745783
}
746784

747-
// new name
785+
// new name TODO: modify action so name is supplied?
748786
const regexResult = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(newFilePath);
749787
if (!regexResult) {
750788
yield call(console.log, "regex fail ", newFilePath);
@@ -757,6 +795,8 @@ export function* persistenceSaga(): SagaIterator {
757795

758796
// handle pers file
759797
yield put(actions.updatePersistenceFilePathAndNameByPath(oldFilePath, newFilePath, newFileName));
798+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
799+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
760800
yield call(
761801
showSuccessMessage,
762802
`${newFileName} successfully renamed in Google Drive.`,
@@ -768,7 +808,46 @@ export function* persistenceSaga(): SagaIterator {
768808
yield takeEvery(
769809
PERSISTENCE_RENAME_FOLDER,
770810
function* ({ payload : {oldFolderPath, newFolderPath} }: ReturnType<typeof actions.persistenceRenameFolder>) {
811+
yield call(store.dispatch, actions.disableFileSystemContextMenus());
812+
771813
yield call(console.log, "rename folder ", oldFolderPath, " to ", newFolderPath);
814+
815+
// look for folder
816+
const persistenceFileArray: PersistenceFile[] = yield select((state: OverallState) => state.fileSystem.persistenceFileArray);
817+
const persistenceFile = persistenceFileArray.find(e => e.path === oldFolderPath);
818+
if (!persistenceFile) {
819+
yield call(console.log, "cannot find pers file for ", oldFolderPath);
820+
return;
821+
}
822+
823+
// new name TODO: modify action so name is supplied?
824+
const regexResult = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(newFolderPath);
825+
if (!regexResult) {
826+
yield call(console.log, "regex fail ", newFolderPath);
827+
return;
828+
}
829+
const newFolderName = regexResult[2] + regexResult[3];
830+
831+
// old name TODO: modify action so name is supplied?
832+
const regexResult2 = /^(.*[\\\/])?(\.*.*?)(\.[^.]+?|)$/.exec(oldFolderPath);
833+
if (!regexResult2) {
834+
yield call(console.log, "regex fail ", oldFolderPath);
835+
return;
836+
}
837+
const oldFolderName = regexResult2[2] + regexResult2[3];
838+
839+
// call gapi
840+
yield call(renameFileOrFolder, persistenceFile.id, newFolderName);
841+
842+
// handle pers file
843+
yield put(actions.updatePersistenceFolderPathAndNameByPath(oldFolderPath, newFolderPath, oldFolderName, newFolderName));
844+
yield call(store.dispatch, actions.enableFileSystemContextMenus());
845+
yield call(store.dispatch, actions.updateRefreshFileViewKey());
846+
yield call(
847+
showSuccessMessage,
848+
`Folder ${newFolderName} successfully renamed in Google Drive.`,
849+
1000
850+
);
772851
}
773852
);
774853
}

0 commit comments

Comments
 (0)