fix: make crtl+s save to appropriate location (#45406)
* fix: crtl+s for multifile cert projects * fix: remove unused code * feat: add limit on save frequency
This commit is contained in:
@ -533,6 +533,7 @@
|
||||
"local-code-saved": "Saved! Your code was saved to your browser's local storage.",
|
||||
"code-saved": "Your code was saved to the database. It will be here when you return.",
|
||||
"code-save-error": "An error occurred trying to save your code.",
|
||||
"code-save-less": "Slow Down! Your code was not saved. Try again in a few seconds.",
|
||||
"challenge-save-too-big": "Sorry, you cannot save your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
|
||||
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org"
|
||||
},
|
||||
|
@ -9,6 +9,7 @@ export enum FlashMessages {
|
||||
ChallengeSubmitTooBig = 'flash.challenge-submit-too-big',
|
||||
CodeSaved = 'flash.code-saved',
|
||||
CodeSaveError = 'flash.code-save-error',
|
||||
CodeSaveLess = 'flash.code-save-less',
|
||||
CompleteProjectFirst = 'flash.complete-project-first',
|
||||
DeleteTokenErr = 'flash.delete-token-err',
|
||||
EmailValid = 'flash.email-valid',
|
||||
|
@ -13,11 +13,23 @@ import {
|
||||
bodySizeFits,
|
||||
MAX_BODY_SIZE
|
||||
} from '../utils/challenge-request-helpers';
|
||||
import { saveChallengeComplete } from './';
|
||||
import { saveChallengeComplete, savedChallengesSelector } from './';
|
||||
|
||||
export function* saveChallengeSaga() {
|
||||
const { id, challengeType } = yield select(challengeMetaSelector);
|
||||
const { challengeFiles } = yield select(challengeDataSelector);
|
||||
const savedChallenges = yield select(savedChallengesSelector);
|
||||
const savedChallenge = savedChallenges.find(challenge => challenge.id === id);
|
||||
|
||||
// don't let users save more than once every 5 seconds
|
||||
if (Date.now() - savedChallenge?.lastSavedDate < 5000) {
|
||||
return yield put(
|
||||
createFlashMessage({
|
||||
type: 'danger',
|
||||
message: FlashMessages.CodeSaveLess
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// only allow saving of multiFileCertProject's
|
||||
if (challengeType === challengeTypes.multiFileCertProject) {
|
||||
|
@ -20,7 +20,11 @@ import store from 'store';
|
||||
|
||||
import { Loader } from '../../../components/helpers';
|
||||
import { Themes } from '../../../components/settings/theme';
|
||||
import { userSelector, isDonationModalOpenSelector } from '../../../redux';
|
||||
import {
|
||||
userSelector,
|
||||
saveChallenge,
|
||||
isDonationModalOpenSelector
|
||||
} from '../../../redux';
|
||||
import {
|
||||
ChallengeFiles,
|
||||
Dimensions,
|
||||
@ -31,8 +35,10 @@ import {
|
||||
} from '../../../redux/prop-types';
|
||||
import { editorToneOptions } from '../../../utils/tone/editor-config';
|
||||
import { editorNotes } from '../../../utils/tone/editor-notes';
|
||||
import { challengeTypes } from '../../../../utils/challenge-types';
|
||||
import {
|
||||
canFocusEditorSelector,
|
||||
challengeMetaSelector,
|
||||
consoleOutputSelector,
|
||||
executeChallenge,
|
||||
saveEditorContent,
|
||||
@ -54,6 +60,7 @@ const MonacoEditor = Loadable(() => import('react-monaco-editor'));
|
||||
interface EditorProps {
|
||||
canFocus: boolean;
|
||||
challengeFiles: ChallengeFiles;
|
||||
challengeType: number;
|
||||
containerRef: RefObject<HTMLElement>;
|
||||
contents: string;
|
||||
description: string;
|
||||
@ -70,6 +77,7 @@ interface EditorProps {
|
||||
isResetting: boolean;
|
||||
output: string[];
|
||||
resizeProps: ResizeProps;
|
||||
saveChallenge: () => void;
|
||||
saveEditorContent: () => void;
|
||||
setEditorFocusability: (isFocusable: boolean) => void;
|
||||
submitChallenge: () => void;
|
||||
@ -105,6 +113,7 @@ interface EditorProperties {
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
canFocusEditorSelector,
|
||||
challengeMetaSelector,
|
||||
consoleOutputSelector,
|
||||
isDonationModalOpenSelector,
|
||||
isProjectPreviewModalOpenSelector,
|
||||
@ -113,6 +122,7 @@ const mapStateToProps = createSelector(
|
||||
challengeTestsSelector,
|
||||
(
|
||||
canFocus: boolean,
|
||||
{ challengeType }: { challengeType: number },
|
||||
output: string[],
|
||||
open,
|
||||
previewOpen: boolean,
|
||||
@ -121,6 +131,7 @@ const mapStateToProps = createSelector(
|
||||
tests: [{ text: string; testString: string }]
|
||||
) => ({
|
||||
canFocus: open ? false : canFocus,
|
||||
challengeType,
|
||||
previewOpen,
|
||||
isResetting,
|
||||
output,
|
||||
@ -133,6 +144,7 @@ const mapStateToProps = createSelector(
|
||||
|
||||
const mapDispatchToProps = {
|
||||
executeChallenge,
|
||||
saveChallenge,
|
||||
saveEditorContent,
|
||||
setEditorFocusability,
|
||||
updateFile,
|
||||
@ -396,9 +408,14 @@ const Editor = (props: EditorProps): JSX.Element => {
|
||||
});
|
||||
editor.addAction({
|
||||
id: 'save-editor-content',
|
||||
label: 'Save editor content to localStorage',
|
||||
label: 'Save editor content',
|
||||
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S],
|
||||
run: props.saveEditorContent
|
||||
run:
|
||||
props.challengeType === challengeTypes.multiFileCertProject
|
||||
? // save to database
|
||||
props.saveChallenge
|
||||
: // save to local storage
|
||||
props.saveEditorContent
|
||||
});
|
||||
editor.addAction({
|
||||
id: 'toggle-accessibility',
|
||||
|
@ -24,6 +24,7 @@ const toneUrls = {
|
||||
[FlashMessages.ChallengeSubmitTooBig]: TRY_AGAIN,
|
||||
[FlashMessages.CodeSaved]: CHAL_COMP,
|
||||
[FlashMessages.CodeSaveError]: TRY_AGAIN,
|
||||
[FlashMessages.CodeSaveLess]: TRY_AGAIN,
|
||||
[FlashMessages.CompleteProjectFirst]: TRY_AGAIN,
|
||||
[FlashMessages.DeleteTokenErr]: TRY_AGAIN,
|
||||
[FlashMessages.EmailValid]: CHAL_COMP,
|
||||
|
Reference in New Issue
Block a user