From 0a50a9b1fa73c88fa14641a725fa5281cbabe8da Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 4 Sep 2026 16:30:58 +0200 Subject: [PATCH] update --- CHANGELOG_LATEST.md | 2 +- interface/src/api/system.ts | 3 +- interface/src/app/settings/DownloadUpload.tsx | 6 +- interface/src/app/settings/Version.tsx | 2 +- .../src/components/upload/SingleUpload.tsx | 5 +- interface/src/i18n/cs/index.ts | 10 +- interface/src/i18n/de/index.ts | 10 +- interface/src/i18n/en/index.ts | 10 +- interface/src/i18n/fr/index.ts | 10 +- interface/src/i18n/it/index.ts | 10 +- interface/src/i18n/nl/index.ts | 10 +- interface/src/i18n/no/index.ts | 10 +- interface/src/i18n/pl/index.ts | 10 +- interface/src/i18n/sk/index.ts | 10 +- interface/src/i18n/sv/index.ts | 10 +- interface/src/i18n/tr/index.ts | 10 +- interface/vite.config.ts | 3 - mock-api/{mockSSEServer.js => mockServer.js} | 109 +++++++++++++++++- mock-api/restServer.ts | 50 +------- project-words.txt | 2 +- 20 files changed, 171 insertions(+), 121 deletions(-) rename mock-api/{mockSSEServer.js => mockServer.js} (55%) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 446c7b035..fa7e77d20 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -13,7 +13,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings - option to disable factory reset [#3150](https://github.com/emsesp/EMS-ESP32/issues/3150) - TLS support with 4MB boards without PSRAM - added eth_10mbit to Network Settings, which forces 10BASE-T half-duplex & autonegotiation off, halving the PHY’s power draw. It’s off by default as it will cause issues on managed switches with a port forced to 100Mb [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213) -- cleaner MD5 and firmware uploading in WebUI [#3203](https://github.com/emsesp/EMS-ESP32/discussions/3203) +- cleaner MD5 and firmware uploading in WebUI [#3222](https://github.com/emsesp/EMS-ESP32/issues/3222) ## Fixed diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts index f12d5daa1..918929789 100644 --- a/interface/src/api/system.ts +++ b/interface/src/api/system.ts @@ -19,6 +19,7 @@ export const uploadFile = (file: File) => { const formData = new FormData(); formData.append('file', file); return alovaInstance.Post('/rest/uploadFile', formData, { - timeout: UPLOAD_TIMEOUT + timeout: UPLOAD_TIMEOUT, + enableUpload: true }); }; diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx index 24bbab1e8..3f2980451 100644 --- a/interface/src/app/settings/DownloadUpload.tsx +++ b/interface/src/app/settings/DownloadUpload.tsx @@ -165,11 +165,7 @@ const DownloadUpload = () => { {LL.UPLOAD()} - - {LL.UPLOAD_TEXT()}: - - - + ); }; diff --git a/interface/src/app/settings/Version.tsx b/interface/src/app/settings/Version.tsx index 464bfd818..61a0cff22 100644 --- a/interface/src/app/settings/Version.tsx +++ b/interface/src/app/settings/Version.tsx @@ -846,7 +846,7 @@ const Version = () => { {LL.UPLOAD()} - + )} diff --git a/interface/src/components/upload/SingleUpload.tsx b/interface/src/components/upload/SingleUpload.tsx index 134cb9918..affc3c3cb 100644 --- a/interface/src/components/upload/SingleUpload.tsx +++ b/interface/src/components/upload/SingleUpload.tsx @@ -14,9 +14,10 @@ import { LinearProgressWithLabel } from './LinearProgressWithLabel'; interface SingleUploadProps { doRestart: () => void; + text: string; } -const SingleUpload = ({ doRestart }: SingleUploadProps) => { +const SingleUpload = ({ doRestart, text }: SingleUploadProps) => { const [md5, setMd5] = useState(); const [file, setFile] = useState(); const { LL } = useI18nContext(); @@ -92,7 +93,7 @@ const SingleUpload = ({ doRestart }: SingleUploadProps) => { ) : ( )} diff --git a/interface/src/i18n/cs/index.ts b/interface/src/i18n/cs/index.ts index 6c8e67707..395a7cf77 100644 --- a/interface/src/i18n/cs/index.ts +++ b/interface/src/i18n/cs/index.ts @@ -178,10 +178,6 @@ const cs: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace', DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty', DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', - UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)', - UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr', - UPLOAD_MD5_RECEIVED: 'Digest přijat, nyní nahrajte firmware .bin', - UPLOAD_MD5_MATCHED: 'MD5 souhlasí, firmware se instaluje...', ERROR: 'Neočekávaná chyba, zkuste to prosím znovu', TIME_SET: 'Čas nastaven', MANAGE_USERS: 'Spravovat uživatele', @@ -351,7 +347,11 @@ const cs: Translation = { COMMANDS_HELP_1: 'Definujte vlastní příkazy pro magistrali EMS', COMMAND_EXECUTED: 'Příkaz úspěšně spuštěn', RUN: 'Spustit příkaz', - INTERNET_CONNECTION_CHECK: 'Kontrola online pro dostupné verze' + INTERNET_CONNECTION_CHECK: 'Kontrola online pro dostupné verze', + UPLOAD_BACKUP_TEXT: 'Klikněte, abyste vybrali nebo přetáhli a pustili soubor zálohy (.json) sem', + UPLOAD_FIRMWARE_TEXT: 'Klikněte, abyste vybrali nebo přetáhli a pustili soubor firmware .bin/.md5 sem', + UPLOAD_MD5_RECEIVED: 'Digest přijat, nyní nahrajte firmware .bin', + UPLOAD_MD5_MATCHED: 'MD5 souhlasí, firmware se instaluje...' }; export default cs; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index f94a3573c..a356c4af0 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -178,10 +178,6 @@ const de: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen', DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte', DOWNLOAD_SYSTEM_BACKUP: 'Systemsicherung', - UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch', - UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier', - UPLOAD_MD5_RECEIVED: 'Prüfsumme empfangen, jetzt die Firmware-Datei (.bin) hochladen', - UPLOAD_MD5_MATCHED: 'MD5 stimmt überein, Firmware wird installiert...', ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.', TIME_SET: 'Zeit gesetzt', MANAGE_USERS: 'Nutzerverwaltung', @@ -351,7 +347,11 @@ const de: Translation = { COMMANDS_HELP_1: 'Definieren Sie eigene Befehle für die EMS-Magistral', COMMAND_EXECUTED: 'Befehl erfolgreich ausgeführt', RUN: 'Befehl ausführen', - INTERNET_CONNECTION_CHECK: 'Online-Prüfung auf verfügbare Versionen' + INTERNET_CONNECTION_CHECK: 'Online-Prüfung auf verfügbare Versionen', + UPLOAD_BACKUP_TEXT: 'Klicken Sie, um eine Sicherungsdatei (.json) auszuwählen oder zu ziehen und abzulegen', + UPLOAD_FIRMWARE_TEXT: 'Klicken Sie, um eine Firmware-Datei (.bin/.md5) auszuwählen oder zu ziehen und abzulegen', + UPLOAD_MD5_RECEIVED: 'Prüfsumme empfangen, jetzt die Firmware-Datei (.bin) hochladen', + UPLOAD_MD5_MATCHED: 'MD5 stimmt überein, Firmware wird installiert...' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index fdda0b131..ee4dde8b5 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -178,10 +178,6 @@ const en: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT2: 'Export all values', DOWNLOAD_SYSTEM_BACKUP: 'System Backup', - UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', - UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', - UPLOAD_MD5_RECEIVED: 'Digest received, now upload the firmware .bin file', - UPLOAD_MD5_MATCHED: 'MD5 matches, installing firmware...', ERROR: 'Unexpected Error, please try again', TIME_SET: 'Time set', MANAGE_USERS: 'Manage Users', @@ -351,7 +347,11 @@ const en: Translation = { COMMANDS_HELP_1: 'Define reusable named commands below. These can be executed from the console, API/MQTT, or referenced by the Scheduler', COMMAND_EXECUTED: 'Command executed successfully', RUN: 'Run', - INTERNET_CONNECTION_CHECK: 'Checking online for available versions' + INTERNET_CONNECTION_CHECK: 'Checking online for available versions', + UPLOAD_BACKUP_TEXT: 'Click to select or Drag&Drop a backup file (.json) here', + UPLOAD_FIRMWARE_TEXT: 'Click to select or Drag&Drop a firmware .bin/.md5 file', + UPLOAD_MD5_RECEIVED: 'Digest received, now upload the firmware .bin file', + UPLOAD_MD5_MATCHED: 'MD5 matches, installing firmware...' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 25953e148..b6245bfbe 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -178,10 +178,6 @@ const fr: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations', DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs', DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système', - UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)', - UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', - UPLOAD_MD5_RECEIVED: 'Empreinte reçue, téléversez maintenant le fichier firmware .bin', - UPLOAD_MD5_MATCHED: 'MD5 concordant, installation du firmware...', ERROR: 'Erreur inattendue, veuillez réessayer', TIME_SET: 'Time set', MANAGE_USERS: 'Gérer les utilisateurs', @@ -351,7 +347,11 @@ const fr: Translation = { COMMANDS_HELP_1: 'Définir des commandes personnalisées pour la magistral EMS', COMMAND_EXECUTED: 'Commande exécutée avec succès', RUN: 'Exécuter une commande', - INTERNET_CONNECTION_CHECK: 'Vérification en ligne pour les versions disponibles' + INTERNET_CONNECTION_CHECK: 'Vérification en ligne pour les versions disponibles', + UPLOAD_BACKUP_TEXT: 'Cliquez pour sélectionner ou faites glisser et déposez un fichier de sauvegarde (.json) ici', + UPLOAD_FIRMWARE_TEXT: 'Cliquez pour sélectionner ou faites glisser et déposez un fichier firmware .bin/.md5 ici', + UPLOAD_MD5_RECEIVED: 'Empreinte reçue, téléversez maintenant le fichier firmware .bin', + UPLOAD_MD5_MATCHED: 'MD5 concordant, installation du firmware...' }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 78eb196a8..6a5bc8b00 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -178,10 +178,6 @@ const it: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori', DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema', - UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', - UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', - UPLOAD_MD5_RECEIVED: 'Digest received, now upload the firmware .bin file', - UPLOAD_MD5_MATCHED: 'MD5 matches, installing firmware...', ERROR: 'Errore Inaspettato, prego tenta ancora', TIME_SET: 'Imposta Ora', MANAGE_USERS: 'Gestione Utenti', @@ -351,7 +347,11 @@ const it: Translation = { COMMANDS_HELP_1: 'Definisci comandi personalizzati per la magistrali EMS', COMMAND_EXECUTED: 'Comando eseguito con successo', RUN: 'Esegui comando', - INTERNET_CONNECTION_CHECK: 'Controllo online per le versioni disponibili' + INTERNET_CONNECTION_CHECK: 'Controllo online per le versioni disponibili', + UPLOAD_BACKUP_TEXT: 'Klik per selezionare o trascinare e rilasciare un file di backup (.json) qui', + UPLOAD_FIRMWARE_TEXT: 'Klik per selezionare o trascinare e rilasciare un file firmware .bin/.md5 qui', + UPLOAD_MD5_RECEIVED: 'Digest ricevuto, ora caricare il file firmware .bin', + UPLOAD_MD5_MATCHED: 'MD5 corrispondente, installazione firmware...' }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 2afeee95d..82ebaf690 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -178,10 +178,6 @@ const nl: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen', DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden', DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup', - UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)', - UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier', - UPLOAD_MD5_RECEIVED: 'Digest ontvangen, upload nu het firmware .bin-bestand', - UPLOAD_MD5_MATCHED: 'MD5 komt overeen, firmware wordt geïnstalleerd...', ERROR: 'Onverwachte fout, probeer opnieuw', TIME_SET: 'Tijd ingesteld', MANAGE_USERS: 'Gebruikersbeheer', @@ -351,7 +347,11 @@ const nl: Translation = { COMMANDS_HELP_1: 'Definieer hergebruikbare benoemde commando\'s hieronder. Deze kunnen worden uitgevoerd vanuit de console, API/MQTT, of worden aangeroepen door de Scheduler', COMMAND_EXECUTED: 'Commando uitgevoerd succesvol', RUN: 'Commando uitvoeren', - INTERNET_CONNECTION_CHECK: 'Controleren op online beschikbare versies' + INTERNET_CONNECTION_CHECK: 'Controleren op online beschikbare versies', + UPLOAD_BACKUP_TEXT: 'Klik voor selecteren of sleep en drop een back-upbestand (.json) hier', + UPLOAD_FIRMWARE_TEXT: 'Klik voor selecteren of sleep en drop een firmware .bin/.md5 bestand hier', + UPLOAD_MD5_RECEIVED: 'Digest ontvangen, upload nu het firmware .bin-bestand', + UPLOAD_MD5_MATCHED: 'MD5 komt overeen, firmware wordt geïnstalleerd...' }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 7576d0c8b..e75c0156e 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -178,10 +178,6 @@ const no: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger', DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier', DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi', - UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)', - UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her', - UPLOAD_MD5_RECEIVED: 'Digest mottatt, last nå opp firmware .bin-filen', - UPLOAD_MD5_MATCHED: 'MD5 stemmer, firmware installeres...', ERROR: 'Ukjent feil, prøv igjen', TIME_SET: 'Still in tid', MANAGE_USERS: 'Administrer Brukere', @@ -351,7 +347,11 @@ const no: Translation = { COMMANDS_HELP_1: 'Definer egne kommandoer for EMS-Magistral', COMMAND_EXECUTED: 'Kommando kjørt lykkes', RUN: 'Kjør', - INTERNET_CONNECTION_CHECK: 'Kontrollerer online for tilgjengelige versjoner' + INTERNET_CONNECTION_CHECK: 'Kontrollerer online for tilgjengelige versjoner', + UPLOAD_BACKUP_TEXT: 'Klikk for å velge eller dra og slipp en sikkerhetskopi (.json) her', + UPLOAD_FIRMWARE_TEXT: 'Klikk for å velge eller dra og slipp en firmware .bin/.md5 her', + UPLOAD_MD5_RECEIVED: 'MD5 mottatt, last nå opp firmware .bin-filen', + UPLOAD_MD5_MATCHED: 'MD5 stemmer, firmware installeres...' }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 3f0e4ab8e..a258e5e3a 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -178,10 +178,6 @@ const pl: BaseTranslation = { DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji', DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości', DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu', - UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)', - UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj', - UPLOAD_MD5_RECEIVED: 'Suma MD5 odebrana, teraz wgraj plik firmware .bin', - UPLOAD_MD5_MATCHED: 'MD5 zgodne, instalowanie firmware...', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', TIME_SET: 'Zegar został ustawiony.', MANAGE_USERS: 'Zarządzanie użytkownikami', @@ -351,7 +347,11 @@ const pl: BaseTranslation = { COMMANDS_HELP_1: 'Zdefiniuj niestandardowe komendy dla magistrali EMS', COMMAND_EXECUTED: 'Komenda wykonana pomyślnie', RUN: 'Wykonaj', - INTERNET_CONNECTION_CHECK: 'Sprawdzanie online dla dostępnych wersji' + INTERNET_CONNECTION_CHECK: 'Sprawdzanie online dla dostępnych wersji', + UPLOAD_BACKUP_TEXT: 'Kliknij, aby wybrać lub przeciągnij i upuść plik kopii zapasowej (.json) tutaj', + UPLOAD_FIRMWARE_TEXT: 'Kliknij, aby wybrać lub przeciągnij i upuść plik firmware .bin/.md5', + UPLOAD_MD5_RECEIVED: 'Suma MD5 odebrana, teraz wgraj plik firmware .bin', + UPLOAD_MD5_MATCHED: 'MD5 zgodne, instalowanie firmware...' }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index d0ab4c72d..9e5efbd7c 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -178,10 +178,6 @@ const sk: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení', DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty', DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', - UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)', - UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem', - UPLOAD_MD5_RECEIVED: 'Digest prijatý, teraz nahrajte firmware .bin', - UPLOAD_MD5_MATCHED: 'MD5 súhlasí, firmvér sa inštaluje...', ERROR: 'Neočakávaná chyba, prosím skúste to znova', TIME_SET: 'Nastavený čas', MANAGE_USERS: 'Správa používateľov', @@ -351,7 +347,11 @@ const sk: Translation = { COMMANDS_HELP_1: 'Definujte vlastné príkazy pre magistrali EMS', COMMAND_EXECUTED: 'Príkaz vykonaný úspešne', RUN: 'Volať príkaz', - INTERNET_CONNECTION_CHECK: 'Kontrola online pre dostupné verzie' + INTERNET_CONNECTION_CHECK: 'Kontrola online pre dostupné verzie', + UPLOAD_BACKUP_TEXT: 'Kliknite, aby ste vybrali alebo presuňte a upustili súbor zálohy (.json) sem', + UPLOAD_FIRMWARE_TEXT: 'Kliknite, aby ste vybrali alebo presuňte a upustili súbor firmware .bin/.md5', + UPLOAD_MD5_RECEIVED: 'Suma MD5 prijatá, teraz nahrajte firmware .bin', + UPLOAD_MD5_MATCHED: 'MD5 súhlasí, firmvér sa inštaluje...' }; export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 7d299d96a..af7351901 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -178,10 +178,6 @@ const sv: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar', DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden', DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia', - UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)', - UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här', - UPLOAD_MD5_RECEIVED: 'Digest mottagen, ladda nu upp firmware .bin-filen', - UPLOAD_MD5_MATCHED: 'MD5 stämmer, firmware installeras...', ERROR: 'Okänt fel, var god försök igen', TIME_SET: 'Ställ in tid', MANAGE_USERS: 'Användare', @@ -351,7 +347,11 @@ const sv: Translation = { COMMANDS_HELP_1: 'Definiera egna kommandon för EMS-Magistral', COMMAND_EXECUTED: 'Kommando kört lyckades', RUN: 'Kör kommando', - INTERNET_CONNECTION_CHECK: 'Kontrollerar online för tillgängliga versioner' + INTERNET_CONNECTION_CHECK: 'Kontrollerar online för tillgängliga versioner', + UPLOAD_BACKUP_TEXT: 'Klicka för att välja eller dra och släpp en säkerhetskopia (.json) här', + UPLOAD_FIRMWARE_TEXT: 'Klicka för att välja eller dra och släpp en firmware .bin/.md5 här', + UPLOAD_MD5_RECEIVED: 'MD5 mottagen, ladda nu upp firmware .bin-filen', + UPLOAD_MD5_MATCHED: 'MD5 stämmer, firmware installeras...' }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 3525b3efd..c214abe47 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -178,10 +178,6 @@ const tr: Translation = { DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın', DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al', DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme', - UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle', - UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın', - UPLOAD_MD5_RECEIVED: 'Özet alındı, şimdi firmware .bin dosyasını yükleyin', - UPLOAD_MD5_MATCHED: 'MD5 eşleşti, firmware yükleniyor...', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', TIME_SET: 'Zaman ayarı', MANAGE_USERS: 'Kullanıcıları yönet', @@ -351,7 +347,11 @@ const tr: Translation = { COMMANDS_HELP_1: 'Özel komutları EMS hattına tanımlayın', COMMAND_EXECUTED: 'Komut başarıyla çalıştırıldı', RUN: 'Komutu çalıştır', - INTERNET_CONNECTION_CHECK: 'Online bağlantısı kontrol ediliyor' + INTERNET_CONNECTION_CHECK: 'Online bağlantısı kontrol ediliyor', + UPLOAD_BACKUP_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle', + UPLOAD_FIRMWARE_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın', + UPLOAD_MD5_RECEIVED: 'Özet alındı, şimdi firmware .bin dosyasını yükleyin', + UPLOAD_MD5_MATCHED: 'MD5 eşleşti, firmware yükleniyor...' }; export default tr; diff --git a/interface/vite.config.ts b/interface/vite.config.ts index 65ff0d722..c87ab4e41 100644 --- a/interface/vite.config.ts +++ b/interface/vite.config.ts @@ -207,9 +207,6 @@ export default defineConfig( async ({ command, mode }: { command: string; mode: string }) => { if (command === 'serve') { console.log(`Preparing for standalone build with server, mode=${mode}`); - // Imported through a computed URL so the config bundler leaves it as a real - // runtime import: mock-api is a separate package with its own node_modules, - // and inlining it here would drag its dependencies into every build. const mockServerUrl = pathToFileURL( path.resolve(import.meta.dirname, '../mock-api/mockServer.js') ).href; diff --git a/mock-api/mockSSEServer.js b/mock-api/mockServer.js similarity index 55% rename from mock-api/mockSSEServer.js rename to mock-api/mockServer.js index 914164d8d..7fba27344 100644 --- a/mock-api/mockSSEServer.js +++ b/mock-api/mockServer.js @@ -1,5 +1,6 @@ -// Simulate EventSource for log messages in EMS-ESP standalone mode -// Server-Sent Events (SSE) +// EMS-ESP standalone mode to simulate +// a REST server for file uploads +// an EventSource (Server-Sent Events) for log messages in EMS-ESP standalone mode const ONE_SECOND_MS = 1000; // padding function @@ -21,11 +22,113 @@ const formatDate = (date) => { return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`; }; +const MOCK_REST_ORIGIN = 'http://localhost:3080'; +const UPLOAD_SIMULATED_KB_PER_SEC = 256; +const UPLOAD_SLICE_BYTES = 16 * 1024; + +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +const readRequestThrottled = (req) => + new Promise((resolve, reject) => { + const chunks = []; + let ended = false; + let settled = false; + + const settle = (settler, value) => { + if (settled) { + return; + } + settled = true; + settler(value); + }; + + req.on('error', (error) => settle(reject, error)); + req.on('end', () => { + ended = true; + void step(); + }); + + const step = async () => { + if (settled) { + return; + } + try { + const chunk = req.read(UPLOAD_SLICE_BYTES); + if (chunk) { + chunks.push(chunk); + await sleep((chunk.length / (UPLOAD_SIMULATED_KB_PER_SEC * 1024)) * 1000); + void step(); + return; + } + if (ended || req.readableEnded) { + settle(resolve, Buffer.concat(chunks)); + return; + } + req.once('readable', () => { + void step(); + }); + } catch (error) { + settle(reject, error); + } + }; + + void step(); + }); + +const forwardThrottledUpload = async (req, res) => { + const startedAt = Date.now(); + try { + const body = await readRequestThrottled(req); + console.log( + `Upload received: ${body.length} bytes in ${((Date.now() - startedAt) / 1000).toFixed(1)}s` + ); + const headers = {}; + if (req.headers['content-type']) { + headers['content-type'] = req.headers['content-type']; + } + if (req.headers.authorization) { + headers.authorization = req.headers.authorization; + } + headers['content-length'] = String(body.length); + + const bunRes = await fetch(`${MOCK_REST_ORIGIN}${req.url}`, { + method: 'POST', + headers, + body + }); + const buf = Buffer.from(await bunRes.arrayBuffer()); + res.statusCode = bunRes.status; + bunRes.headers.forEach((value, key) => { + if (key !== 'transfer-encoding' && key !== 'content-encoding') { + res.setHeader(key, value); + } + }); + res.end(buf); + } catch (error) { + if (error?.code === 'ECONNRESET' || req.destroyed) { + console.log('Upload cancelled by the client'); + } else { + console.error('Throttled upload proxy failed', error); + } + if (!res.headersSent) { + res.statusCode = 502; + } + if (!res.writableEnded) { + res.end(); + } + } +}; + export default () => { return { - name: 'vite:mockserver', + name: 'vite:mockServer', configureServer: async (server) => { server.middlewares.use(async (req, res, next) => { + if (req.url.startsWith('/rest/uploadFile') && req.method === 'POST') { + await forwardThrottledUpload(req, res); + return; + } + // Handle Server-Sent Events (SSE) for log streaming if (req.url.startsWith('/es/log')) { // Set SSE headers diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index a75f81127..ea02c45e3 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -242,15 +242,6 @@ let countHardwarePoll = 0; // for during an upload let pendingFirmwareMd5 = false; // set by a .md5 upload, cleared by the next .bin const VALID_UPLOAD_EXTENSIONS = new Set(['bin', 'json', 'md5']); -const UPLOAD_PROGRESS_LOG_STEP = 10; // log every 10% - -// A real device takes a while to accept a firmware image, so uploads are read at -// this rate instead of completing instantly. That keeps the WebUI progress bar on -// screen long enough to see. Lower it to watch the progress bar for longer. -const UPLOAD_SIMULATED_KB_PER_SEC = 2048; -const UPLOAD_SLICE_BYTES = 64 * 1024; // granularity of the simulated transfer - -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); function parseMd5Digest(text: string): string | null { const token = text.trim().split(/\s+/)[0]; @@ -260,45 +251,6 @@ function parseMd5Digest(text: string): string | null { return null; } -// Read the multipart body in slices at UPLOAD_SIMULATED_KB_PER_SEC, logging progress -// as it goes, then hand the buffered bytes back as FormData so they parse normally. -async function readUploadSlowly(request: Request): Promise { - const contentType = request.headers.get('content-type') || ''; - const expected = Number(request.headers.get('content-length') || '0'); - const reader = request.body?.getReader(); - const chunks: Uint8Array[] = []; - let received = 0; - let loggedPercentage = 0; - - while (reader) { - const { done, value } = await reader.read(); - if (done) { - break; - } - chunks.push(value); - - // A fast local client arrives in very few chunks, so pace each one slice by - // slice to keep the reported progress gradual instead of jumping to 100% - for (let offset = 0; offset < value.length; offset += UPLOAD_SLICE_BYTES) { - const sliceLength = Math.min(UPLOAD_SLICE_BYTES, value.length - offset); - await sleep((sliceLength / (UPLOAD_SIMULATED_KB_PER_SEC * 1024)) * 1000); - received += sliceLength; - - if (expected > 0) { - const percentage = Math.round((received / expected) * 100); - if (percentage >= loggedPercentage + UPLOAD_PROGRESS_LOG_STEP) { - loggedPercentage = percentage; - console.log(`Upload progress: ${percentage}%`); - } - } - } - } - - return new Response(new Blob(chunks as BlobPart[]), { - headers: { 'content-type': contentType } - }).formData(); -} - // DeviceTypes const enum ScheduleFlag { SCHEDULE_SUN = 1, @@ -4702,7 +4654,7 @@ router // SYSTEM and SETTINGS router .post(EMSESP_UPLOAD_FILE_ENDPOINT, async (request: Request) => { - const formData = await readUploadSlowly(request); + const formData = await request.formData(); const uploaded = formData.get('file'); if (!uploaded || typeof uploaded === 'string') { return status(400); diff --git a/project-words.txt b/project-words.txt index 3204475a4..ae59838d4 100644 --- a/project-words.txt +++ b/project-words.txt @@ -744,7 +744,7 @@ mlongcalls mmio mmode mmplus -mockSSEServer +mockServer modbus modee modetype