Dialog wizard groundwork mostly working

This commit is contained in:
Melissa LeBlanc-Williams 2023-01-10 18:36:51 -08:00
parent 79de9d5aa2
commit c0c01ec808
10 changed files with 1526 additions and 113 deletions

View file

@ -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>

View file

@ -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>

View file

@ -21,3 +21,4 @@
@import 'pages/stats';
@import 'pages/libraries';
@import 'pages/contributing';
@import 'pages/espinstaller';

View file

@ -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;

View 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;
}
}
}

View file

@ -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>

File diff suppressed because it is too large Load diff

View file

View 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

View file

@ -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) + "&hellip;";
} else {
label.innerHTML = filename;
}
icon.classList.add("hidden");
} else {
label.innerHTML = "Choose a file&hellip;";
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);
}