Allow prompting for erase (#134)

This commit is contained in:
Paulus Schoutsen 2021-11-30 08:42:59 -08:00 committed by GitHub
parent 10816b5166
commit c4daee18bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 159 additions and 75 deletions

View File

@ -329,7 +329,7 @@
"name": "ESPHome",
"version": "2021.11.0",
"home_assistant_domain": "esphome",
"new_install_skip_erase": false,
"new_install_prompt_erase": false,
"builds": [
{
"chipFamily": "ESP32",
@ -350,7 +350,7 @@
}</pre
>
<p>
Each build contains a list of parts to be flashed to the ESP device.
Each build contains a list of parts to be installed to the ESP device.
Each part consists of a path to the file and an offset on the flash
where it should be installed. Part paths are resolved relative to the
path of the manifest, but can also be URLs to other hosts.
@ -361,12 +361,12 @@
Tools will link the user to add this device to Home Assistant.
</p>
<p>
By default a new installation will erase the entire flash. If you want
to skip this step, set the optional key
<code>new_install_skip_erase</code> to <code>true</code>. ESP Web Tools
offers users a new installation if it is unable to detect the current
firmware of the device (via Improv Serial) or if the detected firmware
does not match the name specififed in the manifest.
By default a new installation will erase all data before installation.
If you want to leave this choice to the user, set the optional key
<code>new_install_prompt_erase</code> to <code>true</code>. ESP Web
Tools offers users a new installation if it is unable to detect the
current firmware of the device (via Improv Serial) or if the detected
firmware does not match the name specififed in the manifest.
</p>
<h2 id="improv">Configuring Wi-Fi</h2>
<p>

104
package-lock.json generated
View File

@ -13,8 +13,8 @@
"@material/mwc-checkbox": "^0.25.3",
"@material/mwc-circular-progress": "^0.25.3",
"@material/mwc-dialog": "^0.25.3",
"@material/mwc-formfield": "^0.25.3",
"@material/mwc-icon-button": "^0.25.3",
"@material/mwc-linear-progress": "^0.25.1",
"@material/mwc-textfield": "^0.25.3",
"esp-web-flasher": "^4.0.0",
"improv-wifi-serial-sdk": "^2.1.0",
@ -188,6 +188,20 @@
"tslib": "^2.1.0"
}
},
"node_modules/@material/form-field": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-14.0.0-canary.261f2db59.0.tgz",
"integrity": "sha512-NCc/o60gwuF28PVMgFkHrKcHxIaCMZK9JRVfoaD0sF2BINYrjaCkFZ+x6AhNjAWLUQMhJMfc+1WXAUE2T85Mug==",
"dependencies": {
"@material/base": "14.0.0-canary.261f2db59.0",
"@material/feature-targeting": "14.0.0-canary.261f2db59.0",
"@material/ripple": "14.0.0-canary.261f2db59.0",
"@material/rtl": "14.0.0-canary.261f2db59.0",
"@material/theme": "14.0.0-canary.261f2db59.0",
"@material/typography": "14.0.0-canary.261f2db59.0",
"tslib": "^2.1.0"
}
},
"node_modules/@material/icon-button": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-14.0.0-canary.261f2db59.0.tgz",
@ -216,20 +230,6 @@
"tslib": "^2.1.0"
}
},
"node_modules/@material/linear-progress": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-14.0.0-canary.261f2db59.0.tgz",
"integrity": "sha512-qP/iI4CT7i7HhXuUiNWL5pDN6tyTJ4uLl8e9QImz4mcQLUMU3xrNBIsutS+I5GnBE8FwLDozZFccfCxHh+pvzw==",
"dependencies": {
"@material/animation": "14.0.0-canary.261f2db59.0",
"@material/base": "14.0.0-canary.261f2db59.0",
"@material/feature-targeting": "14.0.0-canary.261f2db59.0",
"@material/progress-indicator": "14.0.0-canary.261f2db59.0",
"@material/rtl": "14.0.0-canary.261f2db59.0",
"@material/theme": "14.0.0-canary.261f2db59.0",
"tslib": "^2.1.0"
}
},
"node_modules/@material/mwc-base": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-base/-/mwc-base-0.25.3.tgz",
@ -301,6 +301,17 @@
"tslib": "^2.0.1"
}
},
"node_modules/@material/mwc-formfield": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-formfield/-/mwc-formfield-0.25.3.tgz",
"integrity": "sha512-JP/ZgsWok0ZVwUQfYgaov0Ocn1zDiiw7Po6q8k/n5tOS67S41XUB/ctiUg1gh00LAM0v3eZAexa9ZmKarviVJA==",
"dependencies": {
"@material/form-field": "=14.0.0-canary.261f2db59.0",
"@material/mwc-base": "^0.25.3",
"lit": "^2.0.0",
"tslib": "^2.0.1"
}
},
"node_modules/@material/mwc-icon": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-icon/-/mwc-icon-0.25.3.tgz",
@ -330,18 +341,6 @@
"tslib": "^2.0.1"
}
},
"node_modules/@material/mwc-linear-progress": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-linear-progress/-/mwc-linear-progress-0.25.3.tgz",
"integrity": "sha512-iAsM5zo78rYXXzwEg1RT0+jShxkUjOEUK0Yj6KxqxbXy1VKPTZ4HRB5Fy6wChWQi/Xl8wFlfI6nNAQtH7pakeA==",
"dependencies": {
"@material/linear-progress": "=14.0.0-canary.261f2db59.0",
"@material/mwc-base": "^0.25.3",
"@material/theme": "=14.0.0-canary.261f2db59.0",
"lit": "^2.0.0",
"tslib": "^2.0.1"
}
},
"node_modules/@material/mwc-notched-outline": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-notched-outline/-/mwc-notched-outline-0.25.3.tgz",
@ -2060,6 +2059,20 @@
"tslib": "^2.1.0"
}
},
"@material/form-field": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-14.0.0-canary.261f2db59.0.tgz",
"integrity": "sha512-NCc/o60gwuF28PVMgFkHrKcHxIaCMZK9JRVfoaD0sF2BINYrjaCkFZ+x6AhNjAWLUQMhJMfc+1WXAUE2T85Mug==",
"requires": {
"@material/base": "14.0.0-canary.261f2db59.0",
"@material/feature-targeting": "14.0.0-canary.261f2db59.0",
"@material/ripple": "14.0.0-canary.261f2db59.0",
"@material/rtl": "14.0.0-canary.261f2db59.0",
"@material/theme": "14.0.0-canary.261f2db59.0",
"@material/typography": "14.0.0-canary.261f2db59.0",
"tslib": "^2.1.0"
}
},
"@material/icon-button": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-14.0.0-canary.261f2db59.0.tgz",
@ -2088,20 +2101,6 @@
"tslib": "^2.1.0"
}
},
"@material/linear-progress": {
"version": "14.0.0-canary.261f2db59.0",
"resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-14.0.0-canary.261f2db59.0.tgz",
"integrity": "sha512-qP/iI4CT7i7HhXuUiNWL5pDN6tyTJ4uLl8e9QImz4mcQLUMU3xrNBIsutS+I5GnBE8FwLDozZFccfCxHh+pvzw==",
"requires": {
"@material/animation": "14.0.0-canary.261f2db59.0",
"@material/base": "14.0.0-canary.261f2db59.0",
"@material/feature-targeting": "14.0.0-canary.261f2db59.0",
"@material/progress-indicator": "14.0.0-canary.261f2db59.0",
"@material/rtl": "14.0.0-canary.261f2db59.0",
"@material/theme": "14.0.0-canary.261f2db59.0",
"tslib": "^2.1.0"
}
},
"@material/mwc-base": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-base/-/mwc-base-0.25.3.tgz",
@ -2173,6 +2172,17 @@
"tslib": "^2.0.1"
}
},
"@material/mwc-formfield": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-formfield/-/mwc-formfield-0.25.3.tgz",
"integrity": "sha512-JP/ZgsWok0ZVwUQfYgaov0Ocn1zDiiw7Po6q8k/n5tOS67S41XUB/ctiUg1gh00LAM0v3eZAexa9ZmKarviVJA==",
"requires": {
"@material/form-field": "=14.0.0-canary.261f2db59.0",
"@material/mwc-base": "^0.25.3",
"lit": "^2.0.0",
"tslib": "^2.0.1"
}
},
"@material/mwc-icon": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-icon/-/mwc-icon-0.25.3.tgz",
@ -2202,18 +2212,6 @@
"tslib": "^2.0.1"
}
},
"@material/mwc-linear-progress": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-linear-progress/-/mwc-linear-progress-0.25.3.tgz",
"integrity": "sha512-iAsM5zo78rYXXzwEg1RT0+jShxkUjOEUK0Yj6KxqxbXy1VKPTZ4HRB5Fy6wChWQi/Xl8wFlfI6nNAQtH7pakeA==",
"requires": {
"@material/linear-progress": "=14.0.0-canary.261f2db59.0",
"@material/mwc-base": "^0.25.3",
"@material/theme": "=14.0.0-canary.261f2db59.0",
"lit": "^2.0.0",
"tslib": "^2.0.1"
}
},
"@material/mwc-notched-outline": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@material/mwc-notched-outline/-/mwc-notched-outline-0.25.3.tgz",

View File

@ -25,8 +25,8 @@
"@material/mwc-checkbox": "^0.25.3",
"@material/mwc-circular-progress": "^0.25.3",
"@material/mwc-dialog": "^0.25.3",
"@material/mwc-formfield": "^0.25.3",
"@material/mwc-icon-button": "^0.25.3",
"@material/mwc-linear-progress": "^0.25.1",
"@material/mwc-textfield": "^0.25.3",
"esp-web-flasher": "^4.0.0",
"improv-wifi-serial-sdk": "^2.1.0",

View File

@ -0,0 +1,14 @@
import { CheckboxBase } from "@material/mwc-checkbox/mwc-checkbox-base";
import { styles } from "@material/mwc-checkbox/mwc-checkbox.css";
declare global {
interface HTMLElementTagNameMap {
"ewt-checkbox": EwtCheckbox;
}
}
export class EwtCheckbox extends CheckboxBase {
static override styles = [styles];
}
customElements.define("ewt-checkbox", EwtCheckbox);

View File

@ -0,0 +1,14 @@
import { FormfieldBase } from "@material/mwc-formfield/mwc-formfield-base";
import { styles } from "@material/mwc-formfield/mwc-formfield.css";
declare global {
interface HTMLElementTagNameMap {
"ewt-formfield": EwtFormfield;
}
}
export class EwtFormfield extends FormfieldBase {
static override styles = [styles];
}
customElements.define("ewt-formfield", EwtFormfield);

View File

@ -16,7 +16,9 @@ export interface Manifest {
name: string;
version: string;
home_assistant_domain?: string;
/** @deprecated use `new_install_prompt_erase` instead */
new_install_skip_erase?: boolean;
new_install_prompt_erase?: boolean;
builds: Build[];
}

View File

@ -4,6 +4,8 @@ import "./components/ewt-dialog";
import "./components/ewt-textfield";
import "./components/ewt-button";
import "./components/ewt-icon-button";
import "./components/ewt-checkbox";
import "./components/ewt-formfield";
import "./components/ewt-circular-progress";
import type { EwtTextfield } from "./components/ewt-textfield";
import { Logger, Manifest, FlashStateType, FlashState } from "./const.js";
@ -47,6 +49,7 @@ class EwtInstallDialog extends LitElement {
| "DASHBOARD"
| "PROVISION"
| "INSTALL"
| "ASK_ERASE"
| "LOGS" = "DASHBOARD";
@state() private _installErase = false;
@ -83,6 +86,8 @@ class EwtInstallDialog extends LitElement {
}
} else if (this._state === "INSTALL") {
[heading, content, hideActions, allowClosing] = this._renderInstall();
} else if (this._state === "ASK_ERASE") {
[heading, content] = this._renderAskErase();
} else if (this._state === "ERROR") {
heading = "Error";
content = this._renderMessage(ERROR_ICON, this._error!, true);
@ -191,12 +196,15 @@ class EwtInstallDialog extends LitElement {
.label=${!this._isSameFirmware
? `Install ${this._manifest!.name}`
: `Update ${this._manifest!.name}`}
@click=${() =>
this._startInstall(
// Erase if manifest doens't force skipping it and it's not same firmware
!this._manifest.new_install_skip_erase &&
!this._isSameFirmware
)}
@click=${() => {
if (this._isSameFirmware) {
this._startInstall(false);
} else if (this._manifest.new_install_prompt_erase) {
this._state = "ASK_ERASE";
} else {
this._startInstall(true);
}
}}
></ewt-button>
</div>
`
@ -285,9 +293,14 @@ class EwtInstallDialog extends LitElement {
<div>
<ewt-button
.label=${`Install ${this._manifest.name}`}
@click=${() =>
// Erase if manifest doens't force skipping it
this._startInstall(!this._manifest.new_install_skip_erase)}
@click=${() => {
if (this._manifest.new_install_prompt_erase) {
this._state = "ASK_ERASE";
} else {
// Default is to erase a device that does not support Improv Serial
this._startInstall(true);
}
}}
></ewt-button>
</div>
@ -415,7 +428,7 @@ class EwtInstallDialog extends LitElement {
<ewt-button
slot="primaryAction"
label="Connect"
@click="${this._doProvision}"
@click=${this._doProvision}
></ewt-button>
<ewt-button
slot="secondaryAction"
@ -430,6 +443,36 @@ class EwtInstallDialog extends LitElement {
return [heading, content, hideActions];
}
_renderAskErase(): [string | undefined, TemplateResult] {
const heading = "Erase device";
const content = html`
<div>
Do you want to erase the device before installing
${this._manifest.name}? All data on the device will be lost.
</div>
<ewt-formfield label="Erase device" class="danger">
<ewt-checkbox></ewt-checkbox>
</ewt-formfield>
<ewt-button
slot="primaryAction"
label="Next"
@click=${() => {
const checkbox = this.shadowRoot!.querySelector("ewt-checkbox")!;
this._startInstall(checkbox.checked);
}}
></ewt-button>
<ewt-button
slot="secondaryAction"
label="Back"
@click=${() => {
this._state = "DASHBOARD";
}}
></ewt-button>
`;
return [heading, content];
}
_renderInstall(): [string | undefined, TemplateResult, boolean, boolean] {
let heading: string | undefined = `${
this._installConfirmed ? "Installing" : "Install"
@ -630,6 +673,14 @@ class EwtInstallDialog extends LitElement {
this._manifest = await fetch(manifestURL).then(
(resp): Promise<Manifest> => resp.json()
);
if ("new_install_skip_erase" in this._manifest) {
console.warn(
'Manifest option "new_install_skip_erase" is deprecated. Use "new_install_prompt_erase" instead.'
);
if (this._manifest.new_install_skip_erase) {
this._manifest.new_install_prompt_erase = true;
}
}
}
private async _initialize(justErased = false) {
@ -766,6 +817,10 @@ class EwtInstallDialog extends LitElement {
--mdc-dialog-max-width: 390px;
--mdc-theme-primary: var(--improv-primary-color, #03a9f4);
--mdc-theme-on-primary: var(--improv-on-primary-color, #fff);
--improv-danger-color: #db4437;
--improv-text-color: rgba(0, 0, 0, 0.6);
--mdc-theme-text-primary-on-background: var(--improv-text-color);
--mdc-dialog-content-ink-color: var(--improv-text-color);
text-align: left;
}
ewt-icon-button {
@ -775,7 +830,7 @@ class EwtInstallDialog extends LitElement {
}
table {
border-spacing: 0;
color: rgba(0, 0, 0, 0.6);
color: var(--improv-text-color);
margin-bottom: 16px;
}
table svg {
@ -817,10 +872,11 @@ class EwtInstallDialog extends LitElement {
color: black;
}
.error {
color: #db4437;
color: var(--improv-danger-color);
}
.danger {
--mdc-theme-primary: #db4437;
--mdc-theme-primary: var(--improv-danger-color);
--mdc-theme-secondary: var(--improv-danger-color);
}
button.link {
background: none;