From e0185840ccbe020f46e332ad4c1c44e591be586c Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 23 Nov 2019 16:05:18 -0800 Subject: [PATCH 1/5] track git config errors --- src/actions/tutorialConfig.ts | 19 +- src/channel/index.ts | 28 ++- src/services/git/index.ts | 4 +- .../containers/Tutorial/LevelPage/Level.tsx | 216 +++++++++--------- .../containers/Tutorial/LevelPage/index.tsx | 84 +++---- web-app/src/services/state/machine.ts | 11 +- 6 files changed, 192 insertions(+), 170 deletions(-) diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts index 8ffc0827..d1fbe181 100644 --- a/src/actions/tutorialConfig.ts +++ b/src/actions/tutorialConfig.ts @@ -1,3 +1,4 @@ +import * as T from 'typings' import * as G from 'typings/graphql' import * as vscode from 'vscode' import * as git from '../services/git' @@ -10,13 +11,25 @@ interface TutorialConfigParams { onComplete?(): void } -const tutorialConfig = async ({ config, alreadyConfigured }: TutorialConfigParams) => { +const tutorialConfig = async ( + { config, alreadyConfigured }: TutorialConfigParams, + onError: (msg: T.ErrorMessage) => void, +) => { if (!alreadyConfigured) { // setup git, add remote - await git.initIfNotExists() + await git.initIfNotExists().catch(error => { + // failed to setup git + onError({ + title: error.message, + description: + 'Be sure you install Git. See the docs for help https://git-scm.com/book/en/v2/Getting-Started-Installing-Git', + }) + }) // TODO: if remote not already set - await git.setupRemote(config.repo.uri) + await git.setupRemote(config.repo.uri).catch(error => { + onError({ title: error.message, description: 'Remove your current Git project and restarting' }) + }) } vscode.commands.executeCommand(COMMANDS.CONFIG_TEST_RUNNER, config.testRunner) diff --git a/src/channel/index.ts b/src/channel/index.ts index 33ee9570..219349eb 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -1,4 +1,4 @@ -import * as CR from 'typings' +import * as T from 'typings' import * as G from 'typings/graphql' import * as vscode from 'vscode' @@ -10,18 +10,18 @@ import saveCommit from '../actions/saveCommit' import { COMMANDS } from '../editor/commands' interface Channel { - receive(action: CR.Action): Promise - send(action: CR.Action): Promise + receive(action: T.Action): Promise + send(action: T.Action): Promise } interface ChannelProps { - postMessage: (action: CR.Action) => Thenable + postMessage: (action: T.Action) => Thenable workspaceState: vscode.Memento workspaceRoot: vscode.WorkspaceFolder } class Channel implements Channel { - private postMessage: (action: CR.Action) => Thenable + private postMessage: (action: T.Action) => Thenable private workspaceState: vscode.Memento private workspaceRoot: vscode.WorkspaceFolder private context: Context @@ -34,9 +34,10 @@ class Channel implements Channel { } // receive from webview - public receive = async (action: CR.Action) => { + public receive = async (action: T.Action) => { // action may be an object.type or plain string const actionType: string = typeof action === 'string' ? action : action.type + const onError = (error: T.ErrorMessage) => this.send({ type: 'ERROR', payload: { error } }) // console.log('EDITOR RECEIVED:', actionType) switch (actionType) { @@ -87,7 +88,7 @@ class Channel implements Channel { const data: G.TutorialData = tutorialData.version.data - await tutorialConfig({ config: data.config }) + await tutorialConfig({ config: data.config }, onError) // run init setup actions if (data.init) { @@ -106,10 +107,13 @@ class Channel implements Channel { throw new Error('Invalid tutorial to continue') } const continueConfig: G.TutorialConfig = tutorialContinue.version.data.config - tutorialConfig({ - config: continueConfig, - alreadyConfigured: true, - }) + tutorialConfig( + { + config: continueConfig, + alreadyConfigured: true, + }, + onError, + ) return case 'EDITOR_SYNC_PROGRESS': // sync client progress on server @@ -134,7 +138,7 @@ class Channel implements Channel { } } // send to webview - public send = async (action: CR.Action) => { + public send = async (action: T.Action) => { console.log(`EDITOR SEND ${action.type}`) // action may be an object.type or plain string const actionType: string = typeof action === 'string' ? action : action.type diff --git a/src/services/git/index.ts b/src/services/git/index.ts index d5106a17..28c43bcd 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -81,7 +81,7 @@ export async function version(): Promise { async function init(): Promise { const { stderr } = await node.exec('git init') if (stderr) { - throw new Error('Error initializing Gits') + throw new Error('Error initializing Git') } } @@ -133,5 +133,7 @@ export async function setupRemote(repo: string): Promise { // git fetch coderoad if (!hasRemote) { await addRemote(repo) + } else { + throw new Error('A Remote is already configured') } } diff --git a/web-app/src/containers/Tutorial/LevelPage/Level.tsx b/web-app/src/containers/Tutorial/LevelPage/Level.tsx index 1183c0a3..0914bd8b 100644 --- a/web-app/src/containers/Tutorial/LevelPage/Level.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level.tsx @@ -8,124 +8,124 @@ import Markdown from '../../../components/Markdown' import ProcessEvents from '../../../components/ProcessEvents' const styles = { - page: { - backgroundColor: 'white', - position: 'relative' as 'relative', - display: 'flex' as 'flex', - flexDirection: 'column' as 'column', - padding: 0, - paddingBottom: '36px', - height: 'auto', - width: '100%', - }, - header: { - height: '36px', - backgroundColor: '#EBEBEB', - fontSize: '16px', - lineHeight: '16px', - padding: '10px 1rem', - }, - content: { - padding: '0rem 1rem', - paddingBottom: '1rem', - }, - tasks: { - paddingBottom: '5rem', - }, - steps: { - padding: '1rem 16px', - }, - title: { - fontSize: '1.2rem', - fontWeight: 'bold' as 'bold', - lineHeight: '1.2rem', - }, - processes: { - padding: '0 1rem', - position: 'absolute' as 'absolute', - bottom: '36px', - }, - footer: { - display: 'flex' as 'flex', - flexDirection: 'row' as 'row', - justifyContent: 'space-between', - alignItems: 'center', - height: '36px', - backgroundColor: 'black', - fontSize: '16px', - lineHeight: '16px', - padding: '10px 1rem', - position: 'fixed' as 'fixed', - bottom: 0, - left: 0, - right: 0, - color: 'white', - }, + page: { + backgroundColor: 'white', + position: 'relative' as 'relative', + display: 'flex' as 'flex', + flexDirection: 'column' as 'column', + padding: 0, + paddingBottom: '36px', + height: 'auto', + width: '100%', + }, + header: { + height: '36px', + backgroundColor: '#EBEBEB', + fontSize: '16px', + lineHeight: '16px', + padding: '10px 1rem', + }, + content: { + padding: '0rem 1rem', + paddingBottom: '1rem', + }, + tasks: { + paddingBottom: '5rem', + }, + steps: { + padding: '1rem 16px', + }, + title: { + fontSize: '1.2rem', + fontWeight: 'bold' as 'bold', + lineHeight: '1.2rem', + }, + processes: { + padding: '0 1rem', + position: 'absolute' as 'absolute', + bottom: '36px', + }, + footer: { + display: 'flex' as 'flex', + flexDirection: 'row' as 'row', + justifyContent: 'space-between', + alignItems: 'center', + height: '36px', + backgroundColor: 'black', + fontSize: '16px', + lineHeight: '16px', + padding: '10px 1rem', + position: 'fixed' as 'fixed', + bottom: 0, + left: 0, + right: 0, + color: 'white', + }, } interface Props { - level: G.Level & { status: T.ProgressStatus; index: number; steps: Array } - processes: T.ProcessEvent[] - onContinue(): void - onLoadSolution(): void + level: G.Level & { status: T.ProgressStatus; index: number; steps: Array } + processes: T.ProcessEvent[] + onContinue(): void + onLoadSolution(): void } const Level = ({ level, onContinue, onLoadSolution, processes }: Props) => { - if (!level.steps) { - throw new Error('No Stage steps found') - } + if (!level.steps) { + throw new Error('No Stage steps found') + } - return ( -
-
- Learn -
-
-

{level.title}

- {level.content || ''} -
+ return ( +
+
+ Learn +
+
+

{level.title}

+ {level.content || ''} +
-
-
Tasks
-
- {level.steps.map((step: (G.Step & { status: T.ProgressStatus }) | null, index: number) => { - if (!step) { - return null - } - return ( - - ) - })} -
-
+
+
Tasks
+
+ {level.steps.map((step: (G.Step & { status: T.ProgressStatus }) | null, index: number) => { + if (!step) { + return null + } + return ( + + ) + })} +
+
- {processes.length > 0 && ( -
- -
- )} + {processes.length > 0 && ( +
+ +
+ )} -
- - {typeof level.index === 'number' ? `${level.index + 1}. ` : ''} - {level.title} - - - {level.status === 'COMPLETE' && ( - - )} - -
-
- ) +
+ + {typeof level.index === 'number' ? `${level.index + 1}. ` : ''} + {level.title} + + + {level.status === 'COMPLETE' && ( + + )} + +
+
+ ) } export default Level diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 4bad6166..635917a2 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -6,50 +6,52 @@ import * as selectors from '../../../services/selectors' import Level from './Level' interface PageProps { - context: T.MachineContext - send(action: T.Action): void + context: T.MachineContext + send(action: T.Action): void } const LevelSummaryPageContainer = (props: PageProps) => { - const { position, progress, processes } = props.context - - const version = selectors.currentVersion(props.context) - const levelData: G.Level = selectors.currentLevel(props.context) - - const onContinue = (): void => { - props.send({ - type: 'LEVEL_NEXT', - payload: { - LevelId: position.levelId, - }, - }) - } - - const onLoadSolution = (): void => { - props.send({ type: 'STEP_SOLUTION_LOAD' }) - } - - const level: G.Level & { - status: T.ProgressStatus - index: number - steps: Array - } = { - ...levelData, - index: version.data.levels.findIndex((l: G.Level) => l.id === position.levelId), - status: progress.levels[position.levelId] ? 'COMPLETE' : 'ACTIVE', - steps: levelData.steps.map((step: G.Step) => { - // label step status for step component - let status: T.ProgressStatus = 'INCOMPLETE' - if (progress.steps[step.id]) { - status = 'COMPLETE' - } else if (step.id === position.stepId) { - status = 'ACTIVE' - } - return { ...step, status } - }), - } - - return + const { position, progress, processes, error } = props.context + + const version = selectors.currentVersion(props.context) + const levelData: G.Level = selectors.currentLevel(props.context) + + const onContinue = (): void => { + props.send({ + type: 'LEVEL_NEXT', + payload: { + LevelId: position.levelId, + }, + }) + } + + const onLoadSolution = (): void => { + props.send({ type: 'STEP_SOLUTION_LOAD' }) + } + + const level: G.Level & { + status: T.ProgressStatus + index: number + steps: Array + } = { + ...levelData, + index: version.data.levels.findIndex((l: G.Level) => l.id === position.levelId), + status: progress.levels[position.levelId] ? 'COMPLETE' : 'ACTIVE', + steps: levelData.steps.map((step: G.Step) => { + // label step status for step component + let status: T.ProgressStatus = 'INCOMPLETE' + if (progress.steps[step.id]) { + status = 'COMPLETE' + } else if (step.id === position.stepId) { + status = 'ACTIVE' + } + return { ...step, status } + }), + } + + return ( + + ) } export default LevelSummaryPageContainer diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 2b12db85..b1a0c4b7 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -23,11 +23,6 @@ export const machine = Machine Date: Sat, 23 Nov 2019 21:17:40 -0800 Subject: [PATCH 2/5] refactor webview --- src/editor/ReactWebView.ts | 189 ------------------ src/editor/commands.ts | 4 +- src/webview/index.ts | 88 ++++++++ src/webview/render.ts | 83 ++++++++ .../containers/Tutorial/LevelPage/index.tsx | 2 +- 5 files changed, 174 insertions(+), 192 deletions(-) delete mode 100644 src/editor/ReactWebView.ts create mode 100644 src/webview/index.ts create mode 100644 src/webview/render.ts diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts deleted file mode 100644 index f54cdb8e..00000000 --- a/src/editor/ReactWebView.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { Action } from 'typings' -import * as path from 'path' -import * as vscode from 'vscode' -import { JSDOM } from 'jsdom' -import Channel from '../channel' - -const getNonce = (): string => { - let text = '' - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' - for (let i = 0; i < 32; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)) - } - return text -} - -interface ReactWebViewProps { - extensionPath: string - workspaceState: vscode.Memento - workspaceRoot: vscode.WorkspaceFolder -} - -// Manages webview panel -class ReactWebView { - // @ts-ignore - public loaded: boolean - - public send: Channel['send'] - private panel: vscode.WebviewPanel - private extensionPath: string - private disposables: vscode.Disposable[] = [] - private channel: Channel - - public constructor({ extensionPath, workspaceState, workspaceRoot }: ReactWebViewProps) { - this.extensionPath = extensionPath - - // Create and show a new webview panel - this.panel = this.createWebviewPanel() - - // Set the webview initial html content - this.render() - - // Listen for when the panel is disposed - // This happens when the user closes the panel or when the panel is closed programmatically - this.panel.onDidDispose(this.dispose, this, this.disposables) - - // update panel on changes - // const updateWindows = () => { - // vscode.commands.executeCommand('coderoad.open_webview') - // } - - // // // prevents moving coderoad panel on top of left panel - // vscode.window.onDidChangeVisibleTextEditors((textEditors: vscode.TextEditor[]) => { - // // updateWindows() - // }) - - // TODO: prevent window from moving to the left when no windows remain on rights - - // channel connects webview to the editor - this.channel = new Channel({ - workspaceState, - workspaceRoot, - postMessage: (action: Action): Thenable => { - // console.log(`postMessage ${JSON.stringify(action)}`) - return this.panel.webview.postMessage(action) - }, - }) - // Handle messages from the webview - const receive = this.channel.receive - this.panel.webview.onDidReceiveMessage(receive, null, this.disposables) - this.send = this.channel.send - } - - public createOrShow(): void { - vscode.commands.executeCommand('vscode.setEditorLayout', { - orientation: 0, - groups: [ - { groups: [{}], size: 0.6 }, - { groups: [{}], size: 0.4 }, - ], - }) - // If we already have a panel, show it. - // Otherwise, create a new panel. - - if (this.panel && this.panel.webview) { - if (!this.loaded) { - this.panel.reveal(vscode.ViewColumn.Two) - this.loaded = true - } - } else { - this.panel = this.createWebviewPanel() - } - } - - private async dispose(): Promise { - // Clean up our resources - this.loaded = false - this.panel.dispose() - Promise.all(this.disposables.map(x => x.dispose())) - } - - private createWebviewPanel = (): vscode.WebviewPanel => { - const viewType = 'CodeRoad' - const title = 'CodeRoad' - const config = { - // Enable javascript in the webview - enableScripts: true, - // And restrict the webview to only loading content from our extension's `media` directory. - localResourceRoots: [vscode.Uri.file(path.join(this.extensionPath, 'build'))], - // prevents destroying the window when it is in the background - retainContextWhenHidden: true, - } - this.loaded = true - return vscode.window.createWebviewPanel(viewType, title, vscode.ViewColumn.Two, config) - } - - private render = async (): Promise => { - // path to build directory - const rootPath = path.join(this.extensionPath, 'build') - - // load copied index.html from web app build - const dom = await JSDOM.fromFile(path.join(rootPath, 'index.html')) - const { document } = dom.window - - // set base href - const base: HTMLBaseElement = document.createElement('base') - base.href = - vscode.Uri.file(rootPath) - .with({ scheme: 'vscode-resource' }) - .toString() + '/' - document.head.appendChild(base) - - // used for CSP - const nonces: string[] = [] - - // generate vscode-resource build path uri - const createUri = (filePath: string): string => - vscode.Uri.file(filePath) - .with({ scheme: 'vscode-resource' }) - .toString() - .replace(/^\/+/g, '') // remove leading '/' - .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root - - // fix paths for scripts - const scripts: HTMLScriptElement[] = Array.from(document.getElementsByTagName('script')) - for (const script of scripts) { - if (script.src) { - const nonce: string = getNonce() - nonces.push(nonce) - script.nonce = nonce - script.src = createUri(script.src) - } - } - - // add run-time script from webpack - const runTimeScript = document.createElement('script') - runTimeScript.nonce = getNonce() - nonces.push(runTimeScript.nonce) - const manifest = await import(path.join(rootPath, 'asset-manifest.json')) - runTimeScript.src = createUri(path.join(rootPath, manifest.files['runtime-main.js'])) - document.body.appendChild(runTimeScript) - - // fix paths for links - const styles: HTMLLinkElement[] = Array.from(document.getElementsByTagName('link')) - for (const style of styles) { - if (style.href) { - style.href = createUri(style.href) - } - } - - // set CSP (content security policy) to grant permission to local files - const cspMeta: HTMLMetaElement = document.createElement('meta') - cspMeta.httpEquiv = 'Content-Security-Policy' - cspMeta.content = [ - 'font-src vscode-resource://*;', - 'img-src vscode-resource: https:;', - `script-src ${nonces.map(nonce => `'nonce-${nonce}'`).join(' ')};`, - `style-src 'unsafe-inline' vscode-resource: http: https: data:;`, - ].join(' ') - document.head.appendChild(cspMeta) - - // stringify dom - const html = dom.serialize() - - // set view - this.panel.webview.html = html - } -} - -export default ReactWebView diff --git a/src/editor/commands.ts b/src/editor/commands.ts index 80adfe7b..309a3985 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -1,6 +1,6 @@ import * as G from 'typings/graphql' import * as vscode from 'vscode' -import ReactWebView from './ReactWebView' +import createWebView from '../webview' import createTestRunner, { Payload } from '../services/testRunner' export const COMMANDS = { @@ -41,7 +41,7 @@ export const createCommands = ({ extensionPath, workspaceState, workspaceRoot }: } // activate machine - webview = new ReactWebView({ + webview = createWebView({ extensionPath, workspaceState, workspaceRoot, diff --git a/src/webview/index.ts b/src/webview/index.ts new file mode 100644 index 00000000..a7986fc0 --- /dev/null +++ b/src/webview/index.ts @@ -0,0 +1,88 @@ +import { Action } from 'typings' +import * as path from 'path' +import * as vscode from 'vscode' +import Channel from '../channel' +import render from './render' + +interface ReactWebViewProps { + extensionPath: string + workspaceState: vscode.Memento + workspaceRoot: vscode.WorkspaceFolder +} + +const createReactWebView = ({ extensionPath, workspaceState, workspaceRoot }: ReactWebViewProps) => { + let loaded = false + // TODO: add disposables + const disposables: vscode.Disposable[] = [] + + function createWebViewPanel(): vscode.WebviewPanel { + const viewType = 'CodeRoad' + const title = 'CodeRoad' + const config = { + // Enable javascript in the webview + enableScripts: true, + // And restrict the webview to only loading content from our extension's `media` directory. + localResourceRoots: [vscode.Uri.file(path.join(extensionPath, 'build'))], + // prevents destroying the window when it is in the background + retainContextWhenHidden: true, + } + loaded = true + return vscode.window.createWebviewPanel(viewType, title, vscode.ViewColumn.Two, config) + } + + let panel: vscode.WebviewPanel = createWebViewPanel() + + // Listen for when the panel is disposed + // This happens when the user closes the panel or when the panel is closed programmatically + panel.onDidDispose(panel.dispose, null, disposables) + + const channel = new Channel({ + workspaceState, + workspaceRoot, + postMessage: (action: Action): Thenable => { + // console.log(`postMessage ${JSON.stringify(action)}`) + return panel.webview.postMessage(action) + }, + }) + // Handle messages from the webview + const receive = channel.receive + const send = channel.send + + panel.webview.onDidReceiveMessage(receive, null, disposables) + + const rootPath = path.join(extensionPath, 'build') + render(panel, rootPath) + + return { + dispose() { + // Clean up our resources + loaded = false + panel.dispose() + Promise.all(disposables.map(x => x.dispose())) + }, + createOrShow() { + vscode.commands.executeCommand('vscode.setEditorLayout', { + orientation: 0, + groups: [ + { groups: [{}], size: 0.6 }, + { groups: [{}], size: 0.4 }, + ], + }) + // If we already have a panel, show it. + // Otherwise, create a new panel. + + if (panel && panel.webview) { + if (!loaded) { + panel.reveal(vscode.ViewColumn.Two) + loaded = true + } + } else { + panel = createWebViewPanel() + } + }, + send, + receive, + } +} + +export default createReactWebView diff --git a/src/webview/render.ts b/src/webview/render.ts new file mode 100644 index 00000000..55b22c37 --- /dev/null +++ b/src/webview/render.ts @@ -0,0 +1,83 @@ +import { JSDOM } from 'jsdom' +import * as vscode from 'vscode' +import * as path from 'path' + +const getNonce = (): string => { + let text = '' + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)) + } + return text +} + +async function render(panel: vscode.WebviewPanel, rootPath: string) { + // load copied index.html from web app build + const dom = await JSDOM.fromFile(path.join(rootPath, 'index.html')) + const { document } = dom.window + + // set base href + const base: HTMLBaseElement = document.createElement('base') + base.href = + vscode.Uri.file(rootPath) + .with({ scheme: 'vscode-resource' }) + .toString() + '/' + document.head.appendChild(base) + + // used for CSP + const nonces: string[] = [] + + // generate vscode-resource build path uri + const createUri = (filePath: string): string => + vscode.Uri.file(filePath) + .with({ scheme: 'vscode-resource' }) + .toString() + .replace(/^\/+/g, '') // remove leading '/' + .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root + + // fix paths for scripts + const scripts: HTMLScriptElement[] = Array.from(document.getElementsByTagName('script')) + for (const script of scripts) { + if (script.src) { + const nonce: string = getNonce() + nonces.push(nonce) + script.nonce = nonce + script.src = createUri(script.src) + } + } + + // add run-time script from webpack + const runTimeScript = document.createElement('script') + runTimeScript.nonce = getNonce() + nonces.push(runTimeScript.nonce) + const manifest = await import(path.join(rootPath, 'asset-manifest.json')) + runTimeScript.src = createUri(path.join(rootPath, manifest.files['runtime-main.js'])) + document.body.appendChild(runTimeScript) + + // fix paths for links + const styles: HTMLLinkElement[] = Array.from(document.getElementsByTagName('link')) + for (const style of styles) { + if (style.href) { + style.href = createUri(style.href) + } + } + + // set CSP (content security policy) to grant permission to local files + const cspMeta: HTMLMetaElement = document.createElement('meta') + cspMeta.httpEquiv = 'Content-Security-Policy' + cspMeta.content = [ + 'font-src vscode-resource://*;', + 'img-src vscode-resource: https:;', + `script-src ${nonces.map(nonce => `'nonce-${nonce}'`).join(' ')};`, + `style-src vscode-resource: http: https: data:;`, + ].join(' ') + document.head.appendChild(cspMeta) + + // stringify dom + const html = dom.serialize() + + // set view + panel.webview.html = html +} + +export default render diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 635917a2..900a9f0c 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -50,7 +50,7 @@ const LevelSummaryPageContainer = (props: PageProps) => { } return ( - + ) } From a710d6feb3b2d20df52042daed759309f2ae2c07 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 23 Nov 2019 21:31:15 -0800 Subject: [PATCH 3/5] add render test --- src/webview/render.ts | 20 ++++---- src/webview/test.html | 115 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/webview/test.html diff --git a/src/webview/render.ts b/src/webview/render.ts index 55b22c37..92e8411c 100644 --- a/src/webview/render.ts +++ b/src/webview/render.ts @@ -18,22 +18,20 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { // set base href const base: HTMLBaseElement = document.createElement('base') - base.href = - vscode.Uri.file(rootPath) - .with({ scheme: 'vscode-resource' }) - .toString() + '/' + base.href = panel.webview.asWebviewUri(vscode.Uri.file(rootPath)).toString() + '/' + document.head.appendChild(base) // used for CSP const nonces: string[] = [] // generate vscode-resource build path uri - const createUri = (filePath: string): string => - vscode.Uri.file(filePath) - .with({ scheme: 'vscode-resource' }) - .toString() - .replace(/^\/+/g, '') // remove leading '/' - .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root + const createUri = (filePath: string): any => { + return panel.webview.asWebviewUri(vscode.Uri.file(filePath)) + // .toString() + // .replace(/^\/+/g, '') // remove leading '/' + // .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root + } // fix paths for scripts const scripts: HTMLScriptElement[] = Array.from(document.getElementsByTagName('script')) @@ -76,6 +74,8 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { // stringify dom const html = dom.serialize() + console.log(html) + // set view panel.webview.html = html } diff --git a/src/webview/test.html b/src/webview/test.html new file mode 100644 index 00000000..d6f600e6 --- /dev/null +++ b/src/webview/test.html @@ -0,0 +1,115 @@ + + + + + + + + + CodeRoad + + + + + + + +
+ + + + + + From bb4c34791519b59bbfeb42303547652078864dc1 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 23 Nov 2019 21:43:11 -0800 Subject: [PATCH 4/5] use panel.webview.asWebviewUri --- src/webview/render.ts | 11 ++-- src/webview/test.html | 115 ------------------------------------------ 2 files changed, 6 insertions(+), 120 deletions(-) delete mode 100644 src/webview/test.html diff --git a/src/webview/render.ts b/src/webview/render.ts index 92e8411c..dd579e30 100644 --- a/src/webview/render.ts +++ b/src/webview/render.ts @@ -18,7 +18,7 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { // set base href const base: HTMLBaseElement = document.createElement('base') - base.href = panel.webview.asWebviewUri(vscode.Uri.file(rootPath)).toString() + '/' + base.href = `vscode-resource:${rootPath}/` document.head.appendChild(base) @@ -27,10 +27,11 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { // generate vscode-resource build path uri const createUri = (filePath: string): any => { - return panel.webview.asWebviewUri(vscode.Uri.file(filePath)) - // .toString() - // .replace(/^\/+/g, '') // remove leading '/' - // .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root + return panel.webview + .asWebviewUri(vscode.Uri.file(filePath)) + .toString() + .replace(/^\/+/g, '') // remove leading '/' + .replace('/vscode-resource%3A', rootPath) // replace mangled resource path with root } // fix paths for scripts diff --git a/src/webview/test.html b/src/webview/test.html deleted file mode 100644 index d6f600e6..00000000 --- a/src/webview/test.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - CodeRoad - - - - - - - -
- - - - - - From 8f91f70c865fb65342cb4042c4c992c9e28e6169 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 24 Nov 2019 21:11:47 -0800 Subject: [PATCH 5/5] refactor csp --- src/actions/utils/runCommands.ts | 1 - src/channel/index.ts | 2 -- src/webview/index.ts | 1 - src/webview/render.ts | 8 +++----- web-app/src/components/Message/index.tsx | 1 - web-app/src/services/channel/index.ts | 2 -- 6 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/actions/utils/runCommands.ts b/src/actions/utils/runCommands.ts index 07f62ebd..01edf27a 100644 --- a/src/actions/utils/runCommands.ts +++ b/src/actions/utils/runCommands.ts @@ -19,7 +19,6 @@ const runCommands = async (commands: string[], send: (action: T.Action) => void) send({ type: 'COMMAND_FAIL', payload: { process: { ...process, status: 'FAIL' } } }) return } - console.log(result.stdout) send({ type: 'COMMAND_SUCCESS', payload: { process: { ...process, status: 'SUCCESS' } } }) } } diff --git a/src/channel/index.ts b/src/channel/index.ts index 219349eb..f53b900d 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -39,7 +39,6 @@ class Channel implements Channel { const actionType: string = typeof action === 'string' ? action : action.type const onError = (error: T.ErrorMessage) => this.send({ type: 'ERROR', payload: { error } }) - // console.log('EDITOR RECEIVED:', actionType) switch (actionType) { case 'ENV_GET': this.send({ @@ -139,7 +138,6 @@ class Channel implements Channel { } // send to webview public send = async (action: T.Action) => { - console.log(`EDITOR SEND ${action.type}`) // action may be an object.type or plain string const actionType: string = typeof action === 'string' ? action : action.type switch (actionType) { diff --git a/src/webview/index.ts b/src/webview/index.ts index a7986fc0..dbc84a1c 100644 --- a/src/webview/index.ts +++ b/src/webview/index.ts @@ -40,7 +40,6 @@ const createReactWebView = ({ extensionPath, workspaceState, workspaceRoot }: Re workspaceState, workspaceRoot, postMessage: (action: Action): Thenable => { - // console.log(`postMessage ${JSON.stringify(action)}`) return panel.webview.postMessage(action) }, }) diff --git a/src/webview/render.ts b/src/webview/render.ts index dd579e30..8313e0a8 100644 --- a/src/webview/render.ts +++ b/src/webview/render.ts @@ -65,18 +65,16 @@ async function render(panel: vscode.WebviewPanel, rootPath: string) { const cspMeta: HTMLMetaElement = document.createElement('meta') cspMeta.httpEquiv = 'Content-Security-Policy' cspMeta.content = [ - 'font-src vscode-resource://*;', - 'img-src vscode-resource: https:;', + `font-src ${panel.webview.cspSource} http: https: data:;`, + `img-src ${panel.webview.cspSource} https:;`, `script-src ${nonces.map(nonce => `'nonce-${nonce}'`).join(' ')};`, - `style-src vscode-resource: http: https: data:;`, + `style-src ${panel.webview.cspSource} https:;`, ].join(' ') document.head.appendChild(cspMeta) // stringify dom const html = dom.serialize() - console.log(html) - // set view panel.webview.html = html } diff --git a/web-app/src/components/Message/index.tsx b/web-app/src/components/Message/index.tsx index ba71e39b..056785f4 100644 --- a/web-app/src/components/Message/index.tsx +++ b/web-app/src/components/Message/index.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import * as T from 'typings' import { Message as AlifdMessage } from '@alifd/next' interface Props { diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index 5fb0705b..64bf55c5 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -40,8 +40,6 @@ class Channel { return } - console.log(`CLIENT RECEIVE: ${action.type}`, action) - // messages from core switch (action.type) { case 'ENV_LOAD':