Feat(Challenges): no js preview (#16149)
* fix(files): Decouple files from challenges * feat(server/react): Remove action logger use redux remote devtools instead! * feat(Challenges): Disable js on edit, enable on execute * feat(Challenge/Preview): Show message when js is disabled * refactor(frameEpic): Reduce code by using lodash * feat(frameEpic): Disable js in preview by state * feat(frameEpic): Colocate epic in Challenges/redux * refactor(ExecuteChallengeEpic): CoLocated with Challenges * refactor(executeChallengesEpic): Separate tests from main logic * feat(Challenge/Preview): Update main on edit * feat(frameEpuc): Replace frame on edit/execute This allows for sandbox to work properly * fix(Challenges/Utils): Require utisl * revert(frameEpic): Hoist function to mount code in frame * fix(frameEpic): Ensure new frame is given classname * feat(executeChallenge): Update main on code unlocked * fix(frameEpic): Filter out empty test message * fix(Challenge/Preview): Remove unnessary quote in classname * feat(codeStorageEpic): Separate localstorage from solutions loading * fix(fetchUser): Merge user actions into one prefer many effects from one action over one action to one effect * fix(themes): Centralize theme utils and defs * fix(entities.user): Fix user reducer namespacing * feat(frame): Refactor frameEpic to util * feat(Challenges.redux): Should not attempt to update main from storage * fix(loadPreviousChallengeEpic): Refactor for RFR * fix(Challenges.Modern): Show preview plane
This commit is contained in:
committed by
Quincy Larson
parent
9051faee79
commit
2e410330f1
@@ -1,3 +1,4 @@
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
combineActions,
|
||||
combineReducers,
|
||||
@@ -12,14 +13,21 @@ import noop from 'lodash/noop';
|
||||
import bugEpic from './bug-epic';
|
||||
import completionEpic from './completion-epic.js';
|
||||
import challengeEpic from './challenge-epic.js';
|
||||
import editorEpic from './editor-epic.js';
|
||||
import executeChallengeEpic from './execute-challenge-epic.js';
|
||||
import codeStorageEpic from './code-storage-epic.js';
|
||||
|
||||
import ns from '../ns.json';
|
||||
import stepReducer, { epics as stepEpics } from '../views/step/redux';
|
||||
import quizReducer from '../views/quiz/redux';
|
||||
import projectReducer from '../views/project/redux';
|
||||
|
||||
import {
|
||||
createTests,
|
||||
loggerToStr,
|
||||
submitTypes,
|
||||
viewTypes
|
||||
viewTypes,
|
||||
getFileKey,
|
||||
challengeToFiles
|
||||
} from '../utils';
|
||||
import {
|
||||
types as app,
|
||||
@@ -27,19 +35,20 @@ import {
|
||||
} from '../../../redux';
|
||||
import { html } from '../../../utils/challengeTypes.js';
|
||||
import blockNameify from '../../../utils/blockNameify.js';
|
||||
import { getFileKey } from '../../../utils/classic-file.js';
|
||||
import stepReducer, { epics as stepEpics } from '../views/step/redux';
|
||||
import quizReducer from '../views/quiz/redux';
|
||||
import projectReducer from '../views/project/redux';
|
||||
import { updateFileMetaCreator, createFilesMetaCreator } from '../../../files';
|
||||
|
||||
// this is not great but is ok until we move to a different form type
|
||||
export projectNormalizer from '../views/project/redux';
|
||||
|
||||
const challengeToFilesMetaCreator =
|
||||
_.flow(challengeToFiles, createFilesMetaCreator);
|
||||
|
||||
export const epics = [
|
||||
bugEpic,
|
||||
completionEpic,
|
||||
challengeEpic,
|
||||
editorEpic,
|
||||
codeStorageEpic,
|
||||
completionEpic,
|
||||
executeChallengeEpic,
|
||||
...stepEpics
|
||||
];
|
||||
|
||||
@@ -53,7 +62,6 @@ export const types = createTypes([
|
||||
'challengeUpdated',
|
||||
'clickOnReset',
|
||||
'updateHint',
|
||||
'lockUntrustedCode',
|
||||
'unlockUntrustedCode',
|
||||
'closeChallengeModal',
|
||||
'updateSuccessMessage',
|
||||
@@ -62,10 +70,6 @@ export const types = createTypes([
|
||||
|
||||
// rechallenge
|
||||
'executeChallenge',
|
||||
'updateMain',
|
||||
'runTests',
|
||||
'frameMain',
|
||||
'frameTests',
|
||||
'updateOutput',
|
||||
'initOutput',
|
||||
'updateTests',
|
||||
@@ -86,7 +90,12 @@ export const types = createTypes([
|
||||
'togglePreview',
|
||||
'toggleSidePanel',
|
||||
'toggleStep',
|
||||
'toggleModernEditor'
|
||||
'toggleModernEditor',
|
||||
|
||||
// code storage
|
||||
'storedCodeFound',
|
||||
'noStoredCodeFound',
|
||||
'previousSolutionFound'
|
||||
], ns);
|
||||
|
||||
// routes
|
||||
@@ -95,24 +104,29 @@ export const onRouteCurrentChallenge =
|
||||
createAction(types.onRouteCurrentChallenge);
|
||||
|
||||
// classic
|
||||
export const classicEditorUpdated = createAction(types.classicEditorUpdated);
|
||||
export const classicEditorUpdated = createAction(
|
||||
types.classicEditorUpdated,
|
||||
null,
|
||||
updateFileMetaCreator
|
||||
);
|
||||
// modern
|
||||
export const modernEditorUpdated = createAction(
|
||||
types.modernEditorUpdated,
|
||||
(key, content) => ({ key, content })
|
||||
null,
|
||||
createFilesMetaCreator
|
||||
);
|
||||
// challenges
|
||||
export const closeChallengeModal = createAction(types.closeChallengeModal);
|
||||
export const updateHint = createAction(types.updateHint);
|
||||
export const lockUntrustedCode = createAction(types.lockUntrustedCode);
|
||||
export const unlockUntrustedCode = createAction(
|
||||
types.unlockUntrustedCode,
|
||||
() => null
|
||||
_.noop
|
||||
);
|
||||
export const updateSuccessMessage = createAction(types.updateSuccessMessage);
|
||||
export const challengeUpdated = createAction(
|
||||
types.challengeUpdated,
|
||||
challenge => ({ challenge })
|
||||
challenge => ({ challenge }),
|
||||
challengeToFilesMetaCreator
|
||||
);
|
||||
export const clickOnReset = createAction(types.clickOnReset);
|
||||
|
||||
@@ -122,11 +136,6 @@ export const executeChallenge = createAction(
|
||||
noop,
|
||||
);
|
||||
|
||||
export const updateMain = createAction(types.updateMain);
|
||||
export const frameMain = createAction(types.frameMain);
|
||||
export const frameTests = createAction(types.frameTests);
|
||||
|
||||
export const runTests = createAction(types.runTests);
|
||||
export const updateTests = createAction(types.updateTests);
|
||||
|
||||
export const initOutput = createAction(types.initOutput, loggerToStr);
|
||||
@@ -148,6 +157,19 @@ export const closeBugModal = createAction(types.closeBugModal);
|
||||
export const openIssueSearch = createAction(types.openIssueSearch);
|
||||
export const createIssue = createAction(types.createIssue);
|
||||
|
||||
// code storage
|
||||
export const storedCodeFound = createAction(
|
||||
types.storedCodeFound,
|
||||
null,
|
||||
challengeToFilesMetaCreator,
|
||||
);
|
||||
export const noStoredCodeFound = createAction(types.noStoredCodeFound);
|
||||
export const previousSolutionFound = createAction(
|
||||
types.previousSolutionFound,
|
||||
null,
|
||||
challengeToFilesMetaCreator
|
||||
);
|
||||
|
||||
const initialUiState = {
|
||||
output: null,
|
||||
isChallengeModalOpen: false,
|
||||
@@ -157,6 +179,7 @@ const initialUiState = {
|
||||
|
||||
const initialState = {
|
||||
isCodeLocked: false,
|
||||
isJSEnabled: true,
|
||||
id: '',
|
||||
challenge: '',
|
||||
helpChatRoom: 'Help',
|
||||
@@ -176,6 +199,8 @@ export const outputSelector = state => getNS(state).output;
|
||||
export const successMessageSelector = state => getNS(state).successMessage;
|
||||
export const hintIndexSelector = state => getNS(state).hintIndex;
|
||||
export const codeLockedSelector = state => getNS(state).isCodeLocked;
|
||||
export const isCodeLockedSelector = state => getNS(state).isCodeLocked;
|
||||
export const isJSEnabledSelector = state => getNS(state).isJSEnabled;
|
||||
export const chatRoomSelector = state => getNS(state).helpChatRoom;
|
||||
export const challengeModalSelector =
|
||||
state => getNS(state).isChallengeModalOpen;
|
||||
@@ -204,7 +229,10 @@ export const challengeMetaSelector = createSelector(
|
||||
submitTypes[challengeType] ||
|
||||
submitTypes[challenge && challenge.type] ||
|
||||
'tests',
|
||||
showPreview: challengeType === html,
|
||||
showPreview: (
|
||||
challengeType === html ||
|
||||
type === 'modern'
|
||||
),
|
||||
mode: challenge && challengeType === html ?
|
||||
'text/html' :
|
||||
'javascript'
|
||||
@@ -250,8 +278,9 @@ export default combineReducers(
|
||||
...state,
|
||||
successMessage: payload
|
||||
}),
|
||||
[types.lockUntrustedCode]: state => ({
|
||||
[types.storedCodeFound]: state => ({
|
||||
...state,
|
||||
isJSEnabled: false,
|
||||
isCodeLocked: true
|
||||
}),
|
||||
[types.unlockUntrustedCode]: state => ({
|
||||
@@ -260,8 +289,18 @@ export default combineReducers(
|
||||
}),
|
||||
[types.executeChallenge]: state => ({
|
||||
...state,
|
||||
isJSEnabled: true,
|
||||
tests: state.tests.map(test => ({ ...test, err: false, pass: false }))
|
||||
}),
|
||||
[
|
||||
combineActions(
|
||||
types.classicEditorUpdated,
|
||||
types.modernEditorUpdated
|
||||
)
|
||||
]: state => ({
|
||||
...state,
|
||||
isJSEnabled: false
|
||||
}),
|
||||
|
||||
// classic/modern
|
||||
[types.initOutput]: (state, { payload: output }) => ({
|
||||
|
Reference in New Issue
Block a user