feat: Most settings implemented
This commit is contained in:
parent
f8c2f4f228
commit
98ad7d1432
41 changed files with 1976 additions and 421 deletions
259
src/lib/components/sections/FirmwareUpdateSection.svelte
Normal file
259
src/lib/components/sections/FirmwareUpdateSection.svelte
Normal file
|
@ -0,0 +1,259 @@
|
|||
<script lang="ts">
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import { CardContainer, Alert } from '$lib/components';
|
||||
import { getFirmwareBinaryName, getWebUiBinaryName } from '$lib/utils';
|
||||
import { status, settings, firmwareRelease } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { uploadFirmwareFile, uploadWebUiFile, autoUpdate } from '$lib/clockControl';
|
||||
|
||||
// Format date to a more readable format
|
||||
function formatDate(dateString: string): string {
|
||||
if (!dateString) return '';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
// Upload status
|
||||
let firmwareUploadProgress = 0;
|
||||
let webuiUploadProgress = 0;
|
||||
let isUploading = false;
|
||||
let uploadError: string | null = null;
|
||||
let uploadSuccess = false;
|
||||
let countdownValue = 0;
|
||||
let countdownInterval: number | null = null;
|
||||
|
||||
// File selection status
|
||||
let firmwareFileSelected = false;
|
||||
let webuiFileSelected = false;
|
||||
|
||||
// Handle file selection change for firmware file
|
||||
function handleFirmwareFileChange(event: Event) {
|
||||
const fileInput = event.target as HTMLInputElement;
|
||||
firmwareFileSelected = !!(fileInput.files && fileInput.files.length > 0);
|
||||
}
|
||||
|
||||
// Handle file selection change for WebUI file
|
||||
function handleWebUIFileChange(event: Event) {
|
||||
const fileInput = event.target as HTMLInputElement;
|
||||
webuiFileSelected = !!(fileInput.files && fileInput.files.length > 0);
|
||||
}
|
||||
|
||||
// Start countdown to reload page after successful upload
|
||||
function startCountdownToReload(seconds: number) {
|
||||
countdownValue = seconds;
|
||||
if (countdownInterval) clearInterval(countdownInterval);
|
||||
|
||||
countdownInterval = setInterval(() => {
|
||||
countdownValue--;
|
||||
if (countdownValue <= 0) {
|
||||
if (countdownInterval) clearInterval(countdownInterval);
|
||||
window.location.reload();
|
||||
}
|
||||
}, 1000) as unknown as number;
|
||||
}
|
||||
|
||||
// Handle firmware file upload
|
||||
function handleFirmwareUpload() {
|
||||
const fileInput = document.getElementById('firmwareFile') as HTMLInputElement;
|
||||
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
||||
uploadError = 'Please select a firmware file';
|
||||
return;
|
||||
}
|
||||
|
||||
isUploading = true;
|
||||
uploadError = null;
|
||||
uploadSuccess = false;
|
||||
firmwareUploadProgress = 0;
|
||||
|
||||
uploadFirmwareFile(fileInput.files[0], {
|
||||
onProgress: (progress) => {
|
||||
firmwareUploadProgress = progress;
|
||||
},
|
||||
onSuccess: () => {
|
||||
isUploading = false;
|
||||
uploadSuccess = true;
|
||||
startCountdownToReload(10);
|
||||
},
|
||||
onError: (error) => {
|
||||
isUploading = false;
|
||||
uploadError =
|
||||
typeof error === 'string' && error !== 'FAIL' ? error : 'Failed to upload firmware';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle webUI file upload
|
||||
function handleWebUIUpload() {
|
||||
const fileInput = document.getElementById('webuiFile') as HTMLInputElement;
|
||||
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
||||
uploadError = 'Please select a WebUI file';
|
||||
return;
|
||||
}
|
||||
|
||||
isUploading = true;
|
||||
uploadError = null;
|
||||
uploadSuccess = false;
|
||||
webuiUploadProgress = 0;
|
||||
|
||||
uploadWebUiFile(fileInput.files[0], {
|
||||
onProgress: (progress) => {
|
||||
webuiUploadProgress = progress;
|
||||
},
|
||||
onSuccess: () => {
|
||||
isUploading = false;
|
||||
uploadSuccess = true;
|
||||
startCountdownToReload(10);
|
||||
},
|
||||
onError: (error) => {
|
||||
isUploading = false;
|
||||
uploadError = typeof error === 'string' ? error : 'Failed to upload WebUI';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const onAutoUpdate = (e: Event) => {
|
||||
e.preventDefault();
|
||||
autoUpdate({
|
||||
onSuccess: () => {
|
||||
// toast.push({
|
||||
// type: 'success',
|
||||
// message
|
||||
// });
|
||||
startCountdownToReload(10);
|
||||
},
|
||||
onError: (error) => {
|
||||
// toast.push({
|
||||
// type: 'error',
|
||||
// message: error as string
|
||||
// });
|
||||
uploadError = typeof error === 'string' ? error : 'Failed to auto-update';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Fetch firmware data when component is mounted
|
||||
onMount(() => {
|
||||
firmwareRelease.fetchLatest();
|
||||
|
||||
// Cleanup on component destroy
|
||||
return () => {
|
||||
if (countdownInterval) clearInterval(countdownInterval);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<CardContainer title={m['section.control.firmwareUpdate']()} className="">
|
||||
<div>
|
||||
{#if $firmwareRelease.isLoading}
|
||||
<div class="my-4 flex justify-center">
|
||||
<span class="loading loading-spinner"></span>
|
||||
</div>
|
||||
{:else if $firmwareRelease.error}
|
||||
<Alert type="error" className="mb-4" message={$firmwareRelease.error} />
|
||||
{:else}
|
||||
<p class="mb-2 text-sm">
|
||||
{m['section.firmwareUpdater.latestVersion']()}
|
||||
{$firmwareRelease.tag_name} - {m['section.firmwareUpdater.releaseDate']()}
|
||||
{formatDate($firmwareRelease.published_at)} -
|
||||
<a
|
||||
href={$firmwareRelease.html_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link link-primary"
|
||||
>
|
||||
{m['section.firmwareUpdater.viewRelease']()}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
{#if !$status.isOTAUpdating && $settings.gitTag !== $firmwareRelease.tag_name}
|
||||
<Alert type="success" className="mb-4">
|
||||
{m['section.firmwareUpdater.swUpdateAvailable']()}
|
||||
{$settings.gitTag} → {$firmwareRelease.tag_name} -
|
||||
<a href="/" class="link link-primary" on:click={onAutoUpdate}
|
||||
>{m['section.firmwareUpdater.autoUpdate']()}</a
|
||||
>.
|
||||
</Alert>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if !$status.isOTAUpdating}
|
||||
<div class="form-control mb-4">
|
||||
<label class="label" for="firmwareFile">
|
||||
<span class="label-text">Firmware File ({getFirmwareBinaryName($settings.hwRev)})</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="file"
|
||||
class="file-input file-input-bordered w-full"
|
||||
id="firmwareFile"
|
||||
accept=".bin"
|
||||
disabled={isUploading}
|
||||
on:change={handleFirmwareFileChange}
|
||||
/>
|
||||
<button
|
||||
class="btn btn-primary w-1/4"
|
||||
on:click={handleFirmwareUpload}
|
||||
disabled={isUploading || !firmwareFileSelected}
|
||||
>
|
||||
{#if isUploading && firmwareUploadProgress > 0}
|
||||
{firmwareUploadProgress}%
|
||||
{:else}
|
||||
{m['section.control.firmwareUpdate']()}
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{#if isUploading && firmwareUploadProgress > 0}
|
||||
<progress class="progress progress-primary mt-2" value={firmwareUploadProgress} max="100"
|
||||
></progress>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="webuiFile">
|
||||
<span class="label-text">WebUI File ({getWebUiBinaryName($settings.hwRev)})</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="file"
|
||||
class="file-input file-input-bordered w-full"
|
||||
id="webuiFile"
|
||||
accept=".bin"
|
||||
disabled={isUploading}
|
||||
on:change={handleWebUIFileChange}
|
||||
/>
|
||||
<button
|
||||
class="btn btn-primary w-1/4"
|
||||
on:click={handleWebUIUpload}
|
||||
disabled={isUploading || !webuiFileSelected}
|
||||
>
|
||||
{#if isUploading && webuiUploadProgress > 0}
|
||||
{webuiUploadProgress}%
|
||||
{:else}
|
||||
Update WebUI
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{#if isUploading && webuiUploadProgress > 0}
|
||||
<progress class="progress progress-primary mt-2" value={webuiUploadProgress} max="100"
|
||||
></progress>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Alert type="info" className="my-4">
|
||||
<span class="loading loading-spinner text-neutral"></span>
|
||||
{m['section.firmwareUpdater.autoUpdateInProgress']()}
|
||||
</Alert>
|
||||
{/if}
|
||||
{#if uploadSuccess}
|
||||
<Alert type="success" className="my-4">
|
||||
{m['section.firmwareUpdater.fileUploadSuccess']({ countdown: countdownValue })}
|
||||
</Alert>
|
||||
{:else if uploadError}
|
||||
<Alert type="error" className="my-4">
|
||||
{uploadError}
|
||||
</Alert>
|
||||
{/if}
|
||||
<Alert type="warning" className="mt-4">
|
||||
{m['section.firmwareUpdater.firmwareUpdateText']()}
|
||||
</Alert>
|
||||
</div>
|
||||
</CardContainer>
|
Loading…
Add table
Add a link
Reference in a new issue