Skip to content

Commit b3764dd

Browse files
authored
Disable persistence methods in Folder mode (#2403)
* Update GitHub persistence to work with any active editor tab * Update Google Drive persistence to work with any active editor tab * Update PersistenceSaga tests * Disable Google Drive persistence in Folder mode * Disable GitHub persistence in Folder mode * Disable Folder mode when a persistence method is active
1 parent 2546bd1 commit b3764dd

File tree

8 files changed

+196
-103
lines changed

8 files changed

+196
-103
lines changed

src/commons/controlBar/ControlBarGoogleDriveButtons.tsx

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import ControlButton from '../ControlButton';
88
import { useResponsive } from '../utils/Hooks';
99

1010
export type ControlBarGoogleDriveButtonsProps = {
11+
isFolderModeEnabled: boolean;
1112
loggedInAs?: string;
1213
currentFile?: PersistenceFile;
1314
isDirty?: boolean;
@@ -36,6 +37,7 @@ export const ControlBarGoogleDriveButtons: React.FC<ControlBarGoogleDriveButtons
3637
label={(props.currentFile && props.currentFile.name) || 'Google Drive'}
3738
icon={IconNames.CLOUD}
3839
options={{ intent: stateToIntent[state] }}
40+
isDisabled={props.isFolderModeEnabled}
3941
/>
4042
);
4143
const openButton = (
@@ -58,24 +60,30 @@ export const ControlBarGoogleDriveButtons: React.FC<ControlBarGoogleDriveButtons
5860
<ControlButton label="Log out" icon={IconNames.LOG_OUT} onClick={props.onClickLogOut} />
5961
</Tooltip2>
6062
);
63+
const tooltipContent = props.isFolderModeEnabled
64+
? 'Currently unsupported in Folder mode'
65+
: undefined;
6166

6267
return (
63-
<Popover2
64-
autoFocus={false}
65-
content={
66-
<div>
67-
<ButtonGroup large={!isMobileBreakpoint}>
68-
{openButton}
69-
{saveButton}
70-
{saveAsButton}
71-
{logoutButton}
72-
</ButtonGroup>
73-
</div>
74-
}
75-
onOpening={props.onPopoverOpening}
76-
popoverClassName={Classes.POPOVER_DISMISS}
77-
>
78-
{mainButton}
79-
</Popover2>
68+
<Tooltip2 content={tooltipContent} disabled={tooltipContent === undefined}>
69+
<Popover2
70+
autoFocus={false}
71+
content={
72+
<div>
73+
<ButtonGroup large={!isMobileBreakpoint}>
74+
{openButton}
75+
{saveButton}
76+
{saveAsButton}
77+
{logoutButton}
78+
</ButtonGroup>
79+
</div>
80+
}
81+
onOpening={props.onPopoverOpening}
82+
popoverClassName={Classes.POPOVER_DISMISS}
83+
disabled={props.isFolderModeEnabled}
84+
>
85+
{mainButton}
86+
</Popover2>
87+
</Tooltip2>
8088
);
8189
};

src/commons/controlBar/ControlBarToggleFolderModeButton.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ import ControlButton from '../ControlButton';
88
type ControlBarToggleFolderModeButtonProps = {
99
isFolderModeEnabled: boolean;
1010
isSessionActive: boolean;
11+
isPersistenceActive: boolean;
1112
toggleFolderMode: () => void;
1213
};
1314

1415
export const ControlBarToggleFolderModeButton: React.FC<ControlBarToggleFolderModeButtonProps> = ({
1516
isFolderModeEnabled,
1617
isSessionActive,
18+
isPersistenceActive,
1719
toggleFolderMode
1820
}) => {
1921
const tooltipContent = isSessionActive
2022
? 'Currently unsupported while a collaborative session is active'
23+
: isPersistenceActive
24+
? 'Currently unsupported while a persistence method is active'
2125
: `${isFolderModeEnabled ? 'Disable' : 'Enable'} Folder mode`;
2226
return (
2327
<Tooltip2 content={tooltipContent}>
@@ -28,7 +32,7 @@ export const ControlBarToggleFolderModeButton: React.FC<ControlBarToggleFolderMo
2832
iconColor: isFolderModeEnabled ? Colors.BLUE4 : undefined
2933
}}
3034
onClick={toggleFolderMode}
31-
isDisabled={isSessionActive}
35+
isDisabled={isSessionActive || isPersistenceActive}
3236
/>
3337
</Tooltip2>
3438
);

src/commons/controlBar/github/ControlBarGitHubButtons.tsx

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ButtonGroup, Classes, Intent } from '@blueprintjs/core';
22
import { IconNames } from '@blueprintjs/icons';
3-
import { Popover2 } from '@blueprintjs/popover2';
3+
import { Popover2, Tooltip2 } from '@blueprintjs/popover2';
44
import { Octokit } from '@octokit/rest';
55
import * as React from 'react';
66
import { useResponsive } from 'src/commons/utils/Hooks';
@@ -9,6 +9,7 @@ import { GitHubSaveInfo } from '../../../features/github/GitHubTypes';
99
import ControlButton from '../../ControlButton';
1010

1111
export type ControlBarGitHubButtonsProps = {
12+
isFolderModeEnabled: boolean;
1213
loggedInAs?: Octokit;
1314
githubSaveInfo: GitHubSaveInfo;
1415
isDirty: boolean;
@@ -47,6 +48,7 @@ export const ControlBarGitHubButtons: React.FC<ControlBarGitHubButtonsProps> = p
4748
label={mainButtonDisplayText}
4849
icon={IconNames.GIT_BRANCH}
4950
options={{ intent: mainButtonIntent }}
51+
isDisabled={props.isFolderModeEnabled}
5052
/>
5153
);
5254

@@ -83,22 +85,29 @@ export const ControlBarGitHubButtons: React.FC<ControlBarGitHubButtonsProps> = p
8385
<ControlButton label="Log In" icon={IconNames.LOG_IN} onClick={props.onClickLogIn} />
8486
);
8587

88+
const tooltipContent = props.isFolderModeEnabled
89+
? 'Currently unsupported in Folder mode'
90+
: undefined;
91+
8692
return (
87-
<Popover2
88-
autoFocus={false}
89-
content={
90-
<div>
91-
<ButtonGroup large={!isMobileBreakpoint}>
92-
{openButton}
93-
{saveButton}
94-
{saveAsButton}
95-
{loginButton}
96-
</ButtonGroup>
97-
</div>
98-
}
99-
popoverClassName={Classes.POPOVER_DISMISS}
100-
>
101-
{mainButton}
102-
</Popover2>
93+
<Tooltip2 content={tooltipContent} disabled={tooltipContent === undefined}>
94+
<Popover2
95+
autoFocus={false}
96+
content={
97+
<div>
98+
<ButtonGroup large={!isMobileBreakpoint}>
99+
{openButton}
100+
{saveButton}
101+
{saveAsButton}
102+
{loginButton}
103+
</ButtonGroup>
104+
</div>
105+
}
106+
popoverClassName={Classes.POPOVER_DISMISS}
107+
disabled={props.isFolderModeEnabled}
108+
>
109+
{mainButton}
110+
</Popover2>
111+
</Tooltip2>
103112
);
104113
};

src/commons/sagas/GitHubPersistenceSaga.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
GetResponseTypeFromEndpointMethod
44
} from '@octokit/types';
55
import { SagaIterator } from 'redux-saga';
6-
import { call, put, takeLatest } from 'redux-saga/effects';
6+
import { call, put, select, takeLatest } from 'redux-saga/effects';
77

88
import {
99
GITHUB_OPEN_FILE,
@@ -13,13 +13,15 @@ import {
1313
import * as GitHubUtils from '../../features/github/GitHubUtils';
1414
import { getGitHubOctokitInstance } from '../../features/github/GitHubUtils';
1515
import { store } from '../../pages/createStore';
16+
import { OverallState } from '../application/ApplicationTypes';
1617
import { LOGIN_GITHUB, LOGOUT_GITHUB } from '../application/types/SessionTypes';
1718
import FileExplorerDialog, { FileExplorerDialogProps } from '../gitHubOverlay/FileExplorerDialog';
1819
import RepositoryDialog, { RepositoryDialogProps } from '../gitHubOverlay/RepositoryDialog';
1920
import { actions } from '../utils/ActionsHelper';
2021
import Constants from '../utils/Constants';
2122
import { promisifyDialog } from '../utils/DialogHelper';
2223
import { showSuccessMessage, showWarningMessage } from '../utils/NotificationsHelper';
24+
import { EditorTabState } from '../workspace/WorkspaceTypes';
2325

2426
export function* GitHubPersistenceSaga(): SagaIterator {
2527
yield takeLatest(LOGIN_GITHUB, githubLoginSaga);
@@ -121,8 +123,16 @@ function* githubSaveFile(): any {
121123
const githubEmail = authUser.data.email;
122124
const githubName = authUser.data.name;
123125
const commitMessage = 'Changes made from Source Academy';
124-
// TODO: Hardcoded to make use of the first editor tab. Rewrite after editor tabs are added.
125-
const content = store.getState().workspaces.playground.editorTabs[0].value;
126+
const activeEditorTabIndex: number | null = yield select(
127+
(state: OverallState) => state.workspaces.playground.activeEditorTabIndex
128+
);
129+
if (activeEditorTabIndex === null) {
130+
throw new Error('No active editor tab found.');
131+
}
132+
const editorTabs: EditorTabState[] = yield select(
133+
(state: OverallState) => state.workspaces.playground.editorTabs
134+
);
135+
const content = editorTabs[activeEditorTabIndex].value;
126136

127137
GitHubUtils.performOverwritingSave(
128138
octokit,
@@ -160,8 +170,16 @@ function* githubSaveFileAs(): any {
160170
}));
161171
const repoName = yield call(getRepoName);
162172

163-
// TODO: Hardcoded to make use of the first editor tab. Rewrite after editor tabs are added.
164-
const editorContent = store.getState().workspaces.playground.editorTabs[0].value;
173+
const activeEditorTabIndex: number | null = yield select(
174+
(state: OverallState) => state.workspaces.playground.activeEditorTabIndex
175+
);
176+
if (activeEditorTabIndex === null) {
177+
throw new Error('No active editor tab found.');
178+
}
179+
const editorTabs: EditorTabState[] = yield select(
180+
(state: OverallState) => state.workspaces.playground.editorTabs
181+
);
182+
const editorContent = editorTabs[activeEditorTabIndex].value;
165183

166184
if (repoName !== '') {
167185
const pickerType = 'Save';

src/commons/sagas/PersistenceSaga.tsx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,13 @@ export function* persistenceSaga(): SagaIterator {
7878
fields: 'appProperties'
7979
});
8080
const contents = yield call([gapi.client.drive.files, 'get'], { fileId: id, alt: 'media' });
81-
// TODO: Hardcoded to make use of the first editor tab. Rewrite after editor tabs are added.
82-
yield put(actions.updateEditorValue('playground', 0, contents.body));
81+
const activeEditorTabIndex: number | null = yield select(
82+
(state: OverallState) => state.workspaces.playground.activeEditorTabIndex
83+
);
84+
if (activeEditorTabIndex === null) {
85+
throw new Error('No active editor tab found.');
86+
}
87+
yield put(actions.updateEditorValue('playground', activeEditorTabIndex, contents.body));
8388
yield put(actions.playgroundUpdatePersistenceFile({ id, name, lastSaved: new Date() }));
8489
if (meta && meta.appProperties) {
8590
yield put(
@@ -114,13 +119,20 @@ export function* persistenceSaga(): SagaIterator {
114119
try {
115120
yield call(ensureInitialisedAndAuthorised);
116121

117-
const [code, chapter, variant, external] = yield select((state: OverallState) => [
118-
// TODO: Hardcoded to make use of the first editor tab. Rewrite after editor tabs are added.
119-
state.workspaces.playground.editorTabs[0].value,
120-
state.workspaces.playground.context.chapter,
121-
state.workspaces.playground.context.variant,
122-
state.workspaces.playground.externalLibrary
123-
]);
122+
const [activeEditorTabIndex, editorTabs, chapter, variant, external] = yield select(
123+
(state: OverallState) => [
124+
state.workspaces.playground.activeEditorTabIndex,
125+
state.workspaces.playground.editorTabs,
126+
state.workspaces.playground.context.chapter,
127+
state.workspaces.playground.context.variant,
128+
state.workspaces.playground.externalLibrary
129+
]
130+
);
131+
132+
if (activeEditorTabIndex === null) {
133+
throw new Error('No active editor tab found.');
134+
}
135+
const code = editorTabs[activeEditorTabIndex].value;
124136

125137
const pickedDir: PickFileResult = yield call(
126138
pickFile,
@@ -237,13 +249,20 @@ export function* persistenceSaga(): SagaIterator {
237249

238250
yield call(ensureInitialisedAndAuthorised);
239251

240-
const [code, chapter, variant, external] = yield select((state: OverallState) => [
241-
// TODO: Hardcoded to make use of the first editor tab. Rewrite after editor tabs are added.
242-
state.workspaces.playground.editorTabs[0].value,
243-
state.workspaces.playground.context.chapter,
244-
state.workspaces.playground.context.variant,
245-
state.workspaces.playground.externalLibrary
246-
]);
252+
const [activeEditorTabIndex, editorTabs, chapter, variant, external] = yield select(
253+
(state: OverallState) => [
254+
state.workspaces.playground.activeEditorTabIndex,
255+
state.workspaces.playground.editorTabs,
256+
state.workspaces.playground.context.chapter,
257+
state.workspaces.playground.context.variant,
258+
state.workspaces.playground.externalLibrary
259+
]
260+
);
261+
262+
if (activeEditorTabIndex === null) {
263+
throw new Error('No active editor tab found.');
264+
}
265+
const code = editorTabs[activeEditorTabIndex].value;
247266

248267
const config: IPlaygroundConfig = {
249268
chapter,

0 commit comments

Comments
 (0)