Skip to content

Commit a335af8

Browse files
added saving all for github
1 parent 8bf268a commit a335af8

18 files changed

+224
-36
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"mdast-util-to-hast": "^13.0.0",
6161
"moment": "^2.29.4",
6262
"normalize.css": "^8.0.1",
63+
"octokit-commit-multiple-files": "^5.0.2",
6364
"phaser": "^3.55.2",
6465
"query-string": "^9.0.0",
6566
"re-resizable": "^6.9.9",

src/commons/controlBar/github/ControlBarGitHubButtons.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Props = {
1616
onClickOpen?: () => void;
1717
onClickSave?: () => void;
1818
onClickSaveAs?: () => void;
19+
onClickSaveAll?: () => void;
1920
onClickLogIn?: () => void;
2021
onClickLogOut?: () => void;
2122
};
@@ -83,7 +84,7 @@ export const ControlBarGitHubButtons: React.FC<Props> = props => {
8384
<ControlButton
8485
label="Save All"
8586
icon={IconNames.DOUBLE_CHEVRON_UP}
86-
onClick={props.onClickSaveAs}
87+
onClick={props.onClickSaveAll}
8788
isDisabled={shouldDisableButtons}
8889
/>
8990
);

src/commons/fileSystem/FileSystemActions.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { createAction } from '@reduxjs/toolkit';
2+
import { GitHubSaveInfo } from 'src/features/github/GitHubTypes';
23
import { FSModule } from 'browserfs/dist/node/core/FS';
34

45
import {
5-
SET_IN_BROWSER_FILE_SYSTEM,
66
ADD_GITHUB_SAVE_INFO,
7+
DELETE_ALL_GITHUB_SAVE_INFO,
78
DELETE_GITHUB_SAVE_INFO,
8-
DELETE_ALL_GITHUB_SAVE_INFO
9-
} from './FileSystemTypes';
10-
import { GitHubSaveInfo } from 'src/features/github/GitHubTypes';
9+
SET_IN_BROWSER_FILE_SYSTEM,
10+
UPDATE_GITHUB_SAVE_INFO } from './FileSystemTypes';
1111

1212
export const setInBrowserFileSystem = createAction(
1313
SET_IN_BROWSER_FILE_SYSTEM,
@@ -28,3 +28,9 @@ export const deleteAllGithubSaveInfo = createAction(
2828
DELETE_ALL_GITHUB_SAVE_INFO,
2929
() => ({ payload: {} })
3030
);
31+
export const updateGithubSaveInfo = createAction(
32+
UPDATE_GITHUB_SAVE_INFO,
33+
(repoName: string,
34+
filePath: string,
35+
lastSaved: Date) => ({ payload: {repoName, filePath, lastSaved} })
36+
)

src/commons/fileSystem/FileSystemTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const SET_IN_BROWSER_FILE_SYSTEM = 'SET_IN_BROWSER_FILE_SYSTEM';
55
export const ADD_GITHUB_SAVE_INFO = 'ADD_GITHUB_SAVE_INFO';
66
export const DELETE_GITHUB_SAVE_INFO = 'DELETE_GITHUB_SAVE_INFO';
77
export const DELETE_ALL_GITHUB_SAVE_INFO = 'DELETE_ALL_GITHUB_SAVE_INFO';
8+
export const UPDATE_GITHUB_SAVE_INFO = 'UPDATE_GITHUB_SAVE_INFO';
89

910
export type FileSystemState = {
1011
inBrowserFileSystem: FSModule | null;

src/commons/fileSystem/FileSystemUtils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { FSModule } from 'browserfs/dist/node/core/FS';
22
import Stats from 'browserfs/dist/node/core/node_fs_stats';
33
import path from 'path';
4+
import { GitHubSaveInfo } from 'src/features/github/GitHubTypes';
5+
import { store } from 'src/pages/createStore';
46

57
import { WORKSPACE_BASE_PATHS } from '../../pages/fileSystem/createInBrowserFileSystem';
68
import { WorkspaceLocation } from '../workspace/WorkspaceTypes';
@@ -263,3 +265,19 @@ export const writeFileRecursively = (
263265
});
264266
});
265267
};
268+
269+
export const getGithubSaveInfo = () => {
270+
const githubSaveInfoArray = store.getState().fileSystem.githubSaveInfoArray;
271+
const {
272+
editorTabs,
273+
activeEditorTabIndex
274+
} = store.getState().workspaces['playground'];
275+
let currentFilePath = '';
276+
if (activeEditorTabIndex !== null) {
277+
currentFilePath = editorTabs[activeEditorTabIndex].filePath?.slice(12) || '';
278+
}
279+
const nullGithubSaveInfo: GitHubSaveInfo = { repoName: 'test', filePath: '', lastSaved: new Date() };
280+
const githubSaveInfo = githubSaveInfoArray.find(githubSaveInfo => githubSaveInfo.filePath === currentFilePath) || nullGithubSaveInfo;
281+
282+
return githubSaveInfo;
283+
}

src/commons/fileSystemView/FileSystemViewFileNode.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import React from 'react';
66
import { useDispatch, useStore } from 'react-redux';
77
import classes from 'src/styles/FileSystemView.module.scss';
88

9+
import { OverallState } from '../application/ApplicationTypes';
10+
import { actions } from '../utils/ActionsHelper';
911
import { showSimpleConfirmDialog } from '../utils/DialogHelper';
1012
import { addEditorTab, removeEditorTabForFile } from '../workspace/WorkspaceActions';
1113
import { WorkspaceLocation } from '../workspace/WorkspaceTypes';
1214
import FileSystemViewContextMenu from './FileSystemViewContextMenu';
1315
import FileSystemViewFileName from './FileSystemViewFileName';
1416
import FileSystemViewIndentationPadding from './FileSystemViewIndentationPadding';
15-
import { OverallState } from '../application/ApplicationTypes';
16-
import { actions } from '../utils/ActionsHelper';
1717

1818
type Props = {
1919
workspaceLocation: WorkspaceLocation;

src/commons/sagas/GitHubPersistenceSaga.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { call, put, select, takeLatest } from 'redux-saga/effects';
77

88
import {
99
GITHUB_OPEN_FILE,
10+
GITHUB_SAVE_ALL,
1011
GITHUB_SAVE_FILE,
1112
GITHUB_SAVE_FILE_AS
1213
} from '../../features/github/GitHubTypes';
@@ -15,13 +16,15 @@ import { getGitHubOctokitInstance } from '../../features/github/GitHubUtils';
1516
import { store } from '../../pages/createStore';
1617
import { OverallState } from '../application/ApplicationTypes';
1718
import { LOGIN_GITHUB, LOGOUT_GITHUB } from '../application/types/SessionTypes';
19+
import { getGithubSaveInfo, retrieveFilesInWorkspaceAsRecord } from '../fileSystem/FileSystemUtils';
1820
import FileExplorerDialog, { FileExplorerDialogProps } from '../gitHubOverlay/FileExplorerDialog';
1921
import RepositoryDialog, { RepositoryDialogProps } from '../gitHubOverlay/RepositoryDialog';
2022
import { actions } from '../utils/ActionsHelper';
2123
import Constants from '../utils/Constants';
2224
import { promisifyDialog } from '../utils/DialogHelper';
2325
import { showSuccessMessage } from '../utils/notifications/NotificationsHelper';
2426
import { EditorTabState } from '../workspace/WorkspaceTypes';
27+
import { FSModule } from 'browserfs/dist/node/core/FS';
2528

2629
export function* GitHubPersistenceSaga(): SagaIterator {
2730
yield takeLatest(LOGIN_GITHUB, githubLoginSaga);
@@ -30,6 +33,7 @@ export function* GitHubPersistenceSaga(): SagaIterator {
3033
yield takeLatest(GITHUB_OPEN_FILE, githubOpenFile);
3134
yield takeLatest(GITHUB_SAVE_FILE, githubSaveFile);
3235
yield takeLatest(GITHUB_SAVE_FILE_AS, githubSaveFileAs);
36+
yield takeLatest(GITHUB_SAVE_ALL, githubSaveAll);
3337
}
3438

3539
function* githubLoginSaga() {
@@ -113,8 +117,9 @@ function* githubSaveFile(): any {
113117
const authUser: GetAuthenticatedResponse = yield call(octokit.users.getAuthenticated);
114118

115119
const githubLoginId = authUser.data.login;
116-
const repoName = store.getState().playground.githubSaveInfo.repoName;
117-
const filePath = store.getState().playground.githubSaveInfo.filePath;
120+
const githubSaveInfo = getGithubSaveInfo();
121+
const repoName = githubSaveInfo.repoName;
122+
const filePath = githubSaveInfo.filePath;
118123
const githubEmail = authUser.data.email;
119124
const githubName = authUser.data.name;
120125
const commitMessage = 'Changes made from Source Academy';
@@ -190,6 +195,74 @@ function* githubSaveFileAs(): any {
190195

191196
yield call(promisifiedFileExplorer);
192197
}
198+
}
199+
200+
function* githubSaveAll(): any {
201+
const octokit = getGitHubOctokitInstance();
202+
if (octokit === undefined) return;
203+
204+
type GetAuthenticatedResponse = GetResponseTypeFromEndpointMethod<
205+
typeof octokit.users.getAuthenticated
206+
>;
207+
const authUser: GetAuthenticatedResponse = yield call(octokit.users.getAuthenticated);
208+
209+
const githubLoginId = authUser.data.login;
210+
const githubSaveInfo = getGithubSaveInfo();
211+
const repoName = githubSaveInfo.repoName;
212+
const githubEmail = authUser.data.email;
213+
const githubName = authUser.data.name;
214+
const commitMessage = 'Changes made from Source Academy';
215+
const fileSystem: FSModule | null = yield select(
216+
(state: OverallState) => state.fileSystem.inBrowserFileSystem
217+
);
218+
// If the file system is not initialised, do nothing.
219+
if (fileSystem === null) {
220+
yield call(console.log, "no filesystem!");
221+
return;
222+
}
223+
yield call(console.log, "there is a filesystem");
224+
const currFiles: Record<string, string> = yield call(retrieveFilesInWorkspaceAsRecord, "playground", fileSystem);
225+
const modifiedcurrFiles : Record<string, string> = {};
226+
for (const filePath of Object.keys(currFiles)) {
227+
modifiedcurrFiles[filePath.slice(12)] = currFiles[filePath];
228+
}
229+
console.log(modifiedcurrFiles);
230+
231+
yield call(GitHubUtils.performMultipleOverwritingSave,
232+
octokit,
233+
githubLoginId,
234+
repoName,
235+
githubEmail,
236+
githubName,
237+
{ commitMessage: commitMessage, files: modifiedcurrFiles});
238+
239+
// for (const filePath of Object.keys(currFiles)) {
240+
// const content = currFiles[filePath];
241+
// yield call(GitHubUtils.performOverwritingSave,
242+
// octokit,
243+
// githubLoginId,
244+
// repoName,
245+
// filePath.slice(12),
246+
// githubEmail,
247+
// githubName,
248+
// commitMessage,
249+
// content);
250+
// }
251+
252+
// const activeEditorTabIndex: number | null = yield select(
253+
// (state: OverallState) => state.workspaces.playground.activeEditorTabIndex
254+
// );
255+
// if (activeEditorTabIndex === null) {
256+
// throw new Error('No active editor tab found.');
257+
// }
258+
// const editorTabs: EditorTabState[] = yield select(
259+
// (state: OverallState) => state.workspaces.playground.editorTabs
260+
// );
261+
// const content = editorTabs[activeEditorTabIndex].value;
262+
263+
264+
265+
193266
}
194267

195268
export default GitHubPersistenceSaga;

src/commons/sagas/PersistenceSaga.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Intent } from '@blueprintjs/core';
2+
import { FSModule } from 'browserfs/dist/node/core/FS';
23
import { GoogleOAuthProvider, SuccessTokenResponse } from 'google-oauth-gsi';
34
import { Chapter, Variant } from 'js-slang/dist/types';
45
import { SagaIterator } from 'redux-saga';
@@ -16,6 +17,8 @@ import { store } from '../../pages/createStore';
1617
import { OverallState } from '../application/ApplicationTypes';
1718
import { ExternalLibraryName } from '../application/types/ExternalTypes';
1819
import { LOGIN_GOOGLE, LOGOUT_GOOGLE } from '../application/types/SessionTypes';
20+
import { retrieveFilesInWorkspaceAsRecord, rmFilesInDirRecursively, writeFileRecursively } from '../fileSystem/FileSystemUtils';
21+
import { refreshFileView } from '../fileSystemView/FileSystemViewList'; // TODO broken when folder is open when reading folders
1922
import { actions } from '../utils/ActionsHelper';
2023
import Constants from '../utils/Constants';
2124
import { showSimpleConfirmDialog, showSimplePromptDialog } from '../utils/DialogHelper';
@@ -27,9 +30,6 @@ import {
2730
} from '../utils/notifications/NotificationsHelper';
2831
import { AsyncReturnType } from '../utils/TypeHelper';
2932
import { safeTakeEvery as takeEvery, safeTakeLatest as takeLatest } from './SafeEffects';
30-
import { FSModule } from 'browserfs/dist/node/core/FS';
31-
import { retrieveFilesInWorkspaceAsRecord, rmFilesInDirRecursively, writeFileRecursively } from '../fileSystem/FileSystemUtils';
32-
import { refreshFileView } from '../fileSystemView/FileSystemViewList'; // TODO broken when folder is open when reading folders
3333

3434
const DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'];
3535
const SCOPES =

src/commons/utils/GitHubPersistenceHelper.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import { Octokit } from '@octokit/rest';
44
* Returns an instance to Octokit created using the authentication token
55
*/
66
export function generateOctokitInstance(authToken: string) {
7-
const octokit = new Octokit({
7+
const octokitPlugin = Octokit.plugin(require('octokit-commit-multiple-files'));
8+
console.log('testttt');
9+
const octokit = new octokitPlugin({
810
auth: authToken,
911
userAgent: 'Source Academy Playground',
1012
baseUrl: 'https://api.github.com',

src/commons/workspace/WorkspaceActions.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
UPDATE_CURRENT_SUBMISSION_ID,
6464
UPDATE_CURRENTSTEP,
6565
UPDATE_EDITOR_BREAKPOINTS,
66+
UPDATE_EDITOR_GITHUB_SAVE_INFO,
6667
UPDATE_EDITOR_VALUE,
6768
UPDATE_HAS_UNSAVED_CHANGES,
6869
UPDATE_LAST_DEBUGGER_RESULT,
@@ -74,9 +75,7 @@ import {
7475
UPDATE_WORKSPACE,
7576
WorkspaceLocation,
7677
WorkspaceLocationsWithTools,
77-
WorkspaceState,
78-
UPDATE_EDITOR_GITHUB_SAVE_INFO
79-
} from './WorkspaceTypes';
78+
WorkspaceState} from './WorkspaceTypes';
8079

8180
export const setTokenCount = createAction(
8281
SET_TOKEN_COUNT,

0 commit comments

Comments
 (0)