Dialog wizard groundwork mostly working
This commit is contained in:
parent
79de9d5aa2
commit
c0c01ec808
10 changed files with 1526 additions and 113 deletions
|
|
@ -112,7 +112,7 @@
|
|||
<a class="download-button {% if version.stable %}stable{% else %}unstable{% endif %} {{ extension }}" href="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}">DOWNLOAD .{{ extension | upcase }} NOW <i class="fas fa-download" aria-hidden="true"></i></a>
|
||||
{% endfor %}
|
||||
{% if page.family == 'esp32s2' or page.family == 'esp32c3' or page.family == 'esp32s3' or page.family == 'esp32' %}
|
||||
<a class="download-button {% if version.stable %}stable{% else %}unstable{% endif %} bin" id="esp-installer" href="#">OPEN INSTALLER <i class="fas fa-magic" aria-hidden="true"></i></a>
|
||||
<button is="cp-install-button" class="installer-button" boardname="{{ page.name }}" boardid="{{ board_id }}" firmware="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}">OPEN INSTALLER <i class="fas fa-magic" aria-hidden="true"></i></button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
<h3>Absolute Newest</h3>
|
||||
<p>
|
||||
Every time we commit new code to CircuitPython we automatically
|
||||
build binaries for each board and language. The binaries are
|
||||
build binaries for each board and language. The binaries are
|
||||
stored on Amazon S3, organized by board, and then by
|
||||
language. Try them if you want the absolute latest and are
|
||||
feeling daring or want to see if a problem has been fixed.
|
||||
|
|
@ -149,10 +149,10 @@
|
|||
<h3>Past Releases</h3>
|
||||
<p>
|
||||
All previous releases are listed on GitHub, with release notes,
|
||||
and are available for download from Amazon S3. They are handy for
|
||||
and are available for download from Amazon S3. They are handy for
|
||||
testing, but otherwise we recommend using the latest stable
|
||||
release. Some older GitHub release pages include the same
|
||||
binaries for downloading. But we have discontinued including
|
||||
release. Some older GitHub release pages include the same
|
||||
binaries for downloading. But we have discontinued including
|
||||
binaries as assets on newer release pages because of the large
|
||||
number of files for each release.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ layout: default
|
|||
</div>
|
||||
|
||||
{% if page.family == 'esp32' or page.family == 'esp32s2' or page.family == 'esp32c3' or page.family == 'esp32s3' %}
|
||||
{% include downloads/esp_installer.html %}
|
||||
<script src="/assets/javascript/espinstaller.js" type="module"></script>
|
||||
<script src="/cpinstaller/src/cpinstaller.js" type="module"></script>
|
||||
{% endif %}
|
||||
<script src="/assets/javascript/download.js"></script>
|
||||
|
|
|
|||
|
|
@ -21,3 +21,4 @@
|
|||
@import 'pages/stats';
|
||||
@import 'pages/libraries';
|
||||
@import 'pages/contributing';
|
||||
@import 'pages/espinstaller';
|
||||
|
|
|
|||
|
|
@ -44,13 +44,14 @@
|
|||
}
|
||||
|
||||
.download {
|
||||
a.download-button, a.download-button-unrecommended {
|
||||
a.download-button, a.download-button-unrecommended, button[is="cp-install-button"] {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
padding: 15px 30px 15px 30px;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
padding-left: 10px;
|
||||
|
|
@ -143,8 +144,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
button[is="cp-install-button"] {
|
||||
color: $purple;
|
||||
background-color: transparent;
|
||||
border: 2px solid $purple;
|
||||
}
|
||||
|
||||
.download-buttons {
|
||||
a {
|
||||
a, button {
|
||||
width: 100%;
|
||||
height: 49px;
|
||||
padding: 0;
|
||||
|
|
|
|||
66
assets/sass/pages/_espinstaller.scss
Normal file
66
assets/sass/pages/_espinstaller.scss
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
.cp-installer-dialog {
|
||||
min-width: 300px;
|
||||
min-height: 100px;
|
||||
max-width: 600px;
|
||||
padding-bottom: 50px;
|
||||
border-radius: 15px;
|
||||
|
||||
&::backdrop {
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0.3;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:before, &:after {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 0;
|
||||
content: ' ';
|
||||
height: 25px;
|
||||
width: 2px;
|
||||
background-color: #333;
|
||||
}
|
||||
&:before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
&:after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-body {
|
||||
margin-top: 24px;
|
||||
|
||||
progress {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
padding-left: inherit;
|
||||
padding-right: inherit;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
button {
|
||||
margin: 10px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,54 @@
|
|||
<div id="espinstaller">
|
||||
<!--
|
||||
// Wizard screens
|
||||
// - Menu (installerMenu)
|
||||
// - Verify user wants to install (installerVerify)
|
||||
// - erase flash (installerErase)
|
||||
// - if esp32 or c3 flash bin (installerFlash)
|
||||
// - if s2 or s3, flash bootloader (installerFlash)
|
||||
// - if s2 or s3, copy uf2 (May need to use File System Access API)
|
||||
// - request wifi credentials (skip, connect buttons) and AP password
|
||||
// - generate and program settings.toml via REPL
|
||||
// - install complete
|
||||
-->
|
||||
|
||||
<dialog class="installer" id="installerMenu">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerVerify">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerErase">
|
||||
|
||||
</dialog>
|
||||
|
||||
<!-- Used for flashing either bin or uf2 -->
|
||||
<dialog class="installer" id="installerFlash">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerCopyUf2">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerCredentials">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerGenerateSettings">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerSuccess">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog class="installer" id="installerError">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog id="installerDialog">
|
||||
<main class="main">
|
||||
<div id="notSupported" class="notSupported">
|
||||
Sorry, <b>Web Serial</b> is not supported on your browser at this time. Browsers we expect to work:
|
||||
|
|
@ -94,4 +144,4 @@
|
|||
|
||||
<div id="log" class="hidden console-item"></div>
|
||||
</main>
|
||||
</div>
|
||||
</dialog>
|
||||
1321
cpinstaller/src/cpinstaller.js
Normal file
1321
cpinstaller/src/cpinstaller.js
Normal file
File diff suppressed because it is too large
Load diff
0
cpinstaller/src/dialogs.json
Normal file
0
cpinstaller/src/dialogs.json
Normal file
1
cpinstaller/src/img/close_button.svg
Normal file
1
cpinstaller/src/img/close_button.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#fff;opacity:0;}.cls-2{fill:#231f20;}</style></defs><title>close</title><g id="Layer_2" data-name="Layer 2"><g id="close"><g id="close-2" data-name="close"><rect class="cls-1" width="24" height="24" transform="translate(24 24) rotate(180)"/><path class="cls-2" d="M13.41,12l4.3-4.29a1,1,0,1,0-1.42-1.42L12,10.59,7.71,6.29A1,1,0,0,0,6.29,7.71L10.59,12l-4.3,4.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L12,13.41l4.29,4.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42Z"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 553 B |
|
|
@ -48,28 +48,50 @@ const full_bin_program = [stage_erase_all, stage_flash_cpbin, stage_program_sett
|
|||
const full_uf2_program = [stage_erase_all, stage_flash_bootloader, stage_copy_uf2, stage_program_settings];
|
||||
const factory_reset_program = [stage_erase_all, stage_flash_bootloader];
|
||||
|
||||
// Wizard screens
|
||||
// - Menu
|
||||
// - Verify user wants to install
|
||||
// - erase flash
|
||||
// - if esp32 or c3 flash bin
|
||||
// - if s2 or s3, flash bootloader
|
||||
// - if s2 or s3, copy uf2 (May need to use File System Access API)
|
||||
// - request wifi credentials (skip, connect buttons) and AP password
|
||||
// - generate and program settings.toml via REPL
|
||||
// - install complete
|
||||
|
||||
// So we will have a couple of wizard flows and we'll need to associate the flow with the board
|
||||
// We should add the info to the board's page in the boards folder
|
||||
|
||||
// Changes to make:
|
||||
// Hide the log and make it accessible via the menu
|
||||
// Generate dialogs on the fly
|
||||
// Make a drop-in component
|
||||
// Keep in mind it will be used for LEARN too
|
||||
// May need to deal with CORS issues
|
||||
// May need to deal with the fact that the ESPTool uses Web Serial and CircuitPython REPL uses Web Serial
|
||||
|
||||
|
||||
const maxLogLength = 100;
|
||||
const log = document.getElementById("log");
|
||||
const semverLabel = document.getElementById("semver");
|
||||
const butShowConsole = document.getElementById("butShowConsole");
|
||||
const consoleItems = document.getElementsByClassName("console-item");
|
||||
const butConnect = document.getElementById("butConnect");
|
||||
const binSelector = document.getElementById("binSelector");
|
||||
const baudRate = document.getElementById("baudRate");
|
||||
const butClear = document.getElementById("butClear");
|
||||
const butProgram = document.getElementById("butProgram");
|
||||
const butProgramBootloader = document.getElementById("butProgramBootloader");
|
||||
const autoscroll = document.getElementById("autoscroll");
|
||||
const lightSS = document.getElementById("light");
|
||||
const darkSS = document.getElementById("dark");
|
||||
const darkMode = document.getElementById("darkmode");
|
||||
const installerDialog = document.getElementById('installerDialog');
|
||||
const butInstallers = document.getElementsByClassName("installer-button");
|
||||
|
||||
const log = installerDialog.querySelector("#log");
|
||||
const semverLabel = installerDialog.querySelector("#semver");
|
||||
//const butShowConsole = installerDialog.querySelector("#butShowConsole");
|
||||
const consoleItems = installerDialog.getElementsByClassName("console-item");
|
||||
const butConnect = installerDialog.querySelector("#butConnect");
|
||||
const binSelector = installerDialog.querySelector("#binSelector");
|
||||
const baudRate = installerDialog.querySelector("#baudRate");
|
||||
const butClear = installerDialog.querySelector("#butClear");
|
||||
const butProgram = installerDialog.querySelector("#butProgram");
|
||||
const butProgramBootloader = installerDialog.querySelector("#butProgramBootloader");
|
||||
const autoscroll = installerDialog.querySelector("#autoscroll");
|
||||
|
||||
// TODO: This should grab the stuff for settings.toml
|
||||
const partitionData = document.querySelectorAll(".field input.partition-data");
|
||||
|
||||
const progress = document.getElementById("progressBar");
|
||||
const stepname = document.getElementById("stepname");
|
||||
const appDiv = document.getElementById("app");
|
||||
const partitionData = installerDialog.querySelectorAll(".field input.partition-data");
|
||||
const progress = installerDialog.querySelector("#progressBar");
|
||||
const stepname = installerDialog.querySelector("#stepname");
|
||||
const appDiv = installerDialog.querySelector("#app");
|
||||
|
||||
const disableWhileBusy = [partitionData, butProgram, butProgramBootloader, baudRate];
|
||||
|
||||
|
|
@ -79,7 +101,6 @@ let debug;
|
|||
// querystring options
|
||||
const QUERYSTRING_BOARD_KEY = 'board'
|
||||
const QUERYSTRING_DEBUG_KEY = 'debug'
|
||||
const QUERYSTRING_STAGING_KEY = 'staging'
|
||||
|
||||
function getFromQuerystring(key) {
|
||||
const location = new URL(document.location)
|
||||
|
|
@ -87,6 +108,15 @@ function getFromQuerystring(key) {
|
|||
return params.get(key)
|
||||
}
|
||||
|
||||
for (let installer of butInstallers) {
|
||||
installer.addEventListener("click", (e) => {
|
||||
let installerName = e.target.id;
|
||||
installerDialog.showModal();
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// detect debug setting from querystring
|
||||
debug = getFromQuerystring(QUERYSTRING_DEBUG_KEY);
|
||||
|
|
@ -101,11 +131,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
debug = getArgs["debug"] == "1" || getArgs["debug"].toLowerCase() == "true";
|
||||
}
|
||||
|
||||
butShowConsole.addEventListener("click", () => {
|
||||
/*butShowConsole.addEventListener("click", () => {
|
||||
showConsole = !showConsole
|
||||
saveSetting("showConsole", showConsole)
|
||||
toggleConsole(showConsole)
|
||||
})
|
||||
})*/
|
||||
|
||||
// register dom event listeners
|
||||
butConnect.addEventListener("click", () => {
|
||||
|
|
@ -127,17 +157,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
toggleUIConnected(false);
|
||||
});
|
||||
});
|
||||
butClear.addEventListener("click", clickClear);
|
||||
//butClear.addEventListener("click", clickClear);
|
||||
butProgram.addEventListener("click", clickProgram);
|
||||
butProgramNvm.addEventListener("click", clickProgramNvm);
|
||||
butProgramBootloader.addEventListener("click", clickProgramNvm);
|
||||
for (let i = 0; i < partitionData.length; i++) {
|
||||
partitionData[i].addEventListener("change", checkProgrammable);
|
||||
partitionData[i].addEventListener("keydown", checkProgrammable);
|
||||
partitionData[i].addEventListener("input", checkProgrammable);
|
||||
}
|
||||
autoscroll.addEventListener("click", clickAutoscroll);
|
||||
baudRate.addEventListener("change", changeBaudRate);
|
||||
darkMode.addEventListener("click", clickDarkMode);
|
||||
//autoscroll.addEventListener("click", clickAutoscroll);
|
||||
//baudRate.addEventListener("change", changeBaudRate);
|
||||
|
||||
// handle runaway errors
|
||||
window.addEventListener("error", event => {
|
||||
|
|
@ -155,10 +184,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
notSupported.classList.add("hidden");
|
||||
}
|
||||
|
||||
initBinSelector();
|
||||
initBaudRate();
|
||||
//initBinSelector();
|
||||
//initBaudRate();
|
||||
loadAllSettings();
|
||||
updateTheme();
|
||||
logMsg("CircuitPython ESP32 Installer loaded.");
|
||||
checkProgrammable();
|
||||
});
|
||||
|
|
@ -171,7 +199,7 @@ function createOption(value, text) {
|
|||
}
|
||||
|
||||
let latestFirmwares = []
|
||||
async function initBinSelector() {
|
||||
/*async function initBinSelector() {
|
||||
// fetch firmware index from io-rails, a list of available littlefs
|
||||
// firmware items, like the example above
|
||||
const response = await fetch(`${FIRMWARE_API}/wipper_releases`)
|
||||
|
|
@ -212,7 +240,7 @@ function populateBinSelector(title, filter=() => true) {
|
|||
})
|
||||
|
||||
return any
|
||||
}
|
||||
}*/
|
||||
|
||||
function returnToStepOne() {
|
||||
showStep(1, { hideHigherSteps: false });
|
||||
|
|
@ -301,7 +329,7 @@ function toggleConsole(show) {
|
|||
consoleItems.item(idx).classList[consoleItemsMethod]("hidden")
|
||||
}
|
||||
// toggle the button
|
||||
butShowConsole.checked = show
|
||||
//butShowConsole.checked = show
|
||||
// tell the app if it's sharing space with the console
|
||||
const appDivMethod = show ? "add" : "remove"
|
||||
appDiv.classList[appDivMethod]("with-console")
|
||||
|
|
@ -376,9 +404,9 @@ function logMsg(text) {
|
|||
log.innerHTML = logLines.splice(-maxLogLength).join("<br>\n");
|
||||
}
|
||||
|
||||
if (autoscroll.checked) {
|
||||
/*if (autoscroll.checked) {
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
function debugMsg(...args) {
|
||||
|
|
@ -454,27 +482,6 @@ function formatMacAddr(macAddr) {
|
|||
return macAddr.map((value) => value.toString(16).toUpperCase().padStart(2, "0")).join(":");
|
||||
}
|
||||
|
||||
/**
|
||||
* @name updateTheme
|
||||
* Sets the theme to Adafruit (dark) mode. Can be refactored later for more themes
|
||||
*/
|
||||
function updateTheme() {
|
||||
// Disable all themes
|
||||
document.querySelectorAll("link[rel=stylesheet].alternate").forEach((styleSheet) => {
|
||||
enableStyleSheet(styleSheet, false);
|
||||
});
|
||||
|
||||
if (darkMode.checked) {
|
||||
enableStyleSheet(darkSS, true);
|
||||
} else {
|
||||
enableStyleSheet(lightSS, true);
|
||||
}
|
||||
}
|
||||
|
||||
function enableStyleSheet(node, enabled) {
|
||||
node.disabled = !enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name reset
|
||||
* Reset the Panels, Log, and associated data
|
||||
|
|
@ -618,15 +625,6 @@ async function clickAutoscroll() {
|
|||
saveSetting("autoscroll", autoscroll.checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickDarkMode
|
||||
* Change handler for the Dark Mode checkbox.
|
||||
*/
|
||||
async function clickDarkMode() {
|
||||
updateTheme();
|
||||
saveSetting("darkmode", darkMode.checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickProgram
|
||||
* Click handler for the program button.
|
||||
|
|
@ -643,10 +641,6 @@ async function clickProgramNvm() {
|
|||
await programScript(factory_reset_program);
|
||||
}
|
||||
|
||||
function stagingFlagSet() {
|
||||
return getFromQuerystring(QUERYSTRING_STAGING_KEY)
|
||||
}
|
||||
|
||||
async function populateSecretsFile(path) {
|
||||
let response = await fetch(path);
|
||||
let contents = await response.json();
|
||||
|
|
@ -662,10 +656,6 @@ async function populateSecretsFile(path) {
|
|||
}
|
||||
}
|
||||
|
||||
// add "io_url" property to json root with the staging url override
|
||||
if(stagingFlagSet()) {
|
||||
updateObject(contents, 'io_url', 'io.adafruit.us')
|
||||
}
|
||||
// Convert the data to text and return
|
||||
return JSON.stringify(contents, null, 4);
|
||||
}
|
||||
|
|
@ -831,8 +821,11 @@ async function programScript(stages) {
|
|||
}
|
||||
} else if (stages[i] == stage_program_settings) {
|
||||
// TODO: This needs to be rewritten to talk with circuitpython
|
||||
// and run python code via the repl to write a settings.toml file
|
||||
// See https://learn.adafruit.com/circuitpython-with-esp32-quick-start/setting-up-web-workflow
|
||||
// and https://github.com/circuitpython/web-editor/pull/46
|
||||
steps.push({
|
||||
name: "Generating and Flashing LittleFS Partition",
|
||||
name: "Generating and Writing the WiFi Settings",
|
||||
func: async function (params) {
|
||||
let fileSystemImage = await generate(params.flashParams);
|
||||
|
||||
|
|
@ -914,11 +907,10 @@ async function programScript(stages) {
|
|||
function getValidFields() {
|
||||
// Validate user inputs
|
||||
const validFields = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const { id, value } = partitionData[i]
|
||||
// password & brightness can be blank, the rest must have some value
|
||||
if (id === "network_type_wifi.network_password" ||
|
||||
id === "status_pixel_brightness" ||
|
||||
value.length > 0) {
|
||||
validFields.push(i);
|
||||
}
|
||||
|
|
@ -938,29 +930,6 @@ async function checkProgrammable() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name checkFirmware
|
||||
* Handler for firmware upload changes
|
||||
*/
|
||||
async function checkFirmware(event) {
|
||||
let filename = event.target.value.split("\\").pop();
|
||||
let label = event.target.parentNode.querySelector("span");
|
||||
let icon = event.target.parentNode.querySelector("svg");
|
||||
if (filename != "") {
|
||||
if (filename.length > 17) {
|
||||
label.innerHTML = filename.substring(0, 14) + "…";
|
||||
} else {
|
||||
label.innerHTML = filename;
|
||||
}
|
||||
icon.classList.add("hidden");
|
||||
} else {
|
||||
label.innerHTML = "Choose a file…";
|
||||
icon.classList.remove("hidden");
|
||||
}
|
||||
|
||||
await checkProgrammable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickClear
|
||||
* Click handler for the clear button.
|
||||
|
|
@ -997,9 +966,8 @@ function toggleUIConnected(connected) {
|
|||
|
||||
function loadAllSettings() {
|
||||
// Load all saved settings or defaults
|
||||
autoscroll.checked = loadSetting("autoscroll", true);
|
||||
baudRate.value = loadSetting("baudrate", baudRates[0]);
|
||||
darkMode.checked = loadSetting("darkmode", false);
|
||||
//autoscroll.checked = loadSetting("autoscroll", true);
|
||||
//baudRate.value = loadSetting("baudrate", baudRates[0]);
|
||||
showConsole = loadSetting('showConsole', false);
|
||||
toggleConsole(showConsole);
|
||||
}
|
||||
Loading…
Reference in a new issue