Skip to content

WIP - Split state machines #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We���ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Prev Previous commit
further event cleanup
  • Loading branch information
ShMcK committed Jan 26, 2020
commit 0a781bf2ff331ea84462f03a02654e4fe1db12ff
19 changes: 14 additions & 5 deletions src/channel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Channel implements Channel {
public receive = async (action: EditorEvents) => {
// action may be an object.type or plain string
const actionType: string = typeof action === 'string' ? action : action.type
// @ts-ignore TODO: actual error, fix !
const onError = (error: CR.ErrorMessage) => this.send({ type: 'ERROR', payload: { error } })

switch (actionType) {
Expand All @@ -48,17 +49,18 @@ class Channel implements Channel {
env: {
machineId: vscode.env.machineId,
sessionId: vscode.env.sessionId,
token: '',
},
},
})
return
// continue from tutorial from local storage
case 'EDITOR_TUTORIAL_LOAD':
case 'EDITOR_LOAD_STORED_TUTORIAL':
const tutorial: G.Tutorial | null = this.context.tutorial.get()

// new tutorial
if (!tutorial || !tutorial.id || !tutorial.version) {
this.send({ type: 'NEW_TUTORIAL' })
this.send({ type: 'NO_CONTINUE' })
return
}

Expand All @@ -67,21 +69,22 @@ class Channel implements Channel {

if (progress.complete) {
// tutorial is already complete
this.send({ type: 'NEW_TUTORIAL' })
this.send({ type: 'NO_CONTINUE' })
return
}

// communicate to client the tutorial & stepProgress state
this.send({ type: 'CONTINUE_TUTORIAL', payload: { tutorial, progress, position } })
this.send({ type: 'CAN_CONTINUE', payload: { tutorial, progress, position } })

return
// clear tutorial local storage
case 'TUTORIAL_CLEAR':
case 'EDITOR_CLEAR_TUTORIAL_STORAGE':
// clear current progress/position/tutorial
this.context.reset()
return
// configure test runner, language, git
case 'EDITOR_TUTORIAL_CONFIG':
// @ts-ignore TODO: fix typings
const tutorialData: G.Tutorial = action.payload.tutorial
// setup tutorial config (save watcher, test runner, etc)
this.context.setTutorial(this.workspaceState, tutorialData)
Expand All @@ -107,17 +110,22 @@ class Channel implements Channel {
onError,
)
// update the current stepId on startup
// @ts-ignore TODO: fix typings
vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload)
return
// load step actions (git commits, commands, open files)
case 'SETUP_ACTIONS':
// @ts-ignore TODO: fix typings
await vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload)
// @ts-ignore TODO: fix typings
setupActions(this.workspaceRoot, action.payload, this.send)
return
// load solution step actions (git commits, commands, open files)
case 'SOLUTION_ACTIONS':
// @ts-ignore TODO: fix typings
await solutionActions(this.workspaceRoot, action.payload, this.send)
// run test following solution to update position
// @ts-ignore TODO: fix typings
vscode.commands.executeCommand(COMMANDS.RUN_TEST, action.payload)
return

Expand All @@ -133,6 +141,7 @@ class Channel implements Channel {
switch (actionType) {
case 'TEST_PASS':
// update local storage stepProgress
// @ts-ignore TODO: fix typings
const progress = this.context.progress.setStepComplete(action.payload.stepId)
const tutorial = this.context.tutorial.get()
if (!tutorial) {
Expand Down
33 changes: 20 additions & 13 deletions typings/events.d.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
import * as CR from './index'
import * as G from './graphql'

/* --- Editor Events --- */
/*
--- Editor Events ---
sent from client to editor
*/

export type EnvGetEvent = { type: 'ENV_LOAD'; payload: { env: CR.Environment } }
export type EnvGetEvent = { type: 'ENV_GET' }
export type EditorTutorialConfigEvent = { type: 'EDITOR_TUTORIAL_CONFIG'; payload: { tutorial: G.Tutorial } }
export type StepActionsEvent = { type: 'SETUP_ACTIONS'; payload: CR.StepActions }
export type SolutionActionsEvent = { type: 'SOLUTION_ACTIONS'; payload: CR.StepActions }

export type EditorEvents =
| EnvGetEvent
| { type: 'EDITOR_TUTORIAL_LOAD' }
| { type: 'TUTORIAL_CLEAR' }
| { type: 'EDITOR_LOAD_STORED_TUTORIAL' }
| { type: 'EDITOR_CLEAR_TUTORIAL_STORAGE' }
| EditorTutorialConfigEvent
| { type: 'EDITOR_TUTORIAL_CONTINUE_CONFIG' }
| StepActionsEvent
| SolutionActionsEvent

/* --- Client Events --- */
/*
--- Client Events ---
sent within client
or sent from editor to client
*/

export type EventLoadEvent = { type: 'ENV_LOAD'; payload: { env: CR.Environment } }
export type ErrorEvent = { type: 'ERROR'; payload: { error: string } }
export type ErrorMessageEvent = { type: 'ERROR'; payload: CR.ErrorMessage }
export type CommandStartEvent = { type: 'COMMAND_START'; payload: { process: CR.ProcessEvent } }
export type CommandSuccessEvent = { type: 'COMMAND_SUCCESS'; payload: { process: CR.ProcessEvent } }
export type CommandFailEvent = { type: 'COMMAND_FAIL'; payload: { process: CR.ProcessEvent } }
Expand All @@ -31,8 +38,8 @@ export type NextLevelEvent = { type: 'NEXT_LEVEL'; payload: { position: CR.Posit
export type TestRunningEvent = { type: 'TEST_RUNNING'; payload: { stepId: string } }
export type TestErrorEvent = { type: 'TEST_ERROR'; payload: { stepId: string } }
export type LoadNextStepEvent = { type: 'LOAD_NEXT_STEP'; payload: { step: string } }
export type ContinueTutorialEvent = {
type: 'CONTINUE_TUTORIAL'
export type CanContinueEvent = {
type: 'CAN_CONTINUE'
payload: { tutorial: G.Tutorial; progress: CR.Progress; position: CR.Position }
}
export type LoadTutorialEvent = { type: 'LOAD_TUTORIAL'; payload: { tutorial: G.Tutorial } }
Expand All @@ -58,14 +65,14 @@ export type PlayTutorialEvents =
| { type: 'EXIT' }

export type SelectTutorialEvents =
| ContinueTutorialEvent
| { type: 'NO_CONTINUE' }
| CanContinueEvent
| LoadTutorialEvent
| { type: 'NEW_TUTORIAL' }
| { type: 'BACK' }
| TutorialSelectedEvent
| { type: 'TUTORIAL_CONFIGURED' }
| { type: 'SELECT_NEW_TUTORIAL' }
| { type: 'TUTORIAL_START' }
| { type: 'CHOOSE_NEW' }
| { type: 'CHOOSE_CONTINUE' }
| ErrorEvent

type ClientEvents = MachineEvent | AuthenticateEvents | SelectTutorialEvents | PlayTutorialEvents
type ClientEvents = AuthenticateEvents | SelectTutorialEvents | PlayTutorialEvents
4 changes: 1 addition & 3 deletions web-app/src/components/Debugger/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ interface Props extends MachineContext {
children: React.ReactElement
}

const Debugger = ({ state, children, env, position, progress, processes, tutorial }: Props) => (
const Debugger = ({ state, children, position, progress, processes, tutorial }: Props) => (
<div css={{ backgroundColor: '#FFFF99', color: 'black', padding: '.5rem' }}>
<h4>state: {state}</h4>
<p>MachineId: {env.machineId}</p>
<p>SessionId: {env.sessionId}</p>
<p>tutorial: {tutorial ? tutorial.id : 'none'}</p>
<p css={{ backgroundColor: 'khaki', padding: '.5rem' }}>position: {JSON.stringify(position)}</p>
<p css={{ backgroundColor: 'moccasin', padding: '.5rem' }}>progress: {JSON.stringify(progress)}</p>
Expand Down
4 changes: 2 additions & 2 deletions web-app/src/containers/Continue/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ const ContinuePageContainer = ({ context, send }: ContainerProps) => {
return (
<ContinuePage
tutorial={tutorial}
onContinue={() => send({ type: 'TUTORIAL_START' })}
onNew={() => send({ type: 'SELECT_NEW_TUTORIAL' })}
onContinue={() => send({ type: 'CHOOSE_CONTINUE' })}
onNew={() => send({ type: 'CHOOSE_NEW' })}
/>
)
}
Expand Down
52 changes: 26 additions & 26 deletions web-app/src/services/channel/mock.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import { ClientEvents } from 'typings/events'
import channel from './index'
// import { ClientEvents } from 'typings/events'
// import channel from './index'

const createReceiveEvent = (action: ClientEvents) => ({
data: action,
})
// const createReceiveEvent = (action: ClientEvents) => ({
// data: action,
// })

// mock vscode from client side development
// @ts-ignore
window.acquireVsCodeApi = () => ({
postMessage(action: ClientEvents) {
switch (action.type) {
case 'TUTORIAL_START':
return setTimeout(() => {
const receiveAction: ClientEvents = {
type: 'TUTORIAL_LOADED',
}
channel.receive(createReceiveEvent(receiveAction))
}, 1000)
case 'TEST_RUN':
return setTimeout(() => {
const receiveAction: ClientEvents = {
type: 'TEST_PASS',
payload: action.payload,
}
channel.receive(createReceiveEvent(receiveAction))
}, 1000)
default:
console.warn(`${action.type} not found in post message mock`)
}
},
// postMessage(action: ClientEvents) {
// switch (action.type) {
// case 'CHOOSE_CONTINUE':
// return setTimeout(() => {
// const receiveAction: ClientEvents = {
// type: 'TUTORIAL_LOADED',
// }
// channel.receive(createReceiveEvent(receiveAction))
// }, 1000)
// case 'TEST_RUN':
// return setTimeout(() => {
// const receiveAction: ClientEvents = {
// type: 'TEST_PASS',
// payload: action.payload,
// }
// channel.receive(createReceiveEvent(receiveAction))
// }, 1000)
// default:
// console.warn(`${action.type} not found in post message mock`)
// }
// },
})
14 changes: 0 additions & 14 deletions web-app/src/services/selectors/position.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
import { createSelector } from 'reselect'
import * as CR from 'typings'
import * as G from 'typings/graphql'
import * as tutorial from './tutorial'

export const defaultPosition = () => ({
levelId: '',
stepId: '',
})

export const initialPosition = createSelector(tutorial.currentVersion, (version: G.TutorialVersion) => {
const level = version.data.levels[0]
const position: CR.Position = {
levelId: level.id,
stepId: level.steps[0].id,
}
return position
})
12 changes: 9 additions & 3 deletions web-app/src/services/state/authenticate/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as CR from 'typings'
import * as G from 'typings/graphql'
import { AuthenticateEvents, EnvGetEvent } from 'typings/events'
import { AuthenticateEvents, EventLoadEvent, ErrorMessageEvent } from 'typings/events'
import { assign, ActionFunctionMap } from 'xstate'
import client from '../../apollo'
import { setAuthToken } from '../../apollo/auth'
Expand All @@ -23,9 +23,14 @@ interface AuthenticateVariables {
}

const actions: ActionFunctionMap<MachineContext, AuthenticateEvents> = {
loadEnv(): void {
channel.editorSend({
type: 'ENV_GET',
})
},
// @ts-ignore
setEnv: assign({
env: (context: MachineContext, event: EnvGetEvent): CR.Environment => ({
env: (context: MachineContext, event: EventLoadEvent): CR.Environment => ({
...context.env,
...event.payload.env,
}),
Expand Down Expand Up @@ -56,7 +61,8 @@ const actions: ActionFunctionMap<MachineContext, AuthenticateEvents> = {
description: error.message,
}
}
channel.receive({ data: ErrorEvent })
// TODO: fix
// channel.receive({ data: { payload: message } })
return
})

Expand Down
6 changes: 3 additions & 3 deletions web-app/src/services/state/playTutorial/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ const actions: ActionFunctionMap<MachineContext, Event.PlayTutorialEvents> = {
),
// @ts-ignore
setError: assign({
error: (context: MachineContext, event: Event.ErrorEvent): string | null => {
return event.payload.error
error: (context: MachineContext, event: Event.ErrorMessageEvent): string | null => {
return event.payload.title
},
}),
loadLevel(context: MachineContext): void {
Expand Down Expand Up @@ -239,7 +239,7 @@ const actions: ActionFunctionMap<MachineContext, Event.PlayTutorialEvents> = {
})
},
clearStorage(): void {
channel.editorSend({ type: 'TUTORIAL_CLEAR' })
channel.editorSend({ type: 'EDITOR_CLEAR_TUTORIAL_STORAGE' })
},
}

Expand Down
3 changes: 0 additions & 3 deletions web-app/src/services/state/playTutorial/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export type StateSchema = {

export type MachineContext = {
error: CR.ErrorMessage | null
env: CR.Environment
tutorial: G.Tutorial | null
position: CR.Position
progress: CR.Progress
Expand All @@ -45,7 +44,6 @@ export const playTutorialMachine = Machine<MachineContext, StateSchema, PlayTuto
{
context: {
error: null,
env: { machineId: '', sessionId: '', token: '' },
tutorial: null,
position: { levelId: '', stepId: '' },
progress: {
Expand All @@ -57,7 +55,6 @@ export const playTutorialMachine = Machine<MachineContext, StateSchema, PlayTuto
},
id: 'tutorial',
initial: 'Level',
onEntry: ['initTutorial'],
on: {
// track commands
COMMAND_START: {
Expand Down
Loading