Skip to content
Merged
Next Next commit
remove progress progress
Signed-off-by: shmck <shawn.j.mckay@gmail.com>
  • Loading branch information
ShMcK committed Jul 31, 2020
commit 7766d824ca227eee387eba93f433ce1bb6930662
4 changes: 2 additions & 2 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { default as onStartup } from './onStartup'
export { default as onTutorialConfig } from './onTutorialConfig'
export { default as onTutorialContinueConfig } from './onTutorialContinueConfig'
export { default as onTutorialConfigNew } from './onTutorialConfigNew'
export { default as onTutorialConfigContinue } from './onTutorialConfigContinue'
export { default as onValidateSetup } from './onValidateSetup'
export { default as onRunReset } from './onRunReset'
export { default as onErrorPage } from './onErrorPage'
Expand Down
22 changes: 8 additions & 14 deletions src/actions/onStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,26 @@ const onStartup = async (
// no stored tutorial, must start new tutorial
if (!tutorial || !tutorial.id) {
if (TUTORIAL_URL) {
// launch from a url env variable
// NEW_FROM_URL
try {
const tutorialRes = await fetch(TUTORIAL_URL)
const tutorial = await tutorialRes.json()
send({ type: 'START_TUTORIAL_FROM_URL', payload: { tutorial } })
return
} catch (e) {
// on failure to load a tutorial url fallback to NEW
console.log(`Failed to load tutorial from url ${TUTORIAL_URL} with error "${e.message}"`)
}
} else {
// launch from a selected tutorial
send({ type: 'START_NEW_TUTORIAL', payload: { env } })
}
// NEW
send({ type: 'START_NEW_TUTORIAL', payload: { env } })
return
}

// load continued tutorial position & progress
const { position, progress } = await context.setTutorial(workspaceState, tutorial)
logger('CONTINUE STATE', position, progress)

if (progress.complete) {
// tutorial is already complete
send({ type: 'TUTORIAL_ALREADY_COMPLETE', payload: { env } })
return
}
// CONTINUE_FROM_PROGRESS
const { position } = await context.onContinue(tutorial)
// communicate to client the tutorial & stepProgress state
send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, progress, position } })
send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, position } })
} catch (e) {
const error = {
type: 'UnknownError',
Expand Down
8 changes: 1 addition & 7 deletions src/actions/onTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@ import { COMMANDS } from '../commands'
import Context from '../services/context/context'

export const onTestPass = (action: T.Action, context: Context) => {
const tutorial = context.tutorial.get()
if (!tutorial) {
throw new Error('Error with current tutorial. Tutorial may be missing an id.')
}
// update local storage stepProgress
const progress = context.progress.setStepComplete(tutorial, action.payload.position.stepId)
context.position.setPositionFromProgress(tutorial, progress)
context.position.set({ ...action.payload.position, complete: true })
git.saveCommit('Save progress')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Context from '../services/context/context'
import tutorialConfig from './utils/tutorialConfig'
import { COMMANDS } from '../commands'

const onTutorialContinueConfig = async (action: T.Action, context: Context, send: any) => {
const onTutorialConfigContinue = async (action: T.Action, context: Context, send: any) => {
try {
const tutorialContinue: TT.Tutorial | null = context.tutorial.get()
if (!tutorialContinue) {
Expand All @@ -26,4 +26,4 @@ const onTutorialContinueConfig = async (action: T.Action, context: Context, send
}
}

export default onTutorialContinueConfig
export default onTutorialConfigContinue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { version, compareVersions } from '../services/dependencies'
import Context from '../services/context/context'
import tutorialConfig from './utils/tutorialConfig'

const onTutorialConfig = async (action: T.Action, context: Context, workspaceState: vscode.Memento, send: any) => {
const onTutorialConfigNew = async (action: T.Action, context: Context, send: any) => {
try {
const data: TT.Tutorial = action.payload.tutorial

Expand Down Expand Up @@ -37,7 +37,7 @@ const onTutorialConfig = async (action: T.Action, context: Context, workspaceSta
}

// setup tutorial config (save watcher, test runner, etc)
await context.setTutorial(workspaceState, data)
await context.onNew(data)

// validate dependencies
const dependencies = data.config.dependencies
Expand Down Expand Up @@ -118,4 +118,4 @@ const onTutorialConfig = async (action: T.Action, context: Context, workspaceSta
}
}

export default onTutorialConfig
export default onTutorialConfigNew
12 changes: 4 additions & 8 deletions src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,12 @@ class Channel implements Channel {
actions.onStartup(this.context, this.workspaceState, this.send)
return
// clear tutorial local storage
case 'TUTORIAL_CLEAR':
// clear current progress/position/tutorial
this.context.reset()
return
// configure test runner, language, git
case 'EDITOR_TUTORIAL_CONFIG':
actions.onTutorialConfig(action, this.context, this.workspaceState, this.send)
actions.onTutorialConfigNew(action, this.context, this.send)
return
case 'EDITOR_TUTORIAL_CONTINUE_CONFIG':
actions.onTutorialContinueConfig(action, this.context, this.send)
actions.onTutorialConfigContinue(action, this.context, this.send)
return
case 'EDITOR_VALIDATE_SETUP':
actions.onValidateSetup(this.send)
Expand All @@ -69,9 +65,9 @@ class Channel implements Channel {
// run test following solution to update position
actions.onRunTest()
return
case 'EDITOR_SYNC_PROGRESS':
case 'EDITOR_SYNC_POSITION':
// update progress when a level is deemed complete in the client
await this.context.progress.syncProgress(action.payload.progress)
await this.context.position.set(action.payload.position)
return
case 'EDITOR_OPEN_LOGS':
actions.onOpenLogs(action)
Expand Down
2 changes: 1 addition & 1 deletion src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type Env = 'test' | 'local' | 'development' | 'production'
export const NODE_ENV: Env = process.env.NODE_ENV || 'development'

// toggle logging in development
export const LOG = false
export const LOG = true

// error logging tool
export const INSTRUMENTATION_KEY = '6ff37c76-72f3-48e3-a1b9-d5636f519b7b'
Expand Down
24 changes: 9 additions & 15 deletions src/services/context/context.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
import * as CR from 'typings'
import * as T from 'typings'
import * as TT from 'typings/tutorial'
import * as vscode from 'vscode'
import Position from './state/Position'
import Progress from './state/Progress'
import Tutorial from './state/Tutorial'

class Context {
public tutorial: Tutorial
public position: Position
public progress: Progress
private workspaceState: vscode.Memento
constructor(workspaceState: vscode.Memento) {
// state held in one place
this.workspaceState = workspaceState
this.tutorial = new Tutorial(workspaceState)
this.position = new Position()
this.progress = new Progress()
}
public setTutorial = async (
workspaceState: vscode.Memento,
tutorial: TT.Tutorial,
): Promise<{ progress: CR.Progress; position: CR.Position }> => {
public onNew = async (tutorial: TT.Tutorial): Promise<{ position: T.Position }> => {
this.tutorial.set(tutorial)
const progress: CR.Progress = await this.progress.setTutorial(workspaceState, tutorial)
const position: CR.Position = this.position.setPositionFromProgress(tutorial, progress)
return { progress, position }
const position: T.Position = await this.position.initPosition(this.workspaceState, tutorial)
return { position }
}
public reset = (): void => {
this.tutorial.reset()
this.progress.reset()
this.position.reset()
public onContinue = async (tutorial: TT.Tutorial): Promise<{ position: T.Position }> => {
const position: T.Position = await this.position.continuePosition(this.workspaceState, tutorial)
return { position }
}
}

Expand Down
92 changes: 34 additions & 58 deletions src/services/context/state/Position.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,54 @@
import * as CR from 'typings'
import * as vscode from 'vscode'
import * as T from 'typings'
import * as TT from 'typings/tutorial'
import Storage from '../../storage'

const defaultValue: CR.Position = {
const defaultValue: T.Position = {
levelId: '',
stepId: null,
complete: false,
}

// position
class Position {
private value: CR.Position
private value: T.Position
private storage: Storage<T.Position> | undefined
constructor() {
this.value = defaultValue
}
setTutorial(workspaceState: vscode.Memento, tutorial: TT.Tutorial) {
this.storage = new Storage<T.Position>({
key: `coderoad:position:${tutorial.id}:${tutorial.version}`,
storage: workspaceState,
defaultValue,
})
}
async initPosition(workspaceState: vscode.Memento, tutorial: TT.Tutorial): Promise<T.Position> {
// set value from storage
this.setTutorial(workspaceState, tutorial)
// find first level & step id
let initLevel = tutorial.levels.length ? tutorial.levels[0] : null
return this.set({
levelId: initLevel?.id || '',
stepId: initLevel?.steps.length ? initLevel.steps[0].id : null,
complete: false,
})
}
async continuePosition(workspaceState: vscode.Memento, tutorial: TT.Tutorial): Promise<T.Position> {
this.setTutorial(workspaceState, tutorial)
let position: T.Position = (await this.storage?.get()) || defaultValue
return this.set(position)
}
public get = () => {
return this.value
}
public set = (value: CR.Position) => {
public set = (value: T.Position) => {
this.value = value
this.storage?.set(value)
return this.value
}
public reset = () => {
this.value = defaultValue
}
// calculate the current position based on the saved progress
public setPositionFromProgress = (tutorial: TT.Tutorial, progress: CR.Progress): CR.Position => {
// tutorial already completed
// TODO handle start again?
if (progress.complete) {
return this.value
}

if (!tutorial || !tutorial.levels) {
throw new Error('Error setting position from progress')
}

// get level
const { levels } = tutorial
const lastLevelIndex: number | undefined = levels.findIndex((l: TT.Level) => !progress.levels[l.id])
if (lastLevelIndex >= levels.length) {
throw new Error('Error setting progress level')
}

// get step
const currentLevel: TT.Level = levels[lastLevelIndex]
if (!currentLevel) {
// tutorial complete but not reached completed view
const finalLevel = levels[levels.length - 1]
return {
levelId: finalLevel.id,
stepId: finalLevel.steps.length ? finalLevel.steps[finalLevel.steps.length - 1].id : null,
complete: true,
}
}
let currentStepId: string | null
if (!currentLevel.steps.length) {
// no steps available for level
currentStepId = null
} else {
// find current step id
const { steps } = currentLevel
const lastStepIndex: number | undefined = steps.findIndex((s: TT.Step) => !progress.steps[s.id])
if (lastStepIndex >= steps.length) {
throw new Error('Error setting progress step')
}
// handle position when last step is complete but "continue" not yet selected
const adjustedLastStepIndex = lastStepIndex === -1 ? steps.length - 1 : lastStepIndex
currentStepId = steps[adjustedLastStepIndex].id
}

this.value = {
levelId: currentLevel.id,
stepId: currentStepId,
}

return this.value
return this.set(defaultValue)
}
}

Expand Down
70 changes: 0 additions & 70 deletions src/services/context/state/Progress.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/services/reset/lastHash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import getLastCommitHash from './lastHash'

describe('lastHash', () => {
it('should grab the last passing hash from a step', () => {
const position: T.Position = { levelId: '1', stepId: '1.2' }
const position: T.Position = { levelId: '1', stepId: '1.2', complete: false }
// @ts-ignore
const tutorial: TT.Tutorial = {
levels: [
Expand Down Expand Up @@ -32,7 +32,7 @@ describe('lastHash', () => {
expect(result).toBe('abcdef2')
})
it('should grab the last passing hash from a step with several commits', () => {
const position: T.Position = { levelId: '1', stepId: '1.2' }
const position: T.Position = { levelId: '1', stepId: '1.2', complete: false }
// @ts-ignore
const tutorial: TT.Tutorial = {
levels: [
Expand Down Expand Up @@ -60,7 +60,7 @@ describe('lastHash', () => {
expect(result).toBe('abcdef3')
})
it('should grab the last passing hash when level has no steps', () => {
const position: T.Position = { levelId: '1', stepId: null }
const position: T.Position = { levelId: '1', stepId: null, complete: false }
// @ts-ignore
const tutorial: TT.Tutorial = {
config: {
Expand Down
Loading