From 3d242179b28ca5479bcc9995fe58e6cc4e69c54c Mon Sep 17 00:00:00 2001 From: Tom <20648924+moT01@users.noreply.github.com> Date: Mon, 4 Apr 2022 07:32:43 -0500 Subject: [PATCH] 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 --- client/i18n/locales/english/translations.json | 1 + .../components/Flash/redux/flash-messages.ts | 1 + client/src/redux/save-challenge-saga.js | 14 ++++++++++- .../templates/Challenges/classic/editor.tsx | 23 ++++++++++++++++--- client/src/utils/tone/index.ts | 1 + 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index 388ad6aaf0..cc941594e8 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -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" }, diff --git a/client/src/components/Flash/redux/flash-messages.ts b/client/src/components/Flash/redux/flash-messages.ts index 0658f13b93..ad74e91701 100644 --- a/client/src/components/Flash/redux/flash-messages.ts +++ b/client/src/components/Flash/redux/flash-messages.ts @@ -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', diff --git a/client/src/redux/save-challenge-saga.js b/client/src/redux/save-challenge-saga.js index 14fd436003..9b081245de 100644 --- a/client/src/redux/save-challenge-saga.js +++ b/client/src/redux/save-challenge-saga.js @@ -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) { diff --git a/client/src/templates/Challenges/classic/editor.tsx b/client/src/templates/Challenges/classic/editor.tsx index 7cfba6cb78..8b3b4fdc2a 100644 --- a/client/src/templates/Challenges/classic/editor.tsx +++ b/client/src/templates/Challenges/classic/editor.tsx @@ -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; 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', diff --git a/client/src/utils/tone/index.ts b/client/src/utils/tone/index.ts index 1518142247..f75d237824 100644 --- a/client/src/utils/tone/index.ts +++ b/client/src/utils/tone/index.ts @@ -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,