8000 Merge pull request #414 from coderoad/feature/remove-progress · ShaunSHamilton/coderoad-vscode@bca6384 · GitHub
[go: up one dir, main page]

Skip to content

Commit bca6384

Browse files
authored
Merge pull request coderoad#414 from coderoad/feature/remove-progress
Feature/remove progress
2 parents 4c8eb65 + 3cffd7f commit bca6384

File tree

36 files changed

+563
-608
lines changed
  • 36 files changed

    +563
    -608
    lines changed

    CHANGELOG.md

    Lines changed: 5 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -236,3 +236,8 @@ Adds a review page for viewing tutorial content. The review page should be espec
    236236
    - Launch from URL fixes
    237237
    - Move styles into a central theme
    238238
    - Prevent multiple versions of CodeRoad from launching
    239+
    240+
    ### [0.13.0]
    241+
    242+
    - Significant internal refactor to remove recording progress
    243+
    - Admin mode to allow creators to jump between tutorial levels/steps during development

    src/actions/index.ts

    Lines changed: 2 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,6 +1,6 @@
    11
    export { default as onStartup } from './onStartup'
    2-
    export { default as onTutorialConfig } from './onTutorialConfig'
    3-
    export { default as onTutorialContinueConfig } from './onTutorialContinueConfig'
    2+
    export { default as onTutorialConfigNew } from './onTutorialConfigNew'
    3+
    export { default as onTutorialConfigContinue } from './onTutorialConfigContinue'
    44
    export { default as onValidateSetup } from './onValidateSetup'
    55
    export { default as onRunReset } from './onRunReset'
    66
    export { default as onErrorPage } from './onErrorPage'

    src/actions/onStartup.ts

    Lines changed: 8 additions & 14 deletions
    Original file line numberDiff line numberDiff line change
    @@ -41,32 +41,26 @@ const onStartup = async (
    4141
    // no stored tutorial, must start new tutorial
    4242
    if (!tutorial || !tutorial.id) {
    4343
    if (TUTORIAL_URL) {
    44-
    // launch from a url env variable
    44+
    // NEW_FROM_URL
    4545
    try {
    4646
    const tutorialRes = await fetch(TUTORIAL_URL)
    4747
    const tutorial = await tutorialRes.json()
    4848
    send({ type: 'START_TUTORIAL_FROM_URL', payload: { tutorial } })
    49+
    return
    4950
    } catch (e) {
    51+
    // on failure to load a tutorial url fallback to NEW
    5052
    console.log(`Failed to load tutorial from url ${TUTORIAL_URL} with error "${e.message}"`)
    5153
    }
    52-
    } else {
    53-
    // launch from a selected tutorial
    54-
    send({ type: 'START_NEW_TUTORIAL', payload: { env } })
    5554
    }
    55+
    // NEW
    56+
    send({ type: 'START_NEW_TUTORIAL', payload: { env } })
    5657
    return
    5758
    }
    5859

    59-
    // load continued tutorial position & progress
    60-
    const { position, progress } = await context.setTutorial(workspaceState, tutorial)
    61-
    logger('CONTINUE STATE', position, progress)
    62-
    63-
    if (progress.complete) {
    64-
    // tutorial is already complete
    65-
    send({ type: 'TUTORIAL_ALREADY_COMPLETE', payload: { env } })
    66-
    return
    67-
    }
    60+
    // CONTINUE_FROM_PROGRESS
    61+
    const { position } = await context.onContinue(tutorial)
    6862
    // communicate to client the tutorial & stepProgress state
    69-
    send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, progress, position } })
    63+
    send({ type: 'LOAD_STORED_TUTORIAL', payload: { env, tutorial, position } })
    7064
    } catch (e) {
    7165
    const error = {
    7266
    type: 'UnknownError',

    src/actions/onTest.ts

    Lines changed: 1 addition & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,13 +5,7 @@ import { COMMANDS } from '../commands'
    55
    import Context from '../services/context/context'
    66

    77
    export const onTestPass = (action: T.Action, context: Context) => {
    8-
    const tutorial = context.tutorial.get()
    9-
    if (!tutorial) {
    10-
    throw new Error('Error with current tutorial. Tutorial may be missing an id.')
    11-
    }
    12-
    // update local storage stepProgress
    13-
    const progress = context.progress.setStepComplete(tutorial, action.payload.position.stepId)
    14-
    context.position.setPositionFromProgress(tutorial, progress)
    8+
    context.position.set({ ...action.payload.position, complete: true })
    159
    git.saveCommit('Save progress')
    1610
    }
    1711

    src/actions/onTutorialContinueConfig.ts renamed to src/actions/onTutorialConfigContinue.ts

    Lines changed: 2 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,7 +5,7 @@ import Context from '../services/context/context'
    55
    import tutorialConfig from './utils/tutorialConfig'
    66
    import { COMMANDS } from '../commands'
    77

    8-
    const onTutorialContinueConfig = async (action: T.Action, context: Context, send: any) => {
    8+
    const onTutorialConfigContinue = async (action: T.Action, context: Context, send: any) => {
    99
    try {
    1010
    const tutorialContinue: TT.Tutorial | null = context.tutorial.get()
    1111
    if (!tutorialContinue) {
    @@ -26,4 +26,4 @@ const onTutorialContinueConfig = async (action: T.Action, context: Context, send
    2626
    }
    2727
    }
    2828

    29-
    export default onTutorialContinueConfig
    29+
    export default onTutorialConfigContinue

    src/actions/onTutorialConfig.ts renamed to src/actions/onTutorialConfigNew.ts

    Lines changed: 3 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -8,7 +8,7 @@ import { version, compareVersions } from '../services/dependencies'
    88
    import Context from '../services/context/context'
    99
    import tutorialConfig from './utils/tutorialConfig'
    1010

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

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

    3939
    // setup tutorial config (save watcher, test runner, etc)
    40-
    await context.setTutorial(workspaceState, data)
    40+
    await context.onNew(data)
    4141

    4242
    // validate dependencies
    4343
    const dependencies = data.config.dependencies
    @@ -118,4 +118,4 @@ const onTutorialConfig = async (action: T.Action, context: Context, workspaceSta
    118118
    }
    119119
    }
    120120

    121-
    export default onTutorialConfig
    121+
    export default onTutorialConfigNew

    src/channel.ts

    Lines changed: 4 additions & 8 deletions
    Original file line numberDiff line numberDiff line change
    @@ -40,16 +40,12 @@ class Channel implements Channel {
    4040
    actions.onStartup(this.context, this.workspaceState, this.send)
    4141
    return
    4242
    // clear tutorial local storage
    43-
    case 'TUTORIAL_CLEAR':
    44-
    // clear current progress/position/tutorial
    45-
    this.context.reset()
    46-
    return
    4743
    // configure test runner, language, git
    4844
    case 'EDITOR_TUTORIAL_CONFIG':
    49-
    actions.onTutorialConfig(action, this.context, this.workspaceState, this.send)
    45+
    actions.onTutorialConfigNew(action, this.context, this.send)
    5046
    return
    5147
    case 'EDITOR_TUTORIAL_CONTINUE_CONFIG':
    52-
    actions.onTutorialContinueConfig(action, this.context, this.send)
    48+
    actions.onTutorialConfigContinue(action, this.context, this.send)
    5349
    return
    5450
    case 'EDITOR_VALIDATE_SETUP':
    5551
    actions.onValidateSetup(this.send)
    @@ -69,9 +65,9 @@ class Channel implements Channel {
    6965
    // run test following solution to update position
    7066
    actions.onRunTest< 10000 span class=pl-kos>()
    7167
    return
    72-
    case 'EDITOR_SYNC_PROGRESS':
    68+
    case 'EDITOR_SYNC_POSITION':
    7369
    // update progress when a level is deemed complete in the client
    74-
    await this.context.progress.syncProgress(action.payload.progress)
    70+
    await this.context.position.set(action.payload.position)
    7571
    return
    7672
    case 'EDITOR_OPEN_LOGS':
    7773
    actions.onOpenLogs(action)

    src/commands.ts

    Lines changed: 1 addition & 8 deletions
    Original file line numberDiff line numberDiff line change
    @@ -54,7 +54,7 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP
    5454
    onSuccess: (position: T.Position) => {
    5555
    logger('test pass position', position)
    5656
    // send test pass message back to client
    57-
    webview.send({ type: 'TEST_PASS', payload: { position } })
    57+
    webview.send({ type: 'TEST_PASS', payload: { position: { ...position, complete: true } } })
    5858
    },
    5959
    onFail: (position: T.Position, failSummary: T.TestFail): void => {
    6060
    // send test fail message back to client with failure message
    @@ -82,13 +82,6 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP
    8282
    subtasks,
    8383
    callbacks,
    8484
    }: { subtasks?: boolean; callbacks?: { onSuccess: () => void } } = {}) => {
    85-
    logger('run test current', currentPosition)
    86-
    // use stepId from client, or last set stepId
    87-
    // const position: T.Position = {
    88-
    // ...current,
    89-
    // stepId: current && current.position.stepId?.length ? current.position.stepId : currentPosition.stepId,
    90-
    // }
    91-
    logger('currentPosition', currentPosition)
    9285
    testRunner({ position: currentPosition, onSuccess: callbacks?.onSuccess, subtasks })
    9386
    },
    9487
    [COMMANDS.ENTER]: () => {

    src/services/context/context.ts

    Lines changed: 9 additions & 15 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,33 +1,27 @@
    1-
    import * as CR from 'typings'
    1+
    import * as T from 'typings'
    22
    import * as TT from 'typings/tutorial'
    33
    import * as vscode from 'vscode'
    44
    import Position from './state/Position'
    5-
    import Progress from './state/Progress'
    65
    import Tutorial from './state/Tutorial'
    76

    87
    class Context {
    98
    public tutorial: Tutorial
    109
    public position: Position
    11-
    public progress: Progress
    10+
    private workspaceState: vscode.Memento
    1211
    constructor(workspaceState: vscode.Memento) {
    1312
    // state held in one place
    13+
    this.workspaceState = workspaceState
    1414
    this.tutorial = new Tutorial(workspaceState)
    1515
    this.position = new Position()
    16-
    this.progress = new Progress()
    1716
    }
    18-
    public setTutorial = async (
    19-
    workspaceState: vscode.Memento,
    20-
    tutorial: TT.Tutorial,
    21-
    ): Promise<{ progress: CR.Progress; position: CR.Position }> => {
    17+
    public onNew = async (tutorial: TT.Tutorial): Promise<{ position: T.Position }> => {
    2218
    this.tutorial.set(tutorial)
    23-
    const progress: CR.Progress = await this.progress.setTutorial(workspaceState, tutorial)
    24-
    const position: CR.Position = this.position.setPositionFromProgress(tutorial, progress)
    25-
    return { progress, position }
    19+
    const position: T.Position = await this.position.initPosition(this.workspaceState, tutorial)
    20+
    return { position }
    2621
    }
    27-
    public reset = (): void => {
    28-
    this.tutorial.reset()
    29-
    this.progress.reset()
    30-
    this.position.reset()
    22+
    public onContinue = async (tutorial: TT.Tutorial): Promise<{ position: T.Position }> => {
    23+
    const position: T.Position = await this.position.continuePosition(this.workspaceState, tutorial)
    24+
    return { position }
    3125
    }
    3226
    }
    3327

    src/services/context/state/Position.ts

    Lines changed: 34 additions & 58 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,78 +1,54 @@
    1-
    import * as CR from 'typings'
    1+
    import * as vscode from 'vscode'
    2+
    import * as T from 'typings'
    23
    import * as TT from 'typings/tutorial'
    4+
    import Storage from '../../storage'
    35

    4-
    const defaultValue: CR.Position = {
    6+
    const defaultValue: T.Position = {
    57
    levelId: '',
    68
    stepId: null,
    9+
    complete: false,
    710
    }
    811

    912
    // position
    1013
    class Position {
    11-
    private value: CR.Position
    14+
    private value: T.Position
    15+
    private storage: Storage<T.Position> | undefined
    1216
    constructor() {
    1317
    this.value = defaultValue
    1418
    }
    19+
    setTutorial(workspaceState: vscode.Memento, tutorial: TT.Tutorial) {
    20+
    this.storage = new Storage<T.Position>({
    21+
    key: `coderoad:position:${tutorial.id}:${tutorial.version}`,
    22+
    storage: workspaceState,
    23+
    defaultValue,
    24+
    })
    25+
    }
    26+
    async initPosition(workspaceState: vscode.Memento, tutorial: TT.Tutorial): Promise<T.Position> {
    27+
    // set value from storage
    28+
    this.setTutorial(workspaceState, tutorial)
    29+
    // find first level & step id
    30+
    let initLevel = tutorial.levels.length ? tutorial.levels[0] : null
    31+
    return this.set({
    32+
    levelId: initLevel?.id || '',
    33+
    stepId: initLevel?.steps.length ? initLevel.steps[0].id : null,
    34+
    complete: false,
    35+
    })
    36+
    }
    37+
    async continuePosition(workspaceState: vscode.Memento, tutorial: TT.Tutorial): Promise<T.Position> {
    38+
    this.setTutorial(workspaceState, tutorial)
    39+
    let position: T.Position = (await this.storage?.get()) || defaultValue
    40+
    return this.set(position)
    41+
    }
    1542
    public get = () => {
    1643
    return this.value
    1744
    }
    18-
    public set = (value: CR.Position) => {
    45+
    public set = (value: T.Position) => {
    1946
    this.value = value
    47+
    this.storage?.set(value)
    48+
    return this.value
    2049
    }
    2150
    public reset = () => {
    22-
    this.value = defaultValue
    23-
    }
    24-
    // calculate the current position based on the saved progress
    25-
    public setPositionFromProgress = (tutorial: TT.Tutorial, progress: CR.Progress): CR.Position => {
    26-
    // tutorial already completed
    27-
    // TODO handle start again?
    28-
    if (progress.complete) {
    29-
    return this.value
    30-
    }
    31-
    32-
    if (!tutorial || !tutorial.levels) {
    33-
    throw new Error('Error setting position from progress')
    34-
    }
    35-
    36-
    // get level
    37-
    const { levels } = tutorial
    38-
    const lastLevelIndex: number | undefined = levels.findIndex((l: TT.Level) => !progress.levels[l.id])
    39-
    if (lastLevelIndex >= levels.length) {
    40-
    throw new Error('Error setting progress level')
    41-
    }
    42-
    43-
    // get step
    44-
    const currentLevel: TT.Level = levels[lastLevelIndex]
    45-
    if (!currentLevel) {
    46-
    // tutorial complete but not reached completed view
    47-
    const finalLevel = levels[levels.length - 1]
    48-
    return {
    49-
    levelId: finalLevel.id,
    50-
    stepId: finalLevel.steps.length ? finalLevel.steps[finalLevel.steps.length - 1].id : null,
    51-
    complete: true,
    52-
    }
    53-
    }
    54-
    let currentStepId: string | null
    55-
    if (!currentLevel.steps.length) {
    56-
    // no steps available for level
    57-
    currentStepId = null
    58-
    } else {
    59-
    // find current step id
    60-
    const { steps } = currentLevel
    61-
    const lastStepIndex: number | undefined = steps.findIndex((s: TT.Step) => !progress.steps[s.id])
    62-
    if (lastStepIndex >= steps.length) {
    63-
    throw new Error('Error setting progress step')
    64-
    }
    65-
    // handle position when last step is complete but "continue" not yet selected
    66-
    const adjustedLastStepIndex = lastStepIndex === -1 ? steps.length - 1 : lastStepIndex
    67-
    currentStepId = steps[adjustedLastStepIndex].id
    68-
    }
    69-
    70-
    this.value = {
    71-
    levelId: currentLevel.id,
    72-
    stepId: currentStepId,
    73-
    }
    74-
    75-
    return this.value
    51+
    return this.set(defaultValue)
    7652
    }
    7753
    }
    7854

    src/services/context/state/Progress.ts

    Lines changed: 0 additions & 70 deletions
    This file was deleted.

    0 commit comments

    Comments
     (0)
    0