From 3b9781f13a0bd46b62a11ae39efc1168dadf1179 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Wed, 23 May 2018 11:13:20 +0800 Subject: [PATCH 1/3] Add stop button --- src/components/IDE/Control.tsx | 3 +++ src/components/IDE/__tests__/Control.tsx | 3 ++- .../IDE/__tests__/__snapshots__/Control.tsx.snap | 5 +++++ src/containers/IDE/ControlContainer.ts | 7 +++++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/IDE/Control.tsx b/src/components/IDE/Control.tsx index 39523903ca..11a96ae8d6 100644 --- a/src/components/IDE/Control.tsx +++ b/src/components/IDE/Control.tsx @@ -10,6 +10,7 @@ export interface IControlProps { handleEvalEditor: () => void handleEvalRepl: () => void handleClearReplOutput: () => void + handleInterruptEval: () => void } class Control extends React.Component { @@ -31,11 +32,13 @@ class Control extends React.Component { ) const runButton = genericButton('Run', 'play', this.props.handleEvalEditor) + const stopButton = genericButton('Stop', 'stop', this.props.handleInterruptEval) const evalButton = genericButton('Eval', 'play', this.props.handleEvalRepl) const clearButton = genericButton('Clear', 'remove', this.props.handleClearReplOutput) return (
{runButton}
+
{stopButton}
{evalButton}
diff --git a/src/components/IDE/__tests__/Control.tsx b/src/components/IDE/__tests__/Control.tsx index 2a2c8646b3..6963f35592 100644 --- a/src/components/IDE/__tests__/Control.tsx +++ b/src/components/IDE/__tests__/Control.tsx @@ -8,7 +8,8 @@ test('Control renders correctly', () => { const props: IControlProps = { handleEvalEditor: () => {}, handleEvalRepl: () => {}, - handleClearReplOutput: () => {} + handleClearReplOutput: () => {}, + handleInterruptEval: () => {} } const app = const tree = shallow(app) diff --git a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap index 162ba7418a..e29d618f92 100644 --- a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap +++ b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap @@ -7,6 +7,11 @@ exports[`Control renders correctly 1`] = ` Run
+
+ + Stop + +
diff --git a/src/containers/IDE/ControlContainer.ts b/src/containers/IDE/ControlContainer.ts index bf0102f302..eed959ad8b 100644 --- a/src/containers/IDE/ControlContainer.ts +++ b/src/containers/IDE/ControlContainer.ts @@ -1,13 +1,15 @@ import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux' import { bindActionCreators, Dispatch } from 'redux' +import { handleInterruptExecution } from '../../actions/interpreter' import { clearReplOutput, evalEditor, evalRepl } from '../../actions/playground' import Control, { IControlProps } from '../../components/IDE/Control' import { IState } from '../../reducers/states' type DispatchProps = Pick & Pick & - Pick + Pick & + Pick /** No-op mapStateToProps */ const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({}) @@ -20,7 +22,8 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis { handleEvalEditor: evalEditor, handleEvalRepl: evalRepl, - handleClearReplOutput: clearReplOutput + handleClearReplOutput: clearReplOutput, + handleInterruptEval: handleInterruptExecution }, dispatch ) From 282c2169c6e8a3a5a4a0c40b07b02f95d0f0c15c Mon Sep 17 00:00:00 2001 From: remo5000 Date: Wed, 23 May 2018 11:41:15 +0800 Subject: [PATCH 2/3] Add notification for interruption --- src/sagas/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sagas/index.ts b/src/sagas/index.ts index de6a26988b..b19099c738 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -6,6 +6,7 @@ import { Context, interrupt, runInContext } from '../slang' import * as actions from '../actions' import * as actionTypes from '../actions/actionTypes' +import { showWarningMessage } from '../notification' function* evalCode(code: string, context: Context) { const { result, interrupted } = yield race({ @@ -20,6 +21,7 @@ function* evalCode(code: string, context: Context) { } } else if (interrupted) { interrupt(context) + yield call(showWarningMessage, 'Execution aborted by user') } } From e5a8aa0b9fb4d372761483322258b7506b7a2500 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Wed, 23 May 2018 12:32:54 +0800 Subject: [PATCH 3/3] Add isRunning state with switching 'Run' button When code is running (`isRunning == true`), Run button changes into a Stop button. The reverse is true. In addition, the soft block for async code execution, `put(actions.handleInterruptExecution())` was removed. --- src/components/IDE/Control.tsx | 15 ++++++++---- src/components/IDE/__tests__/Control.tsx | 1 + .../__tests__/__snapshots__/Control.tsx.snap | 5 ---- src/containers/IDE/ControlContainer.ts | 6 ++++- src/reducers/playground.ts | 24 +++++++++++++++++-- src/reducers/states.ts | 4 +++- src/sagas/index.ts | 2 -- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/components/IDE/Control.tsx b/src/components/IDE/Control.tsx index 11a96ae8d6..ee54aa5014 100644 --- a/src/components/IDE/Control.tsx +++ b/src/components/IDE/Control.tsx @@ -7,6 +7,7 @@ import { Button, IconName, Intent } from '@blueprintjs/core' * of the editor's content, using `slang` */ export interface IControlProps { + isRunning: boolean handleEvalEditor: () => void handleEvalRepl: () => void handleClearReplOutput: () => void @@ -31,14 +32,20 @@ class Control extends React.Component { {label} ) - const runButton = genericButton('Run', 'play', this.props.handleEvalEditor) - const stopButton = genericButton('Stop', 'stop', this.props.handleInterruptEval) + const runButton = this.props.isRunning + ? null + : genericButton('Run', 'play', this.props.handleEvalEditor) + const stopButton = this.props.isRunning + ? genericButton('Stop', 'stop', this.props.handleInterruptEval) + : null const evalButton = genericButton('Eval', 'play', this.props.handleEvalRepl) const clearButton = genericButton('Clear', 'remove', this.props.handleClearReplOutput) return (
-
{runButton}
-
{stopButton}
+
+ {runButton} + {stopButton} +
{evalButton}
diff --git a/src/components/IDE/__tests__/Control.tsx b/src/components/IDE/__tests__/Control.tsx index 6963f35592..941a3e1239 100644 --- a/src/components/IDE/__tests__/Control.tsx +++ b/src/components/IDE/__tests__/Control.tsx @@ -6,6 +6,7 @@ import Control, { IControlProps } from '../Control' test('Control renders correctly', () => { const props: IControlProps = { + isRunning: false, handleEvalEditor: () => {}, handleEvalRepl: () => {}, handleClearReplOutput: () => {}, diff --git a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap index e29d618f92..162ba7418a 100644 --- a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap +++ b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap @@ -7,11 +7,6 @@ exports[`Control renders correctly 1`] = ` Run
-
- - Stop - -
diff --git a/src/containers/IDE/ControlContainer.ts b/src/containers/IDE/ControlContainer.ts index eed959ad8b..0c52a2baa6 100644 --- a/src/containers/IDE/ControlContainer.ts +++ b/src/containers/IDE/ControlContainer.ts @@ -6,13 +6,17 @@ import { clearReplOutput, evalEditor, evalRepl } from '../../actions/playground' import Control, { IControlProps } from '../../components/IDE/Control' import { IState } from '../../reducers/states' +type StateProps = Pick + type DispatchProps = Pick & Pick & Pick & Pick /** No-op mapStateToProps */ -const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({}) +const mapStateToProps: MapStateToProps = state => ({ + isRunning: state.playground.isRunning +}) /** Provides a callback function `handleEvalEditor` * to evaluate code in the Editor. diff --git a/src/reducers/playground.ts b/src/reducers/playground.ts index c42e4a45ab..bf61c73cc6 100644 --- a/src/reducers/playground.ts +++ b/src/reducers/playground.ts @@ -3,10 +3,13 @@ import { CLEAR_CONTEXT, CLEAR_REPL_INPUT, CLEAR_REPL_OUTPUT, + EVAL_EDITOR, + EVAL_INTERPRETER, EVAL_INTERPRETER_ERROR, EVAL_INTERPRETER_SUCCESS, HANDLE_CONSOLE_LOG, IAction, + INTERRUPT_EXECUTION, SEND_REPL_INPUT_TO_OUTPUT, UPDATE_EDITOR_VALUE, UPDATE_REPL_VALUE @@ -68,6 +71,16 @@ export const reducer: Reducer = (state = defaultPlayground, ac ...state, output: newOutput } + case EVAL_EDITOR: + return { + ...state, + isRunning: true + } + case EVAL_INTERPRETER: + return { + ...state, + isRunning: true + } case EVAL_INTERPRETER_SUCCESS: lastOutput = state.output.slice(-1)[0] if (lastOutput !== undefined && lastOutput.type === 'running') { @@ -83,7 +96,8 @@ export const reducer: Reducer = (state = defaultPlayground, ac } return { ...state, - output: newOutput + output: newOutput, + isRunning: false } case EVAL_INTERPRETER_ERROR: lastOutput = state.output.slice(-1)[0] @@ -100,7 +114,13 @@ export const reducer: Reducer = (state = defaultPlayground, ac } return { ...state, - output: newOutput + output: newOutput, + isRunning: false + } + case INTERRUPT_EXECUTION: + return { + ...state, + isRunning: false } default: return state diff --git a/src/reducers/states.ts b/src/reducers/states.ts index 435cf2f790..696621780f 100644 --- a/src/reducers/states.ts +++ b/src/reducers/states.ts @@ -16,6 +16,7 @@ export interface IPlaygroundState { readonly replValue: string readonly context: Context readonly output: InterpreterOutput[] + readonly isRunning: boolean } /** @@ -90,5 +91,6 @@ export const defaultPlayground: IPlaygroundState = { editorValue: '', replValue: '', context: createContext(), - output: [] + output: [], + isRunning: false } diff --git a/src/sagas/index.ts b/src/sagas/index.ts index b19099c738..6b5fe39e69 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -31,7 +31,6 @@ function* interpreterSaga(): SagaIterator { yield takeEvery(actionTypes.EVAL_EDITOR, function*() { const code: string = yield select((state: IState) => state.playground.editorValue) - yield put(actions.handleInterruptExecution()) yield put(actions.clearContext()) yield put(actions.clearReplOutput()) context = yield select((state: IState) => state.playground.context) @@ -41,7 +40,6 @@ function* interpreterSaga(): SagaIterator { yield takeEvery(actionTypes.EVAL_REPL, function*() { const code: string = yield select((state: IState) => state.playground.replValue) context = yield select((state: IState) => state.playground.context) - yield put(actions.handleInterruptExecution()) yield put(actions.clearReplInput()) yield put(actions.sendReplInputToOutput(code)) yield* evalCode(code, context)