diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts index 6a349355..b5bf9e55 100644 --- a/src/actions/setupActions.ts +++ b/src/actions/setupActions.ts @@ -14,6 +14,9 @@ interface SetupActions { } export const setupActions = async ({ actions, send, path }: SetupActions): Promise => { + if (!actions) { + return + } const { commands, commits, files, watchers } = actions // validate commit is new diff --git a/src/actions/utils/loadWatchers.ts b/src/actions/utils/loadWatchers.ts index 77a15f6a..1463c055 100644 --- a/src/actions/utils/loadWatchers.ts +++ b/src/actions/utils/loadWatchers.ts @@ -37,9 +37,11 @@ const loadWatchers = (watchers: string[]) => { fsWatcher.on('change', (path, event) => { const now = +new Date() if (!lastFire || lastFire - now > 1000) { - vscode.commands.executeCommand(COMMANDS.RUN_TEST, null, () => { - // cleanup watcher on success - disposeWatcher(watcher) + vscode.commands.executeCommand(COMMANDS.RUN_TEST, { + onSuccess: () => { + // cleanup watcher on success + disposeWatcher(watcher) + }, }) } }) diff --git a/src/channel/index.ts b/src/channel/index.ts index 7a82c34e..458cc226 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -224,7 +224,7 @@ class Channel implements Channel { alreadyConfigured: true, }) // update the current stepId on startup - vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload) + vscode.commands.executeCommand(COMMANDS.SET_CURRENT_POSITION, action.payload.position) } catch (e) { const error = { type: 'UnknownError', @@ -286,14 +286,15 @@ class Channel implements Channel { return // load step actions (git commits, commands, open files) case 'SETUP_ACTIONS': - await vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload) - setupActions({ actions: action.payload, send: this.send }) + await vscode.commands.executeCommand(COMMANDS.SET_CURRENT_POSITION, action.payload.position) + setupActions({ actions: action.payload.actions, send: this.send }) return // load solution step actions (git commits, commands, open files) case 'SOLUTION_ACTIONS': - await solutionActions({ actions: action.payload, send: this.send }) + await vscode.commands.executeCommand(COMMANDS.SET_CURRENT_POSITION, action.payload.position) + await solutionActions({ actions: action.payload.actions, send: this.send }) // run test following solution to update position - vscode.commands.executeCommand(COMMANDS.RUN_TEST, action.payload) + vscode.commands.executeCommand(COMMANDS.RUN_TEST) return default: @@ -328,12 +329,13 @@ class Channel implements Channel { switch (actionType) { case 'TEST_PASS': + console.log('TEST_PASS', action) const tutorial = this.context.tutorial.get() if (!tutorial) { throw new Error('Error with current tutorial. Tutorial may be missing an id.') } // update local storage stepProgress - const progress = this.context.progress.setStepComplete(tutorial, action.payload.stepId) + const progress = this.context.progress.setStepComplete(tutorial, action.payload.position.stepId) this.context.position.setPositionFromProgress(tutorial, progress) saveCommit() } diff --git a/src/editor/commands.ts b/src/editor/commands.ts index 57ed0e0c..19b96585 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -1,15 +1,17 @@ +import * as T from 'typings' import * as TT from 'typings/tutorial' import * as vscode from 'vscode' -import createTestRunner, { Payload } from '../services/testRunner' +import createTestRunner from '../services/testRunner' import { setupActions } from '../actions/setupActions' import createWebView from '../webview' +import logger from '../services/logger' export const COMMANDS = { START: 'coderoad.start', OPEN_WEBVIEW: 'coderoad.open_webview', CONFIG_TEST_RUNNER: 'coderoad.config_test_runner', RUN_TEST: 'coderoad.run_test', - SET_CURRENT_STEP: 'coderoad.set_current_step', + SET_CURRENT_POSITION: 'coderoad.set_current_position', } interface CreateCommandProps { @@ -20,7 +22,7 @@ interface CreateCommandProps { export const createCommands = ({ extensionPath, workspaceState }: CreateCommandProps) => { // React panel webview let webview: any - let currentStepId: string | null = '' + let currentPosition: T.Position let testRunner: any return { @@ -55,32 +57,38 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP await setupActions({ actions: config.actions, send: webview.send, path: config.path }) } testRunner = createTestRunner(config, { - onSuccess: (payload: Payload) => { + onSuccess: (position: T.Position) => { + logger('test pass position', position) // send test pass message back to client - webview.send({ type: 'TEST_PASS', payload }) + webview.send({ type: 'TEST_PASS', payload: { position } }) }, - onFail: (payload: Payload, message: string) => { + onFail: (position: T.Position, message: string) => { // send test fail message back to client with failure message - webview.send({ type: 'TEST_FAIL', payload: { ...payload, message } }) + webview.send({ type: 'TEST_FAIL', payload: { position, message } }) }, - onError: (payload: Payload) => { - // send test error message back to client - webview.send({ type: 'TEST_ERROR', payload }) + onError: (position: T.Position) => { + // TODO: send test error message back to client + const message = 'Error with test runner' + webview.send({ type: 'TEST_ERROR', payload: { position, message } }) }, - onRun: (payload: Payload) => { + onRun: (position: T.Position) => { // send test run message back to client - webview.send({ type: 'TEST_RUNNING', payload }) + webview.send({ type: 'TEST_RUNNING', payload: { position } }) }, }) }, - [COMMANDS.SET_CURRENT_STEP]: ({ stepId }: Payload) => { + [COMMANDS.SET_CURRENT_POSITION]: (position: T.Position) => { // set from last setup stepAction - currentStepId = stepId + currentPosition = position }, - [COMMANDS.RUN_TEST]: (current: Payload | undefined, onSuccess: () => void) => { + [COMMANDS.RUN_TEST]: (callback?: { onSuccess: () => void }) => { + logger('run test current', currentPosition) // use stepId from client, or last set stepId - const payload: Payload = { stepId: current && current.stepId?.length ? current.stepId : currentStepId } - testRunner(payload, onSuccess) + // const position: T.Position = { + // ...current, + // stepId: current && current.position.stepId?.length ? current.position.stepId : currentPosition.stepId, + // } + testRunner(currentPosition, callback?.onSuccess) }, } } diff --git a/src/services/logger/index.ts b/src/services/logger/index.ts index ea79bcdf..8d193311 100644 --- a/src/services/logger/index.ts +++ b/src/services/logger/index.ts @@ -1,6 +1,6 @@ import { LOG } from '../../environment' -export type Log = string | object | null +export type Log = string | object | null | undefined const logger = (...messages: Log[]): void => { if (!LOG) { diff --git a/src/services/testRunner/index.ts b/src/services/testRunner/index.ts index c9c12cf2..182abc5e 100644 --- a/src/services/testRunner/index.ts +++ b/src/services/testRunner/index.ts @@ -1,4 +1,5 @@ -import { TutorialTestRunnerConfig } from 'typings/tutorial' +import * as T from 'typings' +import * as TT from 'typings/tutorial' import { exec } from '../node' import logger from '../logger' import parser from './parser' @@ -7,22 +8,19 @@ import onError from '../sentry/onError' import { clearOutput, displayOutput } from './output' import { formatFailOutput } from './formatOutput' -export interface Payload { - stepId: string | null -} - interface Callbacks { - onSuccess(payload: Payload): void - onFail(payload: Payload, message: string): void - onRun(payload: Payload): void - onError(payload: Payload): void + onSuccess(position: T.Position): void + onFail(position: T.Position, message: string): void + onRun(position: T.Position): void + onError(position: T.Position): void } const failChannelName = 'CodeRoad (Tests)' const logChannelName = 'CodeRoad (Logs)' -const createTestRunner = (config: TutorialTestRunnerConfig, callbacks: Callbacks) => { - return async (payload: Payload, onSuccess?: () => void): Promise => { +const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callbacks) => { + return async (position: T.Position, onSuccess?: () => void): Promise => { + logger('createTestRunner', position) const startTime = throttle() // throttle time early if (!startTime) { @@ -32,7 +30,7 @@ const createTestRunner = (config: TutorialTestRunnerConfig, callbacks: Callbacks logger('------------------- RUN TEST -------------------') // flag as running - callbacks.onRun(payload) + callbacks.onRun(position) let result: { stdout: string | undefined; stderr: string | undefined } try { @@ -59,12 +57,12 @@ const createTestRunner = (config: TutorialTestRunnerConfig, callbacks: Callbacks // FAIL also trigger stderr if (stdout && stdout.length && !tap.ok) { const firstFailMessage = tap.failed[0].message - callbacks.onFail(payload, firstFailMessage) + callbacks.onFail(position, firstFailMessage) const output = formatFailOutput(tap) displayOutput({ channel: failChannelName, text: output, show: true }) return } else { - callbacks.onError(payload) + callbacks.onError(position) // open terminal with error string displayOutput({ channel: failChannelName, text: stderr, show: true }) return @@ -74,14 +72,14 @@ const createTestRunner = (config: TutorialTestRunnerConfig, callbacks: Callbacks // PASS if (tap.ok) { clearOutput(failChannelName) - callbacks.onSuccess(payload) + callbacks.onSuccess(position) if (onSuccess) { onSuccess() } } else { // should never get here - onError(new Error(`Error with running test ${JSON.stringify(payload)}`)) - callbacks.onError(payload) + onError(new Error(`Error with running test ${JSON.stringify(position)}`)) + callbacks.onError(position) } } } diff --git a/src/webview/render.ts b/src/webview/render.ts index 59379261..1bf5bf6a 100644 --- a/src/webview/render.ts +++ b/src/webview/render.ts @@ -31,6 +31,7 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { const createUri = (_filePath: string): any => { const filePath = (_filePath.startsWith('vscode') ? _filePath.substr(16) : _filePath).replace('///', '\\') + // @ts-ignore return panel.webview.asWebviewUri(vscode.Uri.file(path.join(rootPath, filePath))) } diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 8dd3f083..e179effe 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -109,7 +109,7 @@ const contextActions: ActionFunctionMap = { // update progress by tracking completed const currentProgress: T.Progress = context.progress - const { stepId } = event.payload + const { stepId } = event.payload.position currentProgress.steps[stepId] = true diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index e8352bd5..5770abf2 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -22,19 +22,24 @@ export default (editorSend: any) => ({ type: 'EDITOR_TUTORIAL_CONTINUE_CONFIG', payload: { // pass position because current stepId or first stepId will be empty - stepId: context.position.stepId, + position: context.position, }, }) }, loadLevel(context: CR.MachineContext): void { const level: TT.Level = selectors.currentLevel(context) - if (level.setup) { - // load step actions - editorSend({ - type: 'SETUP_ACTIONS', - payload: level.setup, - }) - } + const step: TT.Step | null = selectors.currentStep(context) + // load step actions + editorSend({ + type: 'SETUP_ACTIONS', + payload: { + position: { + stepId: step?.id || null, + levelId: level.id, + }, + actions: level.setup, + }, + }) }, loadStep(context: CR.MachineContext): void { const step: TT.Step | null = selectors.currentStep(context) @@ -43,8 +48,12 @@ export default (editorSend: any) => ({ editorSend({ type: 'SETUP_ACTIONS', payload: { - stepId: step.id, - ...step.setup, + // set position here + position: { + stepId: step.id, + levelId: context.position.levelId, + }, + actions: step.setup, }, }) } @@ -56,8 +65,11 @@ export default (editorSend: any) => ({ editorSend({ type: 'SOLUTION_ACTIONS', payload: { - stepId: step.id, - ...step.solution, + position: { + stepId: step.id, + levelId: context.position.levelId, + }, + actions: step.solution, }, }) }