diff --git a/locales/en/package.i18n.json b/locales/en/package.i18n.json index b74373674..7e0bdc747 100644 --- a/locales/en/package.i18n.json +++ b/locales/en/package.i18n.json @@ -1,19 +1,21 @@ { - "deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies", - "deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express", - "deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator", - "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate", - "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor", - "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor", - "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port", - "deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator", - "deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File", - "deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device", - "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device", - "deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator", - "deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File", - "deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration", - "deviceSimulatorExpressExtension.configuration.properties.configEnvOnChange": "When you change the Python interpreter, the Device Simulator Express will automatically configure itself for the required dependencies.", - "deviceSimulatorExpressExtension.configuration.properties.debuggerPort": "The port the Server will listen on for communication with the debugger.", - "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask if we can download dependencies. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files." + "deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies", + "deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express", + "deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator", + "deviceSimulatorExpressExtension.commands.common.gettingStarted": "Getting Started", + + "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate", + "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor", + "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor", + "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port", + "deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator", + "deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File", + "deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device", + "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device", + "deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator", + "deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File", + "deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration", + "deviceSimulatorExpressExtension.configuration.properties.configEnvOnChange": "When you change the Python interpreter, the Device Simulator Express will automatically configure itself for the required dependencies.", + "deviceSimulatorExpressExtension.configuration.properties.debuggerPort": "The port the Server will listen on for communication with the debugger.", + "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask if we can download dependencies. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files." } diff --git a/package.json b/package.json index 66f094cc0..0f9c222c5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "onCommand:deviceSimulatorExpress.common.openSerialMonitor", "onCommand:deviceSimulatorExpress.common.runSimulator", "onCommand:deviceSimulatorExpress.common.selectSerialPort", + "onCommand:deviceSimulatorExpress.common.gettingStarted", "onCommand:deviceSimulatorExpress.cpx.deployToDevice", "onCommand:deviceSimulatorExpress.cpx.newFile", "onCommand:deviceSimulatorExpress.cpx.openSimulator", @@ -75,6 +76,11 @@ "title": "%deviceSimulatorExpressExtension.commands.common.runSimulator%", "category": "%deviceSimulatorExpressExtension.commands.common.label%" }, + { + "command": "deviceSimulatorExpress.common.gettingStarted", + "title": "%deviceSimulatorExpressExtension.commands.common.gettingStarted%", + "category": "%deviceSimulatorExpressExtension.commands.common.label%" + }, { "command": "deviceSimulatorExpress.cpx.deployToDevice", "title": "%deviceSimulatorExpressExtension.commands.cpx.deployToDevice%", diff --git a/package.nls.json b/package.nls.json index ad2a9ce7b..924645d32 100644 --- a/package.nls.json +++ b/package.nls.json @@ -1,19 +1,21 @@ { - "deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies", - "deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express", - "deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator", - "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate", - "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor", - "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor", - "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port", - "deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator", - "deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File", - "deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device", - "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device", - "deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator", - "deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File", - "deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration", - "deviceSimulatorExpressExtension.configuration.properties.configEnvOnChange": "When you change the Python interpreter, the Device Simulator Express will automatically configure itself for the required dependencies.", - "deviceSimulatorExpressExtension.configuration.properties.debuggerPort": "The port the Server will listen on for communication with the debugger.", - "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask for dependency downloads. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files." + "deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies", + "deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express", + "deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator", + "deviceSimulatorExpressExtension.commands.common.gettingStarted": "Getting Started", + + "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate", + "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor", + "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor", + "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port", + "deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator", + "deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File", + "deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device", + "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device", + "deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator", + "deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File", + "deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration", + "deviceSimulatorExpressExtension.configuration.properties.configEnvOnChange": "When you change the Python interpreter, the Device Simulator Express will automatically configure itself for the required dependencies.", + "deviceSimulatorExpressExtension.configuration.properties.debuggerPort": "The port the Server will listen on for communication with the debugger.", + "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask for dependency downloads. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files." } diff --git a/src/constants.ts b/src/constants.ts index fa4e3e1e0..b66330e55 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -25,6 +25,10 @@ export const CONFIG = { }; export const CONSTANTS = { + WEBVIEW_TYPE: { + SIMULATOR: "simulator", + TUTORIAL: "tutorial", + }, DEBUG_CONFIGURATION_TYPE: "deviceSimulatorExpress", DEVICE_NAME: { CPX: "CPX", @@ -320,6 +324,7 @@ export enum TelemetryEventName { COMMAND_SERIAL_MONITOR_OPEN = "COMMAND.SERIAL_MONITOR.OPEN", COMMAND_SERIAL_MONITOR_BAUD_RATE = "COMMAND.SERIAL_MONITOR.BAUD_RATE", COMMAND_SERIAL_MONITOR_CLOSE = "COMMAND.SERIAL_MONITOR.CLOSE", + COMMAND_GETTING_STARTED = "COMMAND.GETTING_STARTED", CPX_COMMAND_DEPLOY_DEVICE = "CPX.COMMAND.DEPLOY.DEVICE", CPX_COMMAND_NEW_FILE = "CPX.COMMAND.NEW.FILE.CPX", diff --git a/src/extension.ts b/src/extension.ts index 2098041b7..d555a0826 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -35,7 +35,12 @@ import { SimulatorDebugConfigurationProvider } from "./simulatorDebugConfigurati import getPackageInfo from "./telemetry/getPackageInfo"; import TelemetryAI from "./telemetry/telemetryAI"; import { UsbDetector } from "./usbDetector"; -import { VSCODE_MESSAGES_TO_WEBVIEW, WEBVIEW_MESSAGES } from "./view/constants"; +import { + VSCODE_MESSAGES_TO_WEBVIEW, + WEBVIEW_MESSAGES, + WEBVIEW_TYPES, +} from "./view/constants"; +import { WebviewService } from "./service/webviewService"; let telemetryAI: TelemetryAI; let pythonExecutablePath: string = GLOBAL_ENV_VARS.PYTHON; @@ -53,14 +58,6 @@ const fileSelectionService = new FileSelectionService(messagingService); export let outChannel: vscode.OutputChannel | undefined; -function loadScript(context: vscode.ExtensionContext, scriptPath: string) { - return ``; -} - const sendCurrentDeviceMessage = (currentPanel: vscode.WebviewPanel) => { if (currentPanel) { currentPanel.webview.postMessage({ @@ -71,14 +68,13 @@ const sendCurrentDeviceMessage = (currentPanel: vscode.WebviewPanel) => { }; // Extension activation export async function activate(context: vscode.ExtensionContext) { - console.info(CONSTANTS.INFO.EXTENSION_ACTIVATED); - telemetryAI = new TelemetryAI(context); setupService = new SetupService(telemetryAI); let currentPanel: vscode.WebviewPanel | undefined; let childProcess: cp.ChildProcess | undefined; let messageListener: vscode.Disposable; let activeEditorListener: vscode.Disposable; + const webviewService = new WebviewService(context, deviceSelectionService); // Add our library path to settings.json for autocomplete functionality updatePythonExtraPaths(); @@ -130,7 +126,7 @@ export async function activate(context: vscode.ExtensionContext) { currentPanel.reveal(vscode.ViewColumn.Beside); } else { currentPanel = vscode.window.createWebviewPanel( - "adafruitSimulator", + CONSTANTS.WEBVIEW_TYPE.SIMULATOR, CONSTANTS.LABEL.WEBVIEW_PANEL, { preserveFocus: true, viewColumn: vscode.ViewColumn.Beside }, { @@ -147,7 +143,10 @@ export async function activate(context: vscode.ExtensionContext) { } ); - currentPanel.webview.html = getWebviewContent(context); + currentPanel.webview.html = webviewService.getWebviewContent( + WEBVIEW_TYPES.SIMULATOR, + true + ); messagingService.setWebview(currentPanel.webview); if (messageListener !== undefined) { @@ -303,6 +302,16 @@ export async function activate(context: vscode.ExtensionContext) { openWebview(); }; + const gettingStartedOpen: vscode.Disposable = vscode.commands.registerCommand( + "deviceSimulatorExpress.common.gettingStarted", + () => { + telemetryAI.trackFeatureUsage( + TelemetryEventName.COMMAND_GETTING_STARTED + ); + webviewService.openTutorialPanel(); + } + ); + // Open Simulator on the webview const cpxOpenSimulator: vscode.Disposable = vscode.commands.registerCommand( "deviceSimulatorExpress.cpx.openSimulator", @@ -1059,6 +1068,7 @@ export async function activate(context: vscode.ExtensionContext) { microbitOpenSimulator, microbitNewFile, microbitDeployToDevice, + gettingStartedOpen, vscode.debug.registerDebugConfigurationProvider( CONSTANTS.DEBUG_CONFIGURATION_TYPE, simulatorDebugConfiguration @@ -1321,27 +1331,6 @@ const updateConfigLists = ( .update(section, Array.from(extraItemsSet), scope); }; -function getWebviewContent(context: vscode.ExtensionContext) { - return ` - - - - - - ${CONSTANTS.NAME} - - -
- - - ${loadScript(context, "out/vendor.js")} - ${loadScript(context, "out/simulator.js")} - - `; -} - // this method is called when your extension is deactivated export async function deactivate() { const monitor: SerialMonitor = SerialMonitor.getInstance(); diff --git a/src/service/webviewService.ts b/src/service/webviewService.ts new file mode 100644 index 000000000..a47a4c62a --- /dev/null +++ b/src/service/webviewService.ts @@ -0,0 +1,104 @@ +import * as path from "path"; +import * as vscode from "vscode"; +import CONSTANTS from "../constants"; +import { WEBVIEW_ATTRIBUTES_KEY, WEBVIEW_TYPES } from "../view/constants"; +import { DeviceSelectionService } from "./deviceSelectionService"; + +// Manages different type of webview +export class WebviewService { + private tutorialPanel: vscode.WebviewPanel | undefined; + private context: vscode.ExtensionContext; + private deviceSelectionService: DeviceSelectionService; + + constructor( + context: vscode.ExtensionContext, + deviceSelectionService: DeviceSelectionService + ) { + this.context = context; + this.deviceSelectionService = deviceSelectionService; + } + + public openTutorialPanel() { + if (this.tutorialPanel) { + this.tutorialPanel.reveal(vscode.ViewColumn.Beside); + } else { + this.createTutorialPanel(); + } + } + + public getWebviewContent(webviewType: string, hasDevice: boolean) { + return ` + + + + + + ${CONSTANTS.NAME} + + +
+ + + ${this.loadScript( + this.context, + webviewType, + "out/vendor.js", + hasDevice + )} + ${this.loadScript( + this.context, + webviewType, + "out/simulator.js", + hasDevice + )} + + `; + } + + private createTutorialPanel() { + this.tutorialPanel = vscode.window.createWebviewPanel( + CONSTANTS.WEBVIEW_TYPE.TUTORIAL, + CONSTANTS.LABEL.WEBVIEW_PANEL, + { preserveFocus: true, viewColumn: vscode.ViewColumn.One }, + { + enableScripts: true, + } + ); + this.tutorialPanel.webview.html = this.getWebviewContent( + WEBVIEW_TYPES.GETTING_STARTED, + false + ); + this.tutorialPanel.onDidDispose(() => { + this.disposeTutorialPanel(); + }); + } + + private disposeTutorialPanel() { + this.tutorialPanel = undefined; + } + + private loadScript( + context: vscode.ExtensionContext, + attributeValue: string, + scriptPath: string, + hasDevice: boolean + ) { + let attributeString: string; + if (hasDevice) { + attributeString = `${ + WEBVIEW_ATTRIBUTES_KEY.TYPE + }=${attributeValue} ${ + WEBVIEW_ATTRIBUTES_KEY.INITIAL_DEVICE + }=${this.deviceSelectionService.getCurrentActiveDevice()}`; + } else { + attributeString = `${WEBVIEW_ATTRIBUTES_KEY.TYPE}=${attributeValue} `; + } + return ``; + } +} diff --git a/src/view/App.tsx b/src/view/App.tsx index eb9da7b02..3e540c8d9 100644 --- a/src/view/App.tsx +++ b/src/view/App.tsx @@ -7,18 +7,23 @@ import { DEVICE_LIST_KEY, VIEW_STATE, VSCODE_MESSAGES_TO_WEBVIEW, + WEBVIEW_ATTRIBUTES_KEY, + WEBVIEW_TYPES, } from "./constants"; import { Device } from "./container/device/Device"; import { ViewStateContext } from "./context"; +import { GettingStartedPage } from "./pages/gettingStarted"; interface IState { currentDevice: string; viewState: VIEW_STATE; + type?: WEBVIEW_TYPES; } const defaultState = { currentDevice: DEVICE_LIST_KEY.CPX, viewState: VIEW_STATE.RUNNING, + type: undefined, }; class App extends React.Component<{}, IState> { @@ -28,15 +33,23 @@ class App extends React.Component<{}, IState> { } componentDidMount() { if (document.currentScript) { - const initialDevice = document.currentScript.getAttribute( - "initialDevice" - ); + const webviewTypeAttribute = document.currentScript.getAttribute( + WEBVIEW_ATTRIBUTES_KEY.TYPE + ) as WEBVIEW_TYPES; + if (webviewTypeAttribute) { + this.setState({ type: webviewTypeAttribute }); + } + if (webviewTypeAttribute === WEBVIEW_TYPES.SIMULATOR) { + const initialDevice = document.currentScript.getAttribute( + WEBVIEW_ATTRIBUTES_KEY.INITIAL_DEVICE + ); - if (initialDevice) { - this.setState({ currentDevice: initialDevice }); + if (initialDevice) { + this.setState({ currentDevice: initialDevice }); + window.addEventListener("message", this.handleMessage); + } } } - window.addEventListener("message", this.handleMessage); } componentWillUnmount() { window.removeEventListener("message", this.handleMessage); @@ -47,14 +60,24 @@ class App extends React.Component<{}, IState> {
- + {this.loadContent()}
); } + loadContent = () => { + console.log(this.state.type); + switch (this.state.type) { + case WEBVIEW_TYPES.GETTING_STARTED: + return ; + case WEBVIEW_TYPES.SIMULATOR: + return ( + + ); + } + return; + }; handleMessage = (event: any): void => { const message = event.data; diff --git a/src/view/__snapshots__/App.spec.tsx.snap b/src/view/__snapshots__/App.spec.tsx.snap index 5f47353a3..6343459f1 100644 --- a/src/view/__snapshots__/App.spec.tsx.snap +++ b/src/view/__snapshots__/App.spec.tsx.snap @@ -6,4701 +6,6 @@ exports[`App component should render correctly 1`] = ` >
-
-
-
- The simulator will run the .py file you have focused on. -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
+ /> `; diff --git a/src/view/components/microbit/Microbit.spec.tsx b/src/view/components/microbit/Microbit.spec.tsx new file mode 100644 index 000000000..e948a1988 --- /dev/null +++ b/src/view/components/microbit/Microbit.spec.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import { IntlProvider } from "react-intl"; +import * as testRenderer from "react-test-renderer"; +import { Microbit } from "./Microbit"; + +describe("Microbit component ", () => { + it("should render correctly", () => { + const component = testRenderer + .create( + + + + ) + .toJSON(); + expect(component).toMatchSnapshot(); + }); + + it("should render without crashing", () => { + const div = document.createElement("div"); + ReactDOM.render( + + + , + div + ); + ReactDOM.unmountComponentAtNode(div); + }); +}); diff --git a/src/view/components/microbit/__snapshots__/Microbit.spec.tsx.snap b/src/view/components/microbit/__snapshots__/Microbit.spec.tsx.snap new file mode 100644 index 000000000..7efb97e8e --- /dev/null +++ b/src/view/components/microbit/__snapshots__/Microbit.spec.tsx.snap @@ -0,0 +1,2975 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Microbit component should render correctly 1`] = ` +Array [ +
+
+ The simulator will run the .py file you have focused on. +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (0,0) + + + + + + (1,0) + + + + + + (2,0) + + + + + + (3,0) + + + + + + (4,0) + + + + + + (0,1) + + + + + + (1,1) + + + + + + (2,1) + + + + + + (3,1) + + + + + + (4,1) + + + + + + (0,2) + + + + + + (1,2) + + + + + + (2,2) + + + + + + (3,2) + + + + + + (4,2) + + + + + + (0,3) + + + + + + (1,3) + + + + + + (2,3) + + + + + + (3,3) + + + + + + (4,3) + + + + + + (0,4) + + + + + + (1,4) + + + + + + (2,4) + + + + + + (3,4) + + + + + + (4,4) + + + + + + + + + + + + P0, ANALOG IN + + + + + P1, ANALOG IN + + + + + P2, ANALOG IN + + + + + P3, ANALOG IN, LED Col 1 + + + + + P4, ANALOG IN, LED Col 2 + + + + + P5, BUTTON A + + + + + P6, LED Col 9 + + + + + P7, LED Col 8 + + + + + P8 + + + + + P9, LED Col 7 + + + + + P10, ANALOG IN, LED Col 3 + + + + + P11, BUTTON B + + + + + P12, RESERVED ACCESSIBILITY + + + + + P13, SPI - SCK + + + + + P14, SPI - MISO + + + + + P15, SPI - MOSI + + + + + P16, SPI - Chip Select + + + + + P17, +3v3 + + + + + P18, +3v3 + + + + + P19, I2C - SCL + + + + + P20, I2C - SDA + + + + + GND + + + + + GND + + + + + +3v3 + + + + + GND + + + + + + + + + + + + + + + + + + + + + + + A+B + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
, +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
, +] +`; diff --git a/src/view/constants.ts b/src/view/constants.ts index d81683ef2..b6ce70bd7 100644 --- a/src/view/constants.ts +++ b/src/view/constants.ts @@ -97,5 +97,12 @@ export enum SENSOR_LIST { MOTION_Y = "motion_y", MOTION_Z = "motion_z", } - +export enum WEBVIEW_ATTRIBUTES_KEY { + INITIAL_DEVICE = "initial_device", + TYPE = "webview_type", +} +export enum WEBVIEW_TYPES { + SIMULATOR = "simulator", + GETTING_STARTED = "getting_started", +} export default CONSTANTS; diff --git a/src/view/pages/__snapshots__/gettingStarted.spec.tsx.snap b/src/view/pages/__snapshots__/gettingStarted.spec.tsx.snap new file mode 100644 index 000000000..4bec5eeff --- /dev/null +++ b/src/view/pages/__snapshots__/gettingStarted.spec.tsx.snap @@ -0,0 +1,192 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GettingStartedPage component should render correctly 1`] = ` +
+

+ Getting started +

+ +

+ Copy these snippets of code to a .py file and run the simulator +

+
+

+ Tutorial for micro:bit +

+

+ 1. Import the micro:bit library to use it (This is required) +

+ +
+        from microbit import *
+      
+
+

+ 2. Light up your micro:bit with love by showing a heart +

+ +
+        display.show(Image.HEART)
+      
+
+

+ 3. Use your micro:bit to tell the world how you’re feeling +

+ +
+        while True:
+      
+
+         if button_a.is_pressed():
+      
+
+         display.show(Image.HAPPY)
+      
+
+         if button_b.is_pressed():
+      
+
+         display.show(Image.SAD)
+      
+
+

+ 4. Read then display the temperature. +

+ +
+        while True:
+      
+
+         temp = temperature()
+      
+
+         display.show(temp)
+      
+
+

+ And much more! These links have more tutorials: +

+

+ + Microbit Tutorials + +

+

+ + Microbit official documentation + +

+
+
+

+ Tutorial for CPX +

+

+ 1. Import the micro:bit library to use it (This is required) +

+ +
+        from adafruit_circuitplayground import cp
+      
+
+

+ 2. Turn on the little red LED +

+ +
+        while True:
+      
+
+         cp.red_led = True
+      
+
+

+ 3. Turn up red LED when button A is clicked +

+ +
+        while True:
+      
+
+         if cp.button_a:
+      
+
+         cp.red_led = True
+      
+
+

+ 4. Light up the first neopixel blue +

+ +
+        cp.pixels[0] = (0, 0, 255)
+      
+
+

+ And much more! These links have more tutorials: +

+

+ + Getting started with CPX and CircuitPython + +

+

+ + More example code + +

+
+
+`; diff --git a/src/view/pages/gettingStarted.css b/src/view/pages/gettingStarted.css new file mode 100644 index 000000000..e85a91a11 --- /dev/null +++ b/src/view/pages/gettingStarted.css @@ -0,0 +1,30 @@ +.inv { + display: none; +} + +.deviceSelector { + width: 250px; + border: 1px solid #3d484c; + margin: 0 0 5px; + padding: 8px; + border-radius: 5px; + font-size: 12px; + padding-right: 30px; +} + +.codeBox { + display: block; + width: 90%; + margin: 10px; + padding: 15px; + text-align: left; + background: none; + border: 1px solid grey; + border-radius: 4px; + background-color: var(--vscode-textCodeBlock-background); +} + +.container { + text-align: left; + padding: 0 10px 0 10px; +} diff --git a/src/view/pages/gettingStarted.spec.tsx b/src/view/pages/gettingStarted.spec.tsx new file mode 100644 index 000000000..278d5ed4b --- /dev/null +++ b/src/view/pages/gettingStarted.spec.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import { IntlProvider } from "react-intl"; +import * as testRenderer from "react-test-renderer"; +import { GettingStartedPage } from "./gettingStarted"; + +describe("GettingStartedPage component ", () => { + it("should render correctly", () => { + const component = testRenderer + .create( + + + + ) + .toJSON(); + expect(component).toMatchSnapshot(); + }); + + it("should render without crashing", () => { + const div = document.createElement("div"); + ReactDOM.render( + + + , + div + ); + ReactDOM.unmountComponentAtNode(div); + }); +}); diff --git a/src/view/pages/gettingStarted.tsx b/src/view/pages/gettingStarted.tsx new file mode 100644 index 000000000..693a6710c --- /dev/null +++ b/src/view/pages/gettingStarted.tsx @@ -0,0 +1,130 @@ +import * as React from "react"; +import "./gettingStarted.css"; + +export class GettingStartedPage extends React.Component { + private selectRef: React.RefObject = React.createRef(); + + componentDidMount() { + if (this.selectRef.current) { + this.selectRef.current.addEventListener("change", (event: any) => { + const visibleElement = document.querySelector( + ".visibleElement" + ); + const target = document.getElementById(event!.target!.value); + if (visibleElement !== null) { + visibleElement.className = "inv"; + } + if (target !== null) { + target.className = "visibleElement"; + } + }); + } + } + + render() { + return ( + +
+

Getting started

+ + +

+ Copy these snippets of code to a .py file and run the + simulator +

+
+

Tutorial for micro:bit

+

+ 1. Import the micro:bit library to use it (This is + required) +

+ +
from microbit import *
+
+

+ 2. Light up your micro:bit with love by showing a + heart +

+ +
display.show(Image.HEART)
+
+

+ 3. Use your micro:bit to tell the world how you’re + feeling +

+ +
while True:
+
 if button_a.is_pressed():
+
 display.show(Image.HAPPY)
+
 if button_b.is_pressed():
+
 display.show(Image.SAD)
+
+

4. Read then display the temperature.

+ +
while True:
+
 temp = temperature()
+
 display.show(temp)
+
+

And much more! These links have more tutorials:

+

+ + Microbit Tutorials + +

+

+ + Microbit official documentation + +

+
+
+

Tutorial for CPX

+

+ 1. Import the micro:bit library to use it (This is + required) +

+ +
from adafruit_circuitplayground import cp
+
+

2. Turn on the little red LED

+ +
while True:
+
 cp.red_led = True
+
+

3. Turn up red LED when button A is clicked

+ +
while True:
+
 if cp.button_a:
+
 cp.red_led = True
+
+

4. Light up the first neopixel blue

+ +
cp.pixels[0] = (0, 0, 255)
+
+

And much more! These links have more tutorials:

+

+ + Getting started with CPX and CircuitPython + +

+

+ + More example code + +

+
+
+
+ ); + } +}