ota update flow

This commit is contained in:
2024-09-29 22:25:03 +02:00
parent 1d976947e1
commit 68faf57a22
3 changed files with 198 additions and 40 deletions

View File

View File

@@ -4,6 +4,29 @@
let { data } = $props();
let working = $state(false);
let success = $state(false);
let error = $state<Error | undefined>(undefined);
async function update() {
working = true;
error = undefined;
success = false;
const port = $serialPort!;
$serialPort = undefined;
try {
const file = await fetch(otaUrl!).then((it) => it.blob());
await port.updateFirmware(file);
success = true;
} catch (e) {
error = e as Error;
} finally {
working = false;
}
}
let currentDevice = $derived(
$serialPort
? `${$serialPort.device.toLowerCase()}_${$serialPort.chipset.toLowerCase()}`
@@ -78,7 +101,29 @@
<section>
<h3>OTA Upate</h3>
{#if data.ota}
<p>OTA update</p>
<button
class:working
class:primary={!error}
class:error={error || (!success && isCorrectDevice === false)}
disabled={working || $serialPort === undefined || !isCorrectDevice}
onclick={update}>Apply Update</button
>
{#if $serialPort}
<div transition:slide>
Your device is ready and compatible. Click the button to perform the
update.
</div>
{:else if success}
<div class="primary" transition:slide>Update successful</div>
{:else if error}
<div class="error" transition:slide>{error.message}</div>
{:else if working}
<div class="primary" transition:slide>Updating your device...</div>
{:else}
<div class="primary" transition:slide>
Connect your device to continue
</div>
{/if}
{:else}
<em>There are no OTA files for this device.</em>
{/if}
@@ -101,6 +146,7 @@
<h4>Via Serial</h4>
<p>WIP</p>
</section>
ading 0 Chordmaps.
</div>
<style lang="scss">
@@ -109,6 +155,84 @@
transition: color 200ms ease;
}
.error {
color: var(--md-sys-color-error);
}
.primary {
color: var(--md-sys-color-primary);
}
@keyframes rotate {
0% {
transform: rotate(120deg);
opacity: 0;
}
20% {
transform: rotate(120deg);
opacity: 0;
}
60% {
opacity: 1;
}
100% {
transform: rotate(270deg);
opacity: 0;
}
}
button {
overflow: hidden;
position: relative;
height: 42px;
border: 2px solid currentcolor;
border-radius: 8px;
outline: 2px dashed currentcolor;
outline-offset: 4px;
background: var(--md-sys-color-background);
transition:
border 200ms ease,
color 200ms ease;
margin: 6px;
margin-block: 16px;
&.primary {
color: var(--md-sys-color-primary);
background: none;
}
&.working {
border-color: transparent;
}
&.working::before {
z-index: -1;
position: absolute;
background: var(--md-sys-color-background);
width: calc(100% - 4px);
height: calc(100% - 4px);
border-radius: 8px;
content: "";
}
&.working::after {
z-index: -2;
position: absolute;
content: "";
background: var(--md-sys-color-primary);
animation: rotate 1s ease-out forwards infinite;
height: 30%;
width: 120%;
}
}
hr {
color: var(--md-sys-color-outline);
margin-block: 3em;