Loading app/src/static/css/styles.css +7 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,13 @@ button.next:disabled { justify-content: space-between; padding: 5px 10px; } #error-message-state { max-height: 100px; overflow: auto; padding: 5px; border: 1px solid var(--top-banner-color); background-color:#fff; } #donate, #help { display: flex; align-items: center; Loading app/src/static/index.html +5 −4 Original line number Diff line number Diff line Loading @@ -33,19 +33,20 @@ <b>Installation</b> <div><span id="current-step">1</span>/</span><span id="total-step">?</span></div> <div>completed</div> <div id="error-message-state"> <div id="error-caption-state"></div> <div id="error-text-state"></div> </div> </div> <div id="sub-banner"> <a href="https://e.foundation/donate/" target="_blank"> <button id="donate"><img src="assets/images/icons/donate.svg"><span data-translate="donate"></span></button> </a> <div id="error-message-state" hidden="display:none"> <div id="error-caption-state"></div> <div id="error-text-state"></div> </div> <a href="https://doc.e.foundation/easy-installer-faq" target="_blank"> <button id="help"><img src="assets/images/icons/help.svg"><span data-translate="help"></span></button> </a> </div> </div> <div id="logo-ctn"> <img id="logo" src="assets/images/icons/logo.png"> Loading app/src/static/js/controller.manager.js +46 −29 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ export class Controller { async init() { this.deviceManager = new DeviceManager(); await this.deviceManager.init(); //VIEW.onStepStarted(this.steps[this.currentIndex]); } async next() { Loading Loading @@ -56,11 +55,17 @@ export class Controller { async executeStep(stepName) { const current = this.steps[this.currentIndex]; let this_command; WDebug.log("ControllerManager Execute step", current) document.getElementById('error-message-state').style.display = 'none'; if (current.name === stepName) { let res = true; for (let i = 0; i < current.commands.length && res; i++) { res = await this.runCommand(current.commands[i]); let i; try { for (i= 0; i < current.commands.length && res; i++) { this_command = current.commands[i]; res = await this.runCommand(this_command); WDebug.log("run command > ", this_command , "returns ", res); } const next = this.steps[this.currentIndex + 1]; let previous = this.steps[this.currentIndex - 1]; Loading @@ -74,10 +79,13 @@ export class Controller { if (!current.needUserGesture) { this.currentIndex--; } throw Error('command failed'); throw new Error('command failed'); } } catch (e) { throw new Error(`Cannot execute command ${this_command.command} <br/> ${e.message || e}`); } } else { throw Error('this is not the current step') throw new Error('this is not the current step') } } Loading @@ -91,6 +99,11 @@ export class Controller { return this.deviceManager.isInMode(mode); } /* * run a command this throw new error if something went wwrong. error should contain a proposal to solve the issue. */ async runCommand(cmd) { WDebug.log("ControllerManager run command:", cmd); switch (cmd.type) { Loading @@ -103,12 +116,12 @@ export class Controller { VIEW.onUnzip(name, loaded, total); }); VIEW.onDownloadingEnd(); res = true; return true; } catch (e) { throw new Error(`Cannot download ${e.message || e}`); } finally { return res; const proposal = "Proposal: Retry by refreshing this page."; throw new Error(`Cannot download <br/> ${e.message || e} <br/> ${proposal}`); } return false; case Command.CMD_TYPE.reboot: try { await this.deviceManager.reboot(cmd.mode); Loading @@ -119,6 +132,7 @@ export class Controller { } return true; case Command.CMD_TYPE.connect: const proposal = "Proposal: Check connection and that no other program is using the phone and retry."; try { const res = await this.deviceManager.connect(cmd.mode); if (res) { Loading @@ -126,9 +140,9 @@ export class Controller { return true; } } catch (e) { throw new Error(`The device is not connected ${e.message || e}`); throw new Error(`The device is not connected ${e.message || e} <br/> ${proposal}`); } return false; throw new Error(`Cannot connect the device <br/> ${proposal}`); case Command.CMD_TYPE.erase: return this.deviceManager.erase(cmd.partition); case Command.CMD_TYPE.flash: Loading Loading @@ -203,8 +217,12 @@ export class Controller { return true; default: WDebug.log(`try unknown command ${cmd.command}`) WDebug.log(`try unknown command ${cmd.command}`); try { await this.deviceManager.runCommand(cmd.command); } catch(e) { } return true; } } Loading @@ -229,7 +247,7 @@ export class Controller { } catch(e) { this.steps.push(new Step(e.message)); VIEW.updateTotalStep(this.steps.length); throw new Error(`onDeviceConnected ${e.message || e}`); // Don not throw this error, as it is handled by the UI directly. } } } Loading Loading @@ -302,7 +320,6 @@ export class Controller { } catch (e) { resources = null; WDebug.log("getRessources Error"); if (override) throw Error('device-model-not-supported'); } Loading app/src/static/js/controller/device.manager.js +2 −3 Original line number Diff line number Diff line Loading @@ -181,7 +181,7 @@ export class DeviceManager { async sideload(file) { let blob = await this.downloader.getFile(file); if (!blob) { throw Error(`error getting blob file ${file}`); throw new Error(`error getting blob file ${file}`); } return await this.device.sideload(blob); Loading @@ -191,8 +191,7 @@ export class DeviceManager { try { return this.device.runCommand(command); } catch (e) { console.error(e); //K1ZFP TODO throw Error(`error ${command} failed`); throw new Error(`error ${command} failed <br/> ${e.message || e}`); } } Loading app/src/static/js/controller/downloader.manager.js +55 −29 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ export class Downloader { /* * */ async downloadAndUnzipFolder(filesRequired, folder, onDownloadProgress, onUnzipProgress) { let current_file ; try { for (let i = 0; i < folder.length; i++) { const file = folder[i]; current_file = file.path; if(filesRequired.includes(file.name) || file.unzip){ const blob = await this.download(file.path, (value, total) => { onDownloadProgress(value, total, file.name); Loading @@ -54,7 +56,7 @@ export class Downloader { } } } catch (e) { throw new Error(`downloadAndUnzipFolder Error ${e.message || e}`); throw new Error(`downloadAndUnzipFolder Error <br/>current_file ${current_file} <br/> ${e.message || e}`); } } Loading Loading @@ -82,7 +84,7 @@ export class Downloader { async getFile(name) { const file = this.stored[name]; if(!file){ throw Error(`File ${name} was not previously downloaded`) throw new Error(`File ${name} was not previously downloaded`) } return await this.getFromDBStore(name); } Loading Loading @@ -114,9 +116,7 @@ export class Downloader { const ret = new Blob(buffers); return ret; } catch (e) { WDebug.log(`Erreur: ${e.message}`); console.error(e); //K1ZFP TODO throw Error(e); throw new Error(`${e.message || e}`); } } Loading Loading @@ -192,37 +192,63 @@ export class Downloader { let xhr = new XMLHttpRequest(); xhr.open("HEAD", url); xhr.send(); xhr.onload = function () { resolve( // xhr.getResponseHeader("Accept-Ranges") === "bytes" && ~~xhr.getResponseHeader("Content-Length") ); if (xhr.status >= 200 && xhr.status < 300) { const contentLength = xhr.getResponseHeader("Content-Length"); if (contentLength) { resolve(parseInt(contentLength, 10)); } else { reject(new Error("Cannot get Content-Length")); } } else { reject(new Error(`Request error : ${xhr.status} ${xhr.statusText}`)); } }; xhr.onerror = function () { reject(new Error("Connetion issue")); }; xhr.ontimeout = function () { reject(new Error("Timeout issue")); }; xhr.onerror = reject; }); } async fetch({url, chunkSize}, onProgress) { try { const contentLength = await this.getContentLength(url); const totalChunks = Math.ceil(contentLength / chunkSize); const buffers = []; for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize - 1, contentLength - 1); const chunk = await fetch(url, { try { const response = await fetch(url, { headers: { 'Range': `bytes=${start}-${end}` } }).then(res => res.arrayBuffer()); }); if (!response.ok) { throw new Error(`Cannot download chunk (1) ${i + 1}: ${response.status} ${response.statusText}`); } const chunk = await response.arrayBuffer(); buffers.push(chunk); onProgress(start + chunk.byteLength, contentLength); } } catch (chunkError) { throw new Error(`Cannot download chunk (2) ${i + 1} ${chunkError.message || chunkError}`); } } return buffers; } catch (error) { throw new Error(`Download fails ${error.message || error}`); } } } No newline at end of file Loading
app/src/static/css/styles.css +7 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,13 @@ button.next:disabled { justify-content: space-between; padding: 5px 10px; } #error-message-state { max-height: 100px; overflow: auto; padding: 5px; border: 1px solid var(--top-banner-color); background-color:#fff; } #donate, #help { display: flex; align-items: center; Loading
app/src/static/index.html +5 −4 Original line number Diff line number Diff line Loading @@ -33,19 +33,20 @@ <b>Installation</b> <div><span id="current-step">1</span>/</span><span id="total-step">?</span></div> <div>completed</div> <div id="error-message-state"> <div id="error-caption-state"></div> <div id="error-text-state"></div> </div> </div> <div id="sub-banner"> <a href="https://e.foundation/donate/" target="_blank"> <button id="donate"><img src="assets/images/icons/donate.svg"><span data-translate="donate"></span></button> </a> <div id="error-message-state" hidden="display:none"> <div id="error-caption-state"></div> <div id="error-text-state"></div> </div> <a href="https://doc.e.foundation/easy-installer-faq" target="_blank"> <button id="help"><img src="assets/images/icons/help.svg"><span data-translate="help"></span></button> </a> </div> </div> <div id="logo-ctn"> <img id="logo" src="assets/images/icons/logo.png"> Loading
app/src/static/js/controller.manager.js +46 −29 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ export class Controller { async init() { this.deviceManager = new DeviceManager(); await this.deviceManager.init(); //VIEW.onStepStarted(this.steps[this.currentIndex]); } async next() { Loading Loading @@ -56,11 +55,17 @@ export class Controller { async executeStep(stepName) { const current = this.steps[this.currentIndex]; let this_command; WDebug.log("ControllerManager Execute step", current) document.getElementById('error-message-state').style.display = 'none'; if (current.name === stepName) { let res = true; for (let i = 0; i < current.commands.length && res; i++) { res = await this.runCommand(current.commands[i]); let i; try { for (i= 0; i < current.commands.length && res; i++) { this_command = current.commands[i]; res = await this.runCommand(this_command); WDebug.log("run command > ", this_command , "returns ", res); } const next = this.steps[this.currentIndex + 1]; let previous = this.steps[this.currentIndex - 1]; Loading @@ -74,10 +79,13 @@ export class Controller { if (!current.needUserGesture) { this.currentIndex--; } throw Error('command failed'); throw new Error('command failed'); } } catch (e) { throw new Error(`Cannot execute command ${this_command.command} <br/> ${e.message || e}`); } } else { throw Error('this is not the current step') throw new Error('this is not the current step') } } Loading @@ -91,6 +99,11 @@ export class Controller { return this.deviceManager.isInMode(mode); } /* * run a command this throw new error if something went wwrong. error should contain a proposal to solve the issue. */ async runCommand(cmd) { WDebug.log("ControllerManager run command:", cmd); switch (cmd.type) { Loading @@ -103,12 +116,12 @@ export class Controller { VIEW.onUnzip(name, loaded, total); }); VIEW.onDownloadingEnd(); res = true; return true; } catch (e) { throw new Error(`Cannot download ${e.message || e}`); } finally { return res; const proposal = "Proposal: Retry by refreshing this page."; throw new Error(`Cannot download <br/> ${e.message || e} <br/> ${proposal}`); } return false; case Command.CMD_TYPE.reboot: try { await this.deviceManager.reboot(cmd.mode); Loading @@ -119,6 +132,7 @@ export class Controller { } return true; case Command.CMD_TYPE.connect: const proposal = "Proposal: Check connection and that no other program is using the phone and retry."; try { const res = await this.deviceManager.connect(cmd.mode); if (res) { Loading @@ -126,9 +140,9 @@ export class Controller { return true; } } catch (e) { throw new Error(`The device is not connected ${e.message || e}`); throw new Error(`The device is not connected ${e.message || e} <br/> ${proposal}`); } return false; throw new Error(`Cannot connect the device <br/> ${proposal}`); case Command.CMD_TYPE.erase: return this.deviceManager.erase(cmd.partition); case Command.CMD_TYPE.flash: Loading Loading @@ -203,8 +217,12 @@ export class Controller { return true; default: WDebug.log(`try unknown command ${cmd.command}`) WDebug.log(`try unknown command ${cmd.command}`); try { await this.deviceManager.runCommand(cmd.command); } catch(e) { } return true; } } Loading @@ -229,7 +247,7 @@ export class Controller { } catch(e) { this.steps.push(new Step(e.message)); VIEW.updateTotalStep(this.steps.length); throw new Error(`onDeviceConnected ${e.message || e}`); // Don not throw this error, as it is handled by the UI directly. } } } Loading Loading @@ -302,7 +320,6 @@ export class Controller { } catch (e) { resources = null; WDebug.log("getRessources Error"); if (override) throw Error('device-model-not-supported'); } Loading
app/src/static/js/controller/device.manager.js +2 −3 Original line number Diff line number Diff line Loading @@ -181,7 +181,7 @@ export class DeviceManager { async sideload(file) { let blob = await this.downloader.getFile(file); if (!blob) { throw Error(`error getting blob file ${file}`); throw new Error(`error getting blob file ${file}`); } return await this.device.sideload(blob); Loading @@ -191,8 +191,7 @@ export class DeviceManager { try { return this.device.runCommand(command); } catch (e) { console.error(e); //K1ZFP TODO throw Error(`error ${command} failed`); throw new Error(`error ${command} failed <br/> ${e.message || e}`); } } Loading
app/src/static/js/controller/downloader.manager.js +55 −29 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ export class Downloader { /* * */ async downloadAndUnzipFolder(filesRequired, folder, onDownloadProgress, onUnzipProgress) { let current_file ; try { for (let i = 0; i < folder.length; i++) { const file = folder[i]; current_file = file.path; if(filesRequired.includes(file.name) || file.unzip){ const blob = await this.download(file.path, (value, total) => { onDownloadProgress(value, total, file.name); Loading @@ -54,7 +56,7 @@ export class Downloader { } } } catch (e) { throw new Error(`downloadAndUnzipFolder Error ${e.message || e}`); throw new Error(`downloadAndUnzipFolder Error <br/>current_file ${current_file} <br/> ${e.message || e}`); } } Loading Loading @@ -82,7 +84,7 @@ export class Downloader { async getFile(name) { const file = this.stored[name]; if(!file){ throw Error(`File ${name} was not previously downloaded`) throw new Error(`File ${name} was not previously downloaded`) } return await this.getFromDBStore(name); } Loading Loading @@ -114,9 +116,7 @@ export class Downloader { const ret = new Blob(buffers); return ret; } catch (e) { WDebug.log(`Erreur: ${e.message}`); console.error(e); //K1ZFP TODO throw Error(e); throw new Error(`${e.message || e}`); } } Loading Loading @@ -192,37 +192,63 @@ export class Downloader { let xhr = new XMLHttpRequest(); xhr.open("HEAD", url); xhr.send(); xhr.onload = function () { resolve( // xhr.getResponseHeader("Accept-Ranges") === "bytes" && ~~xhr.getResponseHeader("Content-Length") ); if (xhr.status >= 200 && xhr.status < 300) { const contentLength = xhr.getResponseHeader("Content-Length"); if (contentLength) { resolve(parseInt(contentLength, 10)); } else { reject(new Error("Cannot get Content-Length")); } } else { reject(new Error(`Request error : ${xhr.status} ${xhr.statusText}`)); } }; xhr.onerror = function () { reject(new Error("Connetion issue")); }; xhr.ontimeout = function () { reject(new Error("Timeout issue")); }; xhr.onerror = reject; }); } async fetch({url, chunkSize}, onProgress) { try { const contentLength = await this.getContentLength(url); const totalChunks = Math.ceil(contentLength / chunkSize); const buffers = []; for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize - 1, contentLength - 1); const chunk = await fetch(url, { try { const response = await fetch(url, { headers: { 'Range': `bytes=${start}-${end}` } }).then(res => res.arrayBuffer()); }); if (!response.ok) { throw new Error(`Cannot download chunk (1) ${i + 1}: ${response.status} ${response.statusText}`); } const chunk = await response.arrayBuffer(); buffers.push(chunk); onProgress(start + chunk.byteLength, contentLength); } } catch (chunkError) { throw new Error(`Cannot download chunk (2) ${i + 1} ${chunkError.message || chunkError}`); } } return buffers; } catch (error) { throw new Error(`Download fails ${error.message || error}`); } } } No newline at end of file