From 67357daff6c3d7dff85685546f5b26210703cd14 Mon Sep 17 00:00:00 2001 From: Christellah Date: Thu, 18 Jul 2019 10:59:53 -0700 Subject: [PATCH] Improvements from bug bash comments (#56) [PBI:30845] * Resetting to switch state to off * Changing the wording for code deployement to device * Indicating which file is selected for deployement in the output panel * Allowing Python processes to be spawned only if a file as been selected * Killing the process when closing the webview --- src/constants.ts | 8 +- src/extension.ts | 279 +++++++++++++++--------------- src/view/components/Simulator.tsx | 19 +- src/view/components/cpx/Cpx.tsx | 24 ++- 4 files changed, 173 insertions(+), 157 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index df789ecd6..0f1f72709 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -47,12 +47,18 @@ export const CONSTANTS = { ), DEPLOY_SUCCESS: localize( "info.deploySuccess", - "\n[INFO] Code successfully deployed\n" + "\n[INFO] Code successfully copied! Your Circuit Playground Express should be loading and ready to go shortly.\n" ), EXTENSION_ACTIVATED: localize( "info.extensionActivated", "Congratulations, your extension Adafruit_Simulator is now active!" ), + FILE_SELECTED: (filePath: string) => { + return localize( + "info.fileSelected", + `[INFO] File selected : ${filePath} \n` + ); + }, FIRST_TIME_WEBVIEW: localize( "info.firstTimeWebview", 'To reopen the simulator click on the "Open Simulator" button on the upper right corner of the text editor, or select the command "Open Simulator" from command palette.' diff --git a/src/extension.ts b/src/extension.ts index 0c0bed4d4..f95c0f343 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -108,6 +108,7 @@ export function activate(context: vscode.ExtensionContext) { currentPanel.onDidDispose( () => { currentPanel = undefined; + killProcessIfRunning(); if (firstTimeClosed) { vscode.window.showInformationMessage( CONSTANTS.INFO.FIRST_TIME_WEBVIEW @@ -217,78 +218,80 @@ export function activate(context: vscode.ExtensionContext) { logToOutputChannel(outChannel, CONSTANTS.INFO.DEPLOY_SIMULATOR); - const activeTextEditor: vscode.TextEditor | undefined = - vscode.window.activeTextEditor; + killProcessIfRunning(); - updateCurrentFileIfPython(activeTextEditor); + updateCurrentFileIfPython(vscode.window.activeTextEditor); if (currentFileAbsPath === "") { logToOutputChannel(outChannel, CONSTANTS.ERROR.NO_FILE_TO_RUN, true); - } - - killProcessIfRunning(); - - childProcess = cp.spawn("python", [ - utils.getPathToScript(context, "out", "process_user_code.py"), - currentFileAbsPath - ]); - - let dataFromTheProcess = ""; - let oldMessage = ""; + } else { + logToOutputChannel( + outChannel, + CONSTANTS.INFO.FILE_SELECTED(currentFileAbsPath) + ); - // Data received from Python process - childProcess.stdout.on("data", data => { - dataFromTheProcess = data.toString(); - if (currentPanel) { - // Process the data from the process and send one state at a time - dataFromTheProcess.split("\0").forEach(message => { - if (currentPanel && message.length > 0 && message != oldMessage) { - oldMessage = message; - let messageToWebview; - // Check the message is a JSON - try { - messageToWebview = JSON.parse(message); - // Check the JSON is a state - switch (messageToWebview.type) { - case "state": - console.log( - `Process state output = ${messageToWebview.data}` - ); - currentPanel.webview.postMessage({ - command: "set-state", - state: JSON.parse(messageToWebview.data) - }); - break; - - default: - console.log( - `Non-state JSON output from the process : ${messageToWebview}` - ); - break; + childProcess = cp.spawn("python", [ + utils.getPathToScript(context, "out", "process_user_code.py"), + currentFileAbsPath + ]); + + let dataFromTheProcess = ""; + let oldMessage = ""; + + // Data received from Python process + childProcess.stdout.on("data", data => { + dataFromTheProcess = data.toString(); + if (currentPanel) { + // Process the data from the process and send one state at a time + dataFromTheProcess.split("\0").forEach(message => { + if (currentPanel && message.length > 0 && message != oldMessage) { + oldMessage = message; + let messageToWebview; + // Check the message is a JSON + try { + messageToWebview = JSON.parse(message); + // Check the JSON is a state + switch (messageToWebview.type) { + case "state": + console.log( + `Process state output = ${messageToWebview.data}` + ); + currentPanel.webview.postMessage({ + command: "set-state", + state: JSON.parse(messageToWebview.data) + }); + break; + + default: + console.log( + `Non-state JSON output from the process : ${messageToWebview}` + ); + break; + } + } catch (err) { + console.log(`Non-JSON output from the process : ${message}`); } - } catch (err) { - console.log(`Non-JSON output from the process : ${message}`); } - } - }); - } - }); - - // Std error output - childProcess.stderr.on("data", data => { - console.error(`Error from the Python process through stderr: ${data}`); - TelemetryAI.trackFeatureUsage(TelemetryEventName.ERROR_PYTHON_PROCESS); - logToOutputChannel(outChannel, CONSTANTS.ERROR.STDERR(data), true); - if (currentPanel) { - console.log("Sending clearing state command"); - currentPanel.webview.postMessage({ command: "reset-state" }); - } - }); + }); + } + }); + + // Std error output + childProcess.stderr.on("data", data => { + console.error(`Error from the Python process through stderr: ${data}`); + TelemetryAI.trackFeatureUsage(TelemetryEventName.ERROR_PYTHON_PROCESS); + logToOutputChannel(outChannel, CONSTANTS.ERROR.STDERR(data), true); + if (currentPanel) { + console.log("Sending clearing state command"); + currentPanel.webview.postMessage({ command: "reset-state" }); + } + }); - // When the process is done - childProcess.on("end", (code: number) => { - console.info(`Command execution exited with code: ${code}`); - }); + // When the process is done + childProcess.on("end", (code: number) => { + console.info(`Command execution exited with code: ${code}`); + }); + } }; // Send message to the webview @@ -304,86 +307,88 @@ export function activate(context: vscode.ExtensionContext) { logToOutputChannel(outChannel, CONSTANTS.INFO.DEPLOY_DEVICE); - const activeTextEditor: vscode.TextEditor | undefined = - vscode.window.activeTextEditor; - - updateCurrentFileIfPython(activeTextEditor); + updateCurrentFileIfPython(vscode.window.activeTextEditor); if (currentFileAbsPath === "") { logToOutputChannel(outChannel, CONSTANTS.ERROR.NO_FILE_TO_RUN, true); - } - - const deviceProcess = cp.spawn("python", [ - utils.getPathToScript(context, "out", "device.py"), - currentFileAbsPath - ]); - - let dataFromTheProcess = ""; - - // Data received from Python process - deviceProcess.stdout.on("data", data => { - dataFromTheProcess = data.toString(); - console.log(`Device output = ${dataFromTheProcess}`); - let messageToWebview; - try { - messageToWebview = JSON.parse(dataFromTheProcess); - // Check the JSON is a state - switch (messageToWebview.type) { - case "complete": - TelemetryAI.trackFeatureUsage( - TelemetryEventName.SUCCESS_COMMAND_DEPLOY_DEVICE - ); - logToOutputChannel(outChannel, CONSTANTS.INFO.DEPLOY_SUCCESS); - break; - - case "no-device": - TelemetryAI.trackFeatureUsage( - TelemetryEventName.ERROR_DEPLOY_WITHOUT_DEVICE - ); - vscode.window - .showErrorMessage( - CONSTANTS.ERROR.NO_DEVICE, - ...[DialogResponses.HELP] - ) - .then((selection: vscode.MessageItem | undefined) => { - if (selection === DialogResponses.HELP) { - TelemetryAI.trackFeatureUsage( - TelemetryEventName.CLICK_DIALOG_HELP_DEPLOY_TO_DEVICE - ); - open(CONSTANTS.LINKS.HELP); - } - }); - break; + } else { + logToOutputChannel( + outChannel, + CONSTANTS.INFO.FILE_SELECTED(currentFileAbsPath) + ); - default: - console.log( - `Non-state JSON output from the process : ${messageToWebview}` - ); - break; + const deviceProcess = cp.spawn("python", [ + utils.getPathToScript(context, "out", "device.py"), + currentFileAbsPath + ]); + + let dataFromTheProcess = ""; + + // Data received from Python process + deviceProcess.stdout.on("data", data => { + dataFromTheProcess = data.toString(); + console.log(`Device output = ${dataFromTheProcess}`); + let messageToWebview; + try { + messageToWebview = JSON.parse(dataFromTheProcess); + // Check the JSON is a state + switch (messageToWebview.type) { + case "complete": + TelemetryAI.trackFeatureUsage( + TelemetryEventName.SUCCESS_COMMAND_DEPLOY_DEVICE + ); + logToOutputChannel(outChannel, CONSTANTS.INFO.DEPLOY_SUCCESS); + break; + + case "no-device": + TelemetryAI.trackFeatureUsage( + TelemetryEventName.ERROR_DEPLOY_WITHOUT_DEVICE + ); + vscode.window + .showErrorMessage( + CONSTANTS.ERROR.NO_DEVICE, + ...[DialogResponses.HELP] + ) + .then((selection: vscode.MessageItem | undefined) => { + if (selection === DialogResponses.HELP) { + TelemetryAI.trackFeatureUsage( + TelemetryEventName.CLICK_DIALOG_HELP_DEPLOY_TO_DEVICE + ); + open(CONSTANTS.LINKS.HELP); + } + }); + break; + + default: + console.log( + `Non-state JSON output from the process : ${messageToWebview}` + ); + break; + } + } catch (err) { + console.log( + `Non-JSON output from the process : ${dataFromTheProcess}` + ); } - } catch (err) { - console.log( - `Non-JSON output from the process : ${dataFromTheProcess}` - ); - } - }); + }); - // Std error output - deviceProcess.stderr.on("data", data => { - TelemetryAI.trackFeatureUsage( - TelemetryEventName.ERROR_PYTHON_DEVICE_PROCESS, - { error: `${data}` } - ); - console.error( - `Error from the Python device process through stderr: ${data}` - ); - logToOutputChannel(outChannel, `[ERROR] ${data} \n`, true); - }); + // Std error output + deviceProcess.stderr.on("data", data => { + TelemetryAI.trackFeatureUsage( + TelemetryEventName.ERROR_PYTHON_DEVICE_PROCESS, + { error: `${data}` } + ); + console.error( + `Error from the Python device process through stderr: ${data}` + ); + logToOutputChannel(outChannel, `[ERROR] ${data} \n`, true); + }); - // When the process is done - deviceProcess.on("end", (code: number) => { - console.info(`Command execution exited with code: ${code}`); - }); + // When the process is done + deviceProcess.on("end", (code: number) => { + console.info(`Command execution exited with code: ${code}`); + }); + } }; const runDevice: vscode.Disposable = vscode.commands.registerCommand( diff --git a/src/view/components/Simulator.tsx b/src/view/components/Simulator.tsx index 525f179f1..07f84fb2a 100644 --- a/src/view/components/Simulator.tsx +++ b/src/view/components/Simulator.tsx @@ -3,8 +3,7 @@ import * as React from "react"; import { BUTTON_NEUTRAL, BUTTON_PRESSED } from "./cpx/Cpx_svg_style"; -import Cpx from "./cpx/Cpx"; -import svg from "./cpx/Svg_utils"; +import Cpx, { updateSwitch } from "./cpx/Cpx"; interface IState { pixels: Array>; @@ -184,23 +183,9 @@ class Simulator extends React.Component { } private handleSwitchClick(button: HTMLElement) { - const switchInner = (window.document.getElementById( - "SWITCH_INNER" - ) as unknown) as SVGElement; - - svg.addClass(switchInner, "sim-slide-switch-inner"); - const switchIsOn: boolean = !this.state.switch; - - if (switchIsOn) { - svg.addClass(switchInner, "on"); - switchInner.setAttribute("transform", "translate(-5,0)"); - } else { - svg.removeClass(switchInner, "on"); - switchInner.removeAttribute("transform"); - } + updateSwitch(switchIsOn); this.setState({ switch: switchIsOn }); - button.setAttribute("aria-pressed", switchIsOn.toString()); return { switch: switchIsOn }; } } diff --git a/src/view/components/cpx/Cpx.tsx b/src/view/components/cpx/Cpx.tsx index bfaeb7fee..b5570dbb2 100644 --- a/src/view/components/cpx/Cpx.tsx +++ b/src/view/components/cpx/Cpx.tsx @@ -34,7 +34,8 @@ const Cpx: React.FC = props => { // Update Neopixels and red LED state updateNeopixels(props); updateRedLED(props.red_led); - updatePowerLED(props.power_led) + updatePowerLED(props.power_led); + updateSwitch(props.switch); } return CPX_SVG; @@ -175,7 +176,6 @@ const updateRedLED = (propsRedLED: boolean): void => { } }; - const updatePowerLED = (propsPowerLED: boolean): void => { let powerLED = window.document.getElementById("PWR_LED"); if (powerLED) { @@ -302,4 +302,24 @@ const setupSwitch = (props: IProps): void => { } }; +export const updateSwitch = (switchState: boolean): void => { + const switchElement = window.document.getElementById("SWITCH"); + const switchInner = (window.document.getElementById( + "SWITCH_INNER" + ) as unknown) as SVGElement; + + if (switchElement && switchInner) { + svg.addClass(switchInner, "sim-slide-switch-inner"); + + if (switchState) { + svg.addClass(switchInner, "on"); + switchInner.setAttribute("transform", "translate(-5,0)"); + } else { + svg.removeClass(switchInner, "on"); + switchInner.removeAttribute("transform"); + } + switchElement.setAttribute("aria-pressed", switchState.toString()); + } +}; + export default Cpx;