From bd2ca64f9cc793a24aa2a6aac19837a40a84ea56 Mon Sep 17 00:00:00 2001 From: ysandler Date: Sat, 12 Sep 2020 17:14:51 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20feat:=20create=20starter=20file?= =?UTF-8?q?=20for=20lesson?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/.brightScreen/brightScreen.json | 24 ---------- demo/.brightScreen/lessonOne/indexTest.js | 23 ---------- demo/.brightScreen/lessonTwo/indexTest.js | 18 -------- demo/.brightScreen/runningTest.js | 25 ----------- demo/userTestOne.js | 3 -- package-lock.json | 13 ++++++ package.json | 55 +++++++++++++++++++++-- src/Interfaces/LessonInterface.ts | 1 + src/UseCases/CourseProvider.ts | 44 ++++++++++++++++++ src/UseCases/LessonsProvider.ts | 6 ++- src/UseCases/installCourse.ts | 29 ++++++++++++ src/UseCases/setupCoursesTree.ts | 28 ++++++++++++ src/extension.ts | 46 ++++++++++++++++++- src/media/createIcon.svg | 1 + src/media/downloadIcon.svg | 1 + src/media/searchIcon.svg | 1 + 16 files changed, 218 insertions(+), 100 deletions(-) delete mode 100644 demo/.brightScreen/brightScreen.json delete mode 100644 demo/.brightScreen/lessonOne/indexTest.js delete mode 100644 demo/.brightScreen/lessonTwo/indexTest.js delete mode 100644 demo/.brightScreen/runningTest.js create mode 100644 src/UseCases/CourseProvider.ts create mode 100644 src/UseCases/installCourse.ts create mode 100644 src/UseCases/setupCoursesTree.ts create mode 100644 src/media/createIcon.svg create mode 100644 src/media/downloadIcon.svg create mode 100644 src/media/searchIcon.svg diff --git a/demo/.brightScreen/brightScreen.json b/demo/.brightScreen/brightScreen.json deleted file mode 100644 index 1f43274..0000000 --- a/demo/.brightScreen/brightScreen.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "courseName": "Test Lesson", - "documentationUrl": "https://brightScreen.io/courses/Test-Lesson/", - "lessons": [ - { - "name": "Lesson One", - "location": "lessonOne/indexTest.js", - "description": "Test Description for Lesson 1", - "executionPrefix": "node", - "fileExtention": "js", - "replacementSubstring": "USER_CODE", - "documentationUrl": "https://brightScreen.io/courses/Test-Lesson/lesson-One/" - }, - { - "name": "Lesson Two", - "location": "lessonTwo/indexTest.js", - "description": "Test Description for Lesson 2", - "executionPrefix": "node", - "fileExtention": "js", - "replacementSubstring": "USER_CODE", - "documentationUrl": "https://brightScreen.io/courses/Test-Lesson/lesson-Two/" - } - ] -} \ No newline at end of file diff --git a/demo/.brightScreen/lessonOne/indexTest.js b/demo/.brightScreen/lessonOne/indexTest.js deleted file mode 100644 index 3dbf173..0000000 --- a/demo/.brightScreen/lessonOne/indexTest.js +++ /dev/null @@ -1,23 +0,0 @@ -const codeFromUser = USER_CODE - -const test = () => { - const input = 'yo' - const expectedOutput = 'yo' - const testedValue = codeFromUser(input) - - if (testedValue === expectedOutput) { - const message = { - didPass: true, - message: 'Passed Test 1' - } - console.log(JSON.stringify(message)) - } else { - const message = { - didPass: false, - message: 'Did not return expected value' - } - console.log(JSON.stringify(message)) - } -} - -test() \ No newline at end of file diff --git a/demo/.brightScreen/lessonTwo/indexTest.js b/demo/.brightScreen/lessonTwo/indexTest.js deleted file mode 100644 index 69f168d..0000000 --- a/demo/.brightScreen/lessonTwo/indexTest.js +++ /dev/null @@ -1,18 +0,0 @@ -const codeFromUser = USER_CODE || function() { console.log('No User code Provided') } - - -const test = () => { - const input = 'yo' - const expectedOutput = 'yo' - const testedValue = codeFromUser(input) - - if (testedValue === expectedOutput) { - console.log('Passed Test 2') - return true - } else { - console.log('Failed Test Two') - return false - } -} - -test() \ No newline at end of file diff --git a/demo/.brightScreen/runningTest.js b/demo/.brightScreen/runningTest.js deleted file mode 100644 index a95d377..0000000 --- a/demo/.brightScreen/runningTest.js +++ /dev/null @@ -1,25 +0,0 @@ -const codeFromUser = function (props) { - return props -} - -const test = () => { - const input = 'yo' - const expectedOutput = 'yo' - const testedValue = codeFromUser(input) - - if (testedValue === expectedOutput) { - const message = { - didPass: true, - message: 'Passed Test 1' - } - console.log(JSON.stringify(message)) - } else { - const message = { - didPass: false, - message: 'Did not return expected value' - } - console.log(JSON.stringify(message)) - } -} - -test() \ No newline at end of file diff --git a/demo/userTestOne.js b/demo/userTestOne.js index c5de357..e69de29 100644 --- a/demo/userTestOne.js +++ b/demo/userTestOne.js @@ -1,3 +0,0 @@ -function (props) { - return props -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6ebf245..eaf5bad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -275,6 +275,14 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "axios": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -789,6 +797,11 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", diff --git a/package.json b/package.json index 5deedb9..19ce493 100644 --- a/package.json +++ b/package.json @@ -30,37 +30,83 @@ "name": "brightScreen", "icon": "src/media/logoBlue.svg", "contextualTitle": "brightScreen" + }, + { + "id": "brightScreenCourses", + "name": "brightScreen Courses", + "contextualTitle": "courses" } ] }, "commands": [ { "command": "brightscreen.startBrightScreen", - "title": "Start Bright Screen", + "title": "BrightScreen: Start BrightScreen", "icon": { "light": "src/media/logoBlue.svg", "dark": "src/media/logoBlue.svg" } }, + { + "command": "brightscreen.searchForCourses", + "title": "BrightScreen: Search For Courses", + "icon": { + "light": "src/media/searchIcon.svg", + "dark": "src/media/searchIcon.svg" + } + }, { "command": "brightscreen.runTests", - "title": "Run Tests", + "title": "BrightScreen: Run Tests", "icon": { "light": "src/media/runCommand.svg", "dark": "src/media/runCommand.svg" } + }, + { + "command": "brightscreen.createStarterFileForLesson", + "title": "BrightScreen: Create Start File For Lesson", + "icon": { + "light": "src/media/createIcon.svg", + "dark": "src/media/createIcon.svg" + } + }, + { + "command": "brightscreen.downloadCourse", + "title": "BrightScreen: Download Course", + "icon": { + "light": "src/media/downloadIcon.svg", + "dark": "src/media/downloadIcon.svg" + } } ], "menus": { "view/title": [ { "command": "brightscreen.startBrightScreen", + "when": "view == brightScreen", + "group": "navigation" + }, + { + "command": "brightscreen.searchForCourses", + "when": "view == brightScreenCourses", "group": "navigation" } ], "view/item/context": [ { "command": "brightscreen.runTests", + "when": "view == brightScreen", + "group": "inline" + }, + { + "command": "brightscreen.createStarterFileForLesson", + "when": "view == brightScreen", + "group": "inline" + }, + { + "command": "brightscreen.downloadCourse", + "when": "view == brightScreenCourses", "group": "inline" } ] @@ -68,7 +114,7 @@ "viewsWelcome": [ { "view": "brightScreen", - "contents": "No Course Selected\n[Find Them Here](https://brightScreen.io/)" + "contents": "Start brightScreen or Search for Courses\n[Documentation](https://brightScreen.io/)" } ] }, @@ -92,5 +138,8 @@ "mocha": "^8.0.1", "typescript": "^3.8.3", "vscode-test": "^1.4.0" + }, + "dependencies": { + "axios": "^0.20.0" } } diff --git a/src/Interfaces/LessonInterface.ts b/src/Interfaces/LessonInterface.ts index 30681c2..2b2423b 100644 --- a/src/Interfaces/LessonInterface.ts +++ b/src/Interfaces/LessonInterface.ts @@ -5,6 +5,7 @@ interface LessonInterface { executionPrefix: string, fileExtention: string, replacementSubstring: string, + starterFileLocation: string, documentationUrl: string } diff --git a/src/UseCases/CourseProvider.ts b/src/UseCases/CourseProvider.ts new file mode 100644 index 0000000..a0ce239 --- /dev/null +++ b/src/UseCases/CourseProvider.ts @@ -0,0 +1,44 @@ +import * as vscode from 'vscode' + +class CourseProvider implements vscode.TreeDataProvider { + courses: {_id: string, name:string, repo: string}[] + constructor(courses: {_id: string, name:string, repo: string}[] ) { + this.courses = courses + } + + getTreeItem (element: CourseTreeItem): vscode.TreeItem { + return element + } + + getChildren (): CourseTreeItem[] { + const treeItems: CourseTreeItem[] = this.courses.map(c => { + return new CourseTreeItem( + c.name, + vscode.TreeItemCollapsibleState.None, + c.repo, + ) + }) + return treeItems || [] + } + } + +class CourseTreeItem extends vscode.TreeItem { + constructor ( + public readonly label: string, + public readonly collapsibleState: vscode.TreeItemCollapsibleState, + public readonly repo: string, + ) { + super(label, collapsibleState) + } + + get tooltip (): string { + return this.repo + } + + iconPath = { + light: `../media/downloadIcon.svg`, + dark: '../media/downloadIcon.svg' + } +} + +export default CourseProvider diff --git a/src/UseCases/LessonsProvider.ts b/src/UseCases/LessonsProvider.ts index acd9b36..b5a9e6c 100644 --- a/src/UseCases/LessonsProvider.ts +++ b/src/UseCases/LessonsProvider.ts @@ -19,7 +19,8 @@ class LessonsProvider implements vscode.TreeDataProvider { l.executionPrefix, l.fileExtention, l.replacementSubstring, - l.location + l.location, + l.starterFileLocation ) }) return treeItems @@ -34,7 +35,8 @@ class LessonTreeItem extends vscode.TreeItem { public readonly executionPrefix: string, public readonly fileExtention: string, public readonly replacementSubstring: string, - public readonly location: string + public readonly location: string, + public readonly starterFileLocation: string ) { super(label, collapsibleState) } diff --git a/src/UseCases/installCourse.ts b/src/UseCases/installCourse.ts new file mode 100644 index 0000000..6cd03f6 --- /dev/null +++ b/src/UseCases/installCourse.ts @@ -0,0 +1,29 @@ +import * as vscode from 'vscode' +import { exec } from 'child_process' + +function installCourse (workspaceFolder: string, repo: string, outputChannel: vscode.OutputChannel): void { + const executionString = `git clone ${repo} ${workspaceFolder}/.brightScreen` + outputChannel.show() + const gitInstallProcess = exec(executionString, (error, stdout, stderr) => { + if (stderr) { + console.log('stderr: ', stderr) + outputChannel.appendLine(stderr) + return + } + + if (error !== null) { + console.log('stderr: ', error) + outputChannel.appendLine('error') + return + } + + outputChannel.append(stdout) + }) + + gitInstallProcess.on('close', () => { + console.log('Git Clone Process Closed') + vscode.window.showInformationMessage('Course successfully installed ot .brightScreen') + }) +} + +export default installCourse \ No newline at end of file diff --git a/src/UseCases/setupCoursesTree.ts b/src/UseCases/setupCoursesTree.ts new file mode 100644 index 0000000..1f99116 --- /dev/null +++ b/src/UseCases/setupCoursesTree.ts @@ -0,0 +1,28 @@ +import * as vscode from 'vscode' +import axios from 'axios' +import CourseProvider from './CourseProvider' + +function setupCoursesTree (): void { + let courses: any + try { + axios.get('http://localhost:5000/api/courses') + .then(response => { + console.log(response.data) + courses = response.data + + try { + vscode.window.registerTreeDataProvider('brightScreenCourses', new CourseProvider(courses)) + } catch (err) { + console.log(err) + vscode.window.showErrorMessage('Could Not Create BrightScreen Course List') + return + } + }) + } catch (err) { + console.log(err) + vscode.window.showErrorMessage('Could Not Access BrightScreen Course List') + return + } +} + +export default setupCoursesTree diff --git a/src/extension.ts b/src/extension.ts index 6c3b662..f2f11da 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,17 +2,21 @@ import * as vscode from 'vscode' import * as fs from 'fs' import BrightScreen from './Entities/BrightScreen' import setupBrightScreen from './UseCases/setupBrightScreen' +import setupCoursesTree from './UseCases/setupCoursesTree' import LessonInterface from './Interfaces/LessonInterface' import { exec } from 'child_process' +import installCourse from './UseCases/installCourse' export function activate(context: vscode.ExtensionContext) { console.log('brightscreen is now active') let brightScreen: BrightScreen - let workspaceFolder: string + let workspaceFolder: string = vscode.workspace.rootPath || '' let lessons: LessonInterface[] const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('brightScreen') + setupCoursesTree() + const startupBrightScreenCommand = vscode.commands.registerCommand('brightscreen.startBrightScreen', () => { setupBrightScreen() brightScreen = BrightScreen.getInstance() @@ -20,6 +24,44 @@ export function activate(context: vscode.ExtensionContext) { lessons = brightScreen.lessons }) + const searchForCoursesComand = vscode.commands.registerCommand('brightscreen.searchForCourses', async () => { + // console.log(await vscode.window.showInputBox()) + setupCoursesTree() + }) + + const downloadCourseComand = vscode.commands.registerCommand('brightscreen.downloadCourse', async (treeItemContext) => { + console.log(treeItemContext) + const repo = treeItemContext.repo + // console.log(await vscode.window.showInputBox()) + if (brightScreen) { + vscode.window.showErrorMessage('brightScreen Course is already installed') + return + } + installCourse(workspaceFolder, repo, outputChannel) + // setupBrightScreen() + }) + + const createStarterFileForLesson = vscode.commands.registerCommand('brightscreen.createStarterFileForLesson', treeItemContext => { + let starterFileAsString :string + try{ + starterFileAsString = fs.readFileSync(`${workspaceFolder}/.brightScreen/${treeItemContext.starterFileLocation}`, 'utf-8') + } catch (err) { + console.log(err) + vscode.window.showErrorMessage('Issue reading starter file provided by course.') + return + } + try { + vscode.window.activeTextEditor?.edit(builder => { + builder.insert(new vscode.Position(0, 0), starterFileAsString) + // builder.replace(vscode.window?.activeTextEditor.selection, starterFileAsString); + }) + } catch (err) { + console.log(err) + vscode.window.showErrorMessage('Coule Not create starter file for the lesson.') + return + } + }) + const runTestCommand = vscode.commands.registerCommand('brightscreen.runTests', (treeItemContext) => { let lessonCodeAsString: string try { @@ -96,7 +138,7 @@ export function activate(context: vscode.ExtensionContext) { }) }) - context.subscriptions.push(...[runTestCommand, startupBrightScreenCommand]) + context.subscriptions.push(...[runTestCommand, startupBrightScreenCommand, searchForCoursesComand, downloadCourseComand]) } export function deactivate() {} diff --git a/src/media/createIcon.svg b/src/media/createIcon.svg new file mode 100644 index 0000000..08a11d1 --- /dev/null +++ b/src/media/createIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/media/downloadIcon.svg b/src/media/downloadIcon.svg new file mode 100644 index 0000000..b4519b2 --- /dev/null +++ b/src/media/downloadIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/media/searchIcon.svg b/src/media/searchIcon.svg new file mode 100644 index 0000000..4fa6ff5 --- /dev/null +++ b/src/media/searchIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file