Expand Up @@ -49,49 +49,57 @@ class Channel implements Channel { switch ( actionType ) { case 'EDITOR_STARTUP' :// check if a workspace is open, otherwise nothing works const noActiveWorksapce = ! WORKSPACE_ROOT . length if ( noActiveWorksapce ) { const error :E . ErrorMessage = { type :'NoWorkspaceFound' , message :'' , actions :[ { label :'Open Workspace' , transition :'REQUEST_WORKSPACE' , } , ] , try { // check if a workspace is open, otherwise nothing works const noActiveWorksapce = ! WORKSPACE_ROOT . length if ( noActiveWorksapce ) { const error :E . ErrorMessage = { type :'NoWorkspaceFound' , message :'' , actions :[ { label :'Open Workspace' , transition :'REQUEST_WORKSPACE' , } , ] , } this . send ( { type :'NO_WORKSPACE' , payload :{ error} } ) return } this . send ( { type :'NO_WORKSPACE' , payload :{ error} } ) return } const env = { machineId :vscode . env . machineId , sessionId :vscode . env . sessionId , } const env = { machineId :vscode . env . machineId , sessionId :vscode . env . sessionId , } // continue from tutorial from local storage const tutorial :TT . Tutorial | null = this . context . tutorial . get ( ) // continue from tutorial from local storage const tutorial :TT . Tutorial | null = this . context . tutorial . get ( ) // new tutorial if ( ! tutorial || ! tutorial . id ) { this . send ( { type :'START_NEW_TUTORIAL' , payload :{ env} } ) return } // new tutorial if ( ! tutorial || ! tutorial . id ) { this . send ( { type :'START_NEW_TUTORIAL' , payload :{ env} } ) return } // set tutorial const { position, progress} = await this . context . setTutorial ( this . workspaceState , tutorial ) // set tutorial const { position, progress} = await this . context . setTutorial ( this . workspaceState , tutorial ) if ( progress . complete ) { // tutorial is already complete this . send ( { type :'TUTORIAL_ALREADY_COMPLETE' , payload :{ env} } ) return } // communicate to client the tutorial & stepProgress state this . send ( { type :'LOAD_STORED_TUTORIAL' , payload :{ env, tutorial, progress, position} } ) if ( progress . complete ) { // tutorial is already complete this . send ( { type :'TUTORIAL_ALREADY_COMPLETE' , payload :{ env} } ) return } catch ( e ) { const error = { type :'UnknownError' , message :`Location: Editor startup\n\n${ e . message } ` , } this . send ( { type :'EDITOR_STARTUP_FAILED' , payload :{ error} } ) } // communicate to client the tutorial & stepProgress state this . send ( { type :'LOAD_STORED_TUTORIAL' , payload :{ env, tutorial, progress, position} } ) return // clear tutorial local storage case 'TUTORIAL_CLEAR' :Expand All @@ -100,134 +108,159 @@ class Channel implements Channel { return // configure test runner, language, git case 'EDITOR_TUTORIAL_CONFIG' :const data :TT . Tutorial = action . payload . tutorial // setup tutorial config (save watcher, test runner, etc) await this . context . setTutorial ( this . workspaceState , data ) try { const data :TT . Tutorial = action . payload . tutorial // setup tutorial config (save watcher, test runner, etc) await this . context . setTutorial ( this . workspaceState , data ) // validate dependencies const dependencies = data . config . dependencies if ( dependencies && dependencies . length ) { for ( const dep of dependencies ) { // check dependency is installed const currentVersion :string | null = await version ( dep . name ) if ( ! currentVersion ) { // use a custom error message const error = { type :'MissingTutorialDependency' , message :dep . message || `Process "${ dep . name } " is required but not found. It may need to be installed` , actions :[ { label :'Check Again' , transition :'TRY_AGAIN' , } , ] , // validate dependencies const dependencies = data . config . dependencies if ( dependencies && dependencies . length ) { for ( const dep of dependencies ) { // check dependency is installed const currentVersion :string | null = await version ( dep . name ) if ( ! currentVersion ) { // use a custom error message const error = { type :'MissingTutorialDependency' , message :dep . message || `Process "${ dep . name } " is required but not found. It may need to be installed` , actions :[ { label :'Check Again' , transition :'TRY_AGAIN' , } , ] , } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } // check dependency version const satisfiedDependency = await compareVersions ( currentVersion , dep . version ) // check dependency version const satisfiedDependency = await compareVersions ( currentVersion , dep . version ) if ( ! satisfiedDependency ) { const error = { type :'UnmetTutorialDependency' , message :`Expected${ dep . name } to have version${ dep . version } , but found version${ currentVersion } ` , actions :[ { label :'Check Again' , transition :'TRY_AGAIN' , } , ] , if ( ! satisfiedDependency ) { const error = { type :'UnmetTutorialDependency' , message :`Expected${ dep . name } to have version${ dep . version } , but found version${ currentVersion } ` , actions :[ { label :'Check Again' , transition :'TRY_AGAIN' , } , ] , } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } if ( satisfiedDependency !== true ) { const error = satisfiedDependency || { type :'UnknownError' , message :`Something went wrong comparing dependency for${ name } ` , actions :[ { label :'Try Again' , transition :'TRY_AGAIN' , } , ] , if ( satisfiedDependency !== true ) { const error = satisfiedDependency || { type :'UnknownError' , message :`Something went wrong comparing dependency for${ name } ` , actions :[ { label :'Try Again' , transition :'TRY_AGAIN' , } , ] , } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } } } const error :E . ErrorMessage | void = await tutorialConfig ( { config :data . config } ) . catch ( ( error :Error ) => ( { type :'UnknownError' , message :`Location: tutorial config.\n\n${ error . message } ` , } ) ) const error :E . ErrorMessage | void = await tutorialConfig ( { config :data . config } ) . catch ( ( error :Error ) => ( { type :'UnknownError' , message :`Location: tutorial config.\n\n${ error . message } ` , } ) ) // has error if ( error && error . type ) { this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) // has error if ( error && error . type ) { this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) return } // report back to the webview that setup is complete this . send ( { type :'TUTORIAL_CONFIGURED' } ) return } catch ( e ) { const error = { type :'UnknownError' , message :`Location: EditorTutorialConfig.\n\n${ e . message } ` , } this . send ( { type :'TUTORIAL_CONFIGURE_FAIL' , payload :{ error} } ) } // report back to the webview that setup is complete this . send ( { type :'TUTORIAL_CONFIGURED' } ) return case 'EDITOR_TUTORIAL_CONTINUE_CONFIG' :const tutorialContinue :TT . Tutorial | null = this . context . tutorial . get ( ) if ( ! tutorialContinue ) { throw new Error ( 'Invalid tutorial to continue' ) try { const tutorialContinue :TT . Tutorial | null = this . context . tutorial . get ( ) if ( ! tutorialContinue ) { throw new Error ( 'Invalid tutorial to continue' ) } const continueConfig :TT . TutorialConfig = tutorialContinue . config await tutorialConfig ( { config :continueConfig , alreadyConfigured :true , } ) // update the current stepId on startup vscode . commands . executeCommand ( COMMANDS . SET_CURRENT_STEP , action . payload ) return } catch ( e ) { const error = { type :'UnknownError' , message :`Location: Editor tutorial continue config.\n\n${ e . message } ` , } this . send ( { type :'CONTINUE_FAILED' , payload :{ error} } ) } const continueConfig :TT . TutorialConfig = tutorialContinue . config await tutorialConfig ( { config :continueConfig , alreadyConfigured :true , } ) // update the current stepId on startup vscode . commands . executeCommand ( COMMANDS . SET_CURRENT_STEP , action . payload ) return case 'EDITOR_VALIDATE_SETUP' :// check workspace is selected const isEmptyWorkspace = await checkWorkspaceEmpty ( ) if ( ! isEmptyWorkspace ) { const error :E . ErrorMessage = { type :'WorkspaceNotEmpty' , message :'' , actions :[ { label :'Open Workspace' , transition :'REQUEST_WORKSPACE' , } , { label :'Check Again' , transition :'RETRY' , } , ] , try { // check workspace is selected const isEmptyWorkspace = await checkWorkspaceEmpty ( ) if ( ! isEmptyWorkspace ) { const error :E . ErrorMessage = { type :'WorkspaceNotEmpty' , message :'' , actions :[ { label :'Open Workspace' , transition :'REQUEST_WORKSPACE' , } , { label :'Check Again' , transition :'RETRY' , } , ] , } this . send ( { type :'VALIDATE_SETUP_FAILED' , payload :{ error} } ) return } this . send ( { type :'VALIDATE_SETUP_FAILED' , payload :{ error} } ) // check Git is installed. // Should wait for workspace before running otherwise requires access to root folder const isGitInstalled = await version ( 'git' ) if ( ! isGitInstalled ) { const error :E . ErrorMessage = { type :'GitNotFound' , message :'' , actions :[ { label :'Check Again' , transition :'RETRY' , } , ] , } this . send ( { type :'VALIDATE_SETUP_FAILED' , payload :{ error} } ) return } this . send ( { type :'SETUP_VALIDATED' } ) return } // check Git is installed. // Should wait for workspace before running otherwise requires access to root folder const isGitInstalled = await version ( 'git' ) if ( ! isGitInstalled ) { const error :E . ErrorMessage = { type :'GitNotFound' , message :'' , actions :[ { label :'Check Again' , transition :'RETRY' , } , ] , } catch ( e ) { const error = { type :'UknownError' , message :e . message , } this . send ( { type :'VALIDATE_SETUP_FAILED' , payload :{ error} } ) return } this . send ( { type :'SETUP_VALIDATED' } ) return case 'EDITOR_REQUEST_WORKSPACE' :openWorkspace ( ) return Expand Down