Cambios generales
This commit is contained in:
parent
5221b6fb19
commit
6777bf363b
@ -1,4 +1,11 @@
|
|||||||
** Mejoras de interfaz y configuración (Septiembre 27, 2026)
|
** Versión 2.0.0: (Septiembre 27, 2026)
|
||||||
|
+ Se actualiza la versión de NWJS → 0.107.0
|
||||||
|
+ Node-hid ahora no necesita nw-gyp, se actualiza la compilación
|
||||||
|
+ Se migra escritorio y web a Bootstrap 5 con Popper incluido en el bundle.
|
||||||
|
+ Se actualiza bootstrap-select a 1.14.0-beta3 y se reconstruyen selects conservando el valor para evitar opciones duplicadas.
|
||||||
|
+ Se integran DataTables 1.13.11 y Buttons 2.4.3 con estilos Bootstrap 5.
|
||||||
|
+ Se corrigen atributos, clases, rutas de imágenes y estilos de tablas/formularios.
|
||||||
|
+ Se agrega desktop:dev y test:ui (requiere un binario NW.js SDK como argumento).
|
||||||
+ Se actualizó RGraph 7.01 → 7.21
|
+ Se actualizó RGraph 7.01 → 7.21
|
||||||
+ NW.js 0.117.0 centralizado en runtime.json para desarrollo y empaquetado x64.
|
+ NW.js 0.117.0 centralizado en runtime.json para desarrollo y empaquetado x64.
|
||||||
+ Formulario compartido con controles nativos, validación y aviso de cambios sin guardar.
|
+ Formulario compartido con controles nativos, validación y aviso de cambios sin guardar.
|
||||||
@ -8,15 +15,8 @@
|
|||||||
+ Estados separados para conexión, última lectura y publicación, con motivos y acciones.
|
+ Estados separados para conexión, última lectura y publicación, con motivos y acciones.
|
||||||
+ Pruebas de configuración, interfaz y arranque aisladas de la estación real.
|
+ Pruebas de configuración, interfaz y arranque aisladas de la estación real.
|
||||||
+ El empaquetador ARM histórico queda bloqueado: su Node/NW.js no soportan esta versión.
|
+ El empaquetador ARM histórico queda bloqueado: su Node/NW.js no soportan esta versión.
|
||||||
|
+ Se mejora el iconizado.
|
||||||
** Versión 2.0.0: (Septiembre 27, 2026)
|
+ Se mejora el boton de guardado.
|
||||||
+ Se actualiza la versión de NWJS → 0.107.0
|
|
||||||
+ Node-hid ahora no necesita nw-gyp, se actualiza la compilación
|
|
||||||
+ Se migra escritorio y web a Bootstrap 5 con Popper incluido en el bundle.
|
|
||||||
+ Se actualiza bootstrap-select a 1.14.0-beta3 y se reconstruyen selects conservando el valor para evitar opciones duplicadas.
|
|
||||||
+ Se integran DataTables 1.13.11 y Buttons 2.4.3 con estilos Bootstrap 5.
|
|
||||||
+ Se corrigen atributos, clases, rutas de imágenes y estilos de tablas/formularios.
|
|
||||||
+ Se agrega desktop:dev y test:ui (requiere un binario NW.js SDK como argumento).
|
|
||||||
|
|
||||||
** Versión 1.36: (Enero 10 , 2026)
|
** Versión 1.36: (Enero 10 , 2026)
|
||||||
+ Se incorporó recolectar por WIFI/IP.
|
+ Se incorporó recolectar por WIFI/IP.
|
||||||
|
|||||||
@ -160,7 +160,7 @@
|
|||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('.menu').on('click', function(evnt) {
|
$('.menu').on('click', function(evnt) {
|
||||||
var obj = $(evnt.target);
|
var obj = $(evnt.currentTarget);
|
||||||
$('#' + obj.attr('aria-controls')).empty();
|
$('#' + obj.attr('aria-controls')).empty();
|
||||||
let screens = gui.Screen.screens;
|
let screens = gui.Screen.screens;
|
||||||
let winX = win.x;
|
let winX = win.x;
|
||||||
@ -178,7 +178,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//nw.Window.get().moveTo(0);
|
//nw.Window.get().moveTo(0);
|
||||||
switch (obj.attr('id')) {
|
switch (obj.attr('aria-controls')) {
|
||||||
case 'Wzoomin':
|
case 'Wzoomin':
|
||||||
win.zoomLevel += 0.3;
|
win.zoomLevel += 0.3;
|
||||||
break;
|
break;
|
||||||
@ -190,9 +190,7 @@
|
|||||||
nw.Window.get().resizeTo(currentScreen.bounds.width, currentScreen.bounds.height);
|
nw.Window.get().resizeTo(currentScreen.bounds.width, currentScreen.bounds.height);
|
||||||
break;
|
break;
|
||||||
case 'Wmin':
|
case 'Wmin':
|
||||||
nw.Window.get().minimize();
|
ocultarVentana();
|
||||||
//win.hide(); // Oculta completamente la ventana
|
|
||||||
//win.setShowInTaskbar(false); // Quita el icono del taskbar
|
|
||||||
break;
|
break;
|
||||||
case 'Wmax':
|
case 'Wmax':
|
||||||
nw.Window.get().moveTo(currentScreen.bounds.x, currentScreen.bounds.y);
|
nw.Window.get().moveTo(currentScreen.bounds.x, currentScreen.bounds.y);
|
||||||
|
|||||||
@ -32,6 +32,8 @@
|
|||||||
// y exporta las variables necesarias para el resto del archivo.
|
// y exporta las variables necesarias para el resto del archivo.
|
||||||
var configGeneralEMA, configGlobalEMA, funcionesActualizar, EMA, gui, os, win;
|
var configGeneralEMA, configGlobalEMA, funcionesActualizar, EMA, gui, os, win;
|
||||||
var _IS_NW = false;
|
var _IS_NW = false;
|
||||||
|
let tray = null;
|
||||||
|
let ventanaMinimizada = false;
|
||||||
const iconoEncendido = './gui_common/iconos/icono_enc.png'; // Imagen del Icono Encendido
|
const iconoEncendido = './gui_common/iconos/icono_enc.png'; // Imagen del Icono Encendido
|
||||||
const iconoApagado = './gui_common/iconos/icono_off.png'; // Imagen del Icono Apagado
|
const iconoApagado = './gui_common/iconos/icono_off.png'; // Imagen del Icono Apagado
|
||||||
const iconoPublicado = './gui_common/iconos/icono_pub.png'; // Imagen del Icono Prublicado --> no utilizada
|
const iconoPublicado = './gui_common/iconos/icono_pub.png'; // Imagen del Icono Prublicado --> no utilizada
|
||||||
@ -58,85 +60,64 @@ if (_IS_NW) {
|
|||||||
// **********************Iconizado / Menu Superior *********************************************************
|
// **********************Iconizado / Menu Superior *********************************************************
|
||||||
gui.App.clearCache(); // Se limpia cache
|
gui.App.clearCache(); // Se limpia cache
|
||||||
win = gui.Window.get(); // Se obtiene la ventana actual
|
win = gui.Window.get(); // Se obtiene la ventana actual
|
||||||
// Crear el icono en el tray
|
// Mantener el icono y su menú durante toda la vida de la ventana.
|
||||||
function createTray() {
|
function mostrarVentana() {
|
||||||
if (tray) return; // Evitar duplicados
|
win.setShowInTaskbar(true);
|
||||||
|
win.show();
|
||||||
|
if (ventanaMinimizada) {
|
||||||
|
win.restore();
|
||||||
|
ventanaMinimizada = false;
|
||||||
|
}
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
|
||||||
// Crear menú contextual (sin 'menubar')
|
function ocultarVentana() {
|
||||||
const menu = new nw.Menu();
|
createTray();
|
||||||
menu.append(new nw.MenuItem({ type: 'checkbox', label: 'box1' }));
|
win.hide();
|
||||||
menu.append(new nw.MenuItem({
|
win.setShowInTaskbar(false);
|
||||||
label: 'Iniciar',
|
}
|
||||||
click: () => { if (typeof INICIAR === 'function') INICIAR(); }
|
|
||||||
}));
|
function createTray() {
|
||||||
menu.append(new nw.MenuItem({
|
if (tray) return;
|
||||||
label: 'Detener',
|
|
||||||
click: () => { if (typeof DETENER === 'function') DETENER(); }
|
const menu = new gui.Menu();
|
||||||
}));
|
menu.append(new gui.MenuItem({
|
||||||
menu.append(new nw.MenuItem({ type: 'separator' }));
|
|
||||||
menu.append(new nw.MenuItem({
|
|
||||||
label: 'Mostrar ventana',
|
label: 'Mostrar ventana',
|
||||||
click: () => {
|
click: mostrarVentana
|
||||||
win.show();
|
|
||||||
win.restore();
|
|
||||||
win.focus();
|
|
||||||
win.setShowInTaskbar(true);
|
|
||||||
removeTray();
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
menu.append(new nw.MenuItem({
|
menu.append(new gui.MenuItem({
|
||||||
label: 'Ocultar ventana',
|
label: 'Ocultar ventana',
|
||||||
click: () => {
|
click: ocultarVentana
|
||||||
win.hide();
|
|
||||||
win.setShowInTaskbar(false);
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
menu.append(new nw.MenuItem({ type: 'separator' }));
|
menu.append(new gui.MenuItem({ type: 'separator' }));
|
||||||
menu.append(new nw.MenuItem({
|
menu.append(new gui.MenuItem({ label: 'Iniciar', click: INICIAR }));
|
||||||
|
menu.append(new gui.MenuItem({ label: 'Detener', click: DETENER }));
|
||||||
|
menu.append(new gui.MenuItem({ type: 'separator' }));
|
||||||
|
menu.append(new gui.MenuItem({
|
||||||
label: 'Salir',
|
label: 'Salir',
|
||||||
click: () => {
|
click: () => {
|
||||||
if (!ConfigUI.canLeave()) return;
|
if (!ConfigUI.canLeave()) return;
|
||||||
if (typeof EMA !== 'undefined' && typeof EMA.Salir === 'function') EMA.Salir();
|
if (typeof EMA.Salir === 'function') EMA.Salir();
|
||||||
nw.App.closeAllWindows();
|
gui.App.closeAllWindows();
|
||||||
nw.App.quit();
|
gui.App.quit();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Crear tray icon
|
// Entregar el menú al crear el indicador, también en Linux.
|
||||||
tray = new nw.Tray({
|
tray = new gui.Tray({
|
||||||
title: 'EmaLibre Carpincho',
|
title: 'EmaLibre Carpincho',
|
||||||
icon: iconoApagado,
|
icon: iconoApagado,
|
||||||
|
menu: menu
|
||||||
});
|
});
|
||||||
tray.menu = menu;
|
tray.tooltip = 'Ema Libre Carpincho';
|
||||||
|
// NW.js abre el menú nativo con clic derecho; solo emite clic izquierdo.
|
||||||
// Click izquierdo: mostrar ventana
|
tray.on('click', mostrarVentana);
|
||||||
tray.on('click', () => {
|
|
||||||
console.log('Tray icon clicked');
|
|
||||||
win.show();
|
|
||||||
win.restore();
|
|
||||||
win.focus();
|
|
||||||
win.setShowInTaskbar(true);
|
|
||||||
removeTray();
|
|
||||||
if (typeof MuestraRegistroActual === 'function') MuestraRegistroActual(false);
|
|
||||||
if (typeof Graficos === 'function') Graficos();
|
|
||||||
if (typeof ClimaActual === 'function') ClimaActual();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Click derecho: abrir menú manualmente si el entorno no lo hace
|
|
||||||
tray.on('right-click', () => {
|
|
||||||
console.log('Tray icon right-clicked');
|
|
||||||
tray.menu.popup();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Doble click: también mostrar
|
|
||||||
tray.on('double-click', () => {
|
|
||||||
win.show();
|
|
||||||
win.focus();
|
|
||||||
win.setShowInTaskbar(true);
|
|
||||||
removeTray();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
nw.Window.get().on('loaded', createTray);
|
win.on('loaded', createTray);
|
||||||
|
win.on('minimize', () => {
|
||||||
|
ventanaMinimizada = true;
|
||||||
|
ocultarVentana();
|
||||||
|
});
|
||||||
|
|
||||||
// Window resizing is handled by responsive CSS; preserve manual zoom.
|
// Window resizing is handled by responsive CSS; preserve manual zoom.
|
||||||
|
|
||||||
@ -171,7 +152,6 @@ if (_IS_NW) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
// **********************Vairales Generales*********************
|
// **********************Vairales Generales*********************
|
||||||
let tray = null;
|
|
||||||
var UltimoReg;
|
var UltimoReg;
|
||||||
var Ant_UltimoReg;
|
var Ant_UltimoReg;
|
||||||
var ModeloVisor; // Variables Generales - Registros recolectados
|
var ModeloVisor; // Variables Generales - Registros recolectados
|
||||||
@ -204,7 +184,7 @@ function INICIAR () {
|
|||||||
HABLA(0, 'Se inicio en modo Recolector', 'success');
|
HABLA(0, 'Se inicio en modo Recolector', 'success');
|
||||||
$('#signal').addClass('parpadea');
|
$('#signal').addClass('parpadea');
|
||||||
}
|
}
|
||||||
if (_IS_NW) tray.icon = iconoEncendido;
|
if (_IS_NW) { createTray(); tray.icon = iconoEncendido; }
|
||||||
$('td#barralateral').css('background-color', '#11881161');
|
$('td#barralateral').css('background-color', '#11881161');
|
||||||
$('#estado').html('En Linea');
|
$('#estado').html('En Linea');
|
||||||
$('#mensaje').html('Encendido');
|
$('#mensaje').html('Encendido');
|
||||||
@ -268,7 +248,7 @@ function killAllTimers() {
|
|||||||
function DETENER () {
|
function DETENER () {
|
||||||
clearInterval(intervaloBarra);
|
clearInterval(intervaloBarra);
|
||||||
killAllTimers();
|
killAllTimers();
|
||||||
if (_IS_NW) tray.icon = iconoApagado;
|
if (_IS_NW) { createTray(); tray.icon = iconoApagado; }
|
||||||
$('td#barralateral').css('background-color', '#ff000030');
|
$('td#barralateral').css('background-color', '#ff000030');
|
||||||
$('#estado').html('Fuera de Linea');
|
$('#estado').html('Fuera de Linea');
|
||||||
$('#img_estado').attr('src', iconoNeutro);
|
$('#img_estado').attr('src', iconoNeutro);
|
||||||
|
|||||||
@ -5,9 +5,49 @@ const ConfigUI = (() => {
|
|||||||
const values = () => Object.fromEntries(Object.keys(ConfiguracionModelo.fields).map(id => [id, document.getElementById(id)?.value ?? '']));
|
const values = () => Object.fromEntries(Object.keys(ConfiguracionModelo.fields).map(id => [id, document.getElementById(id)?.value ?? '']));
|
||||||
const snapshot = () => JSON.stringify(values());
|
const snapshot = () => JSON.stringify(values());
|
||||||
const dirty = () => !!form() && baseline !== snapshot();
|
const dirty = () => !!form() && baseline !== snapshot();
|
||||||
function message(text, error = false) {
|
let notification;
|
||||||
|
function notify(text, error) {
|
||||||
|
if (notification) {
|
||||||
|
bootstrap.Toast.getInstance(notification)?.dispose();
|
||||||
|
notification.remove();
|
||||||
|
}
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.className = 'toast position-fixed top-0 end-0 m-3 border-0 shadow text-bg-' + (error ? 'danger' : 'success');
|
||||||
|
toast.style.zIndex = '1090';
|
||||||
|
toast.style.maxWidth = 'calc(100vw - 2rem)';
|
||||||
|
toast.setAttribute('role', error ? 'alert' : 'status');
|
||||||
|
toast.setAttribute('aria-live', error ? 'assertive' : 'polite');
|
||||||
|
toast.setAttribute('aria-atomic', 'true');
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = 'd-flex';
|
||||||
|
const body = document.createElement('div');
|
||||||
|
body.className = 'toast-body';
|
||||||
|
const title = document.createElement('strong');
|
||||||
|
title.className = 'd-block mb-1';
|
||||||
|
title.textContent = error ? 'No se pudo guardar' : 'Configuración guardada';
|
||||||
|
const detail = document.createElement('div');
|
||||||
|
detail.textContent = text;
|
||||||
|
body.append(title, detail);
|
||||||
|
const close = document.createElement('button');
|
||||||
|
close.type = 'button';
|
||||||
|
close.className = 'btn-close btn-close-white me-2 m-auto';
|
||||||
|
close.setAttribute('aria-label', 'Cerrar notificación');
|
||||||
|
close.setAttribute('data-bs-dismiss', 'toast');
|
||||||
|
row.append(body, close);
|
||||||
|
toast.append(row);
|
||||||
|
document.body.append(toast);
|
||||||
|
notification = toast;
|
||||||
|
toast.addEventListener('hidden.bs.toast', () => {
|
||||||
|
bootstrap.Toast.getInstance(toast)?.dispose();
|
||||||
|
toast.remove();
|
||||||
|
if (notification === toast) notification = null;
|
||||||
|
});
|
||||||
|
new bootstrap.Toast(toast, {autohide: !error, delay: 5000}).show();
|
||||||
|
}
|
||||||
|
function message(text, error = false, floating = false) {
|
||||||
const status = document.getElementById('config-status');
|
const status = document.getElementById('config-status');
|
||||||
if (status) { status.textContent = text; status.className = error ? 'text-danger' : 'text-white'; }
|
if (status) { status.textContent = text; status.className = error ? 'text-danger' : 'text-white'; }
|
||||||
|
if (floating) notify(text, error);
|
||||||
}
|
}
|
||||||
function canLeave() {
|
function canLeave() {
|
||||||
if (saving) { message('Esperá a que termine el guardado.'); return false; }
|
if (saving) { message('Esperá a que termine el guardado.'); return false; }
|
||||||
@ -72,7 +112,7 @@ const ConfigUI = (() => {
|
|||||||
const data = values();
|
const data = values();
|
||||||
const invalid = ConfiguracionModelo.validate(data);
|
const invalid = ConfiguracionModelo.validate(data);
|
||||||
errors(invalid);
|
errors(invalid);
|
||||||
if (Object.keys(invalid).length) { message('Revisá los campos marcados.', true); return false; }
|
if (Object.keys(invalid).length) { message('Revisá los campos marcados en el formulario.', true, true); return false; }
|
||||||
const draft = ConfiguracionModelo.build(original, data);
|
const draft = ConfiguracionModelo.build(original, data);
|
||||||
saving = true;
|
saving = true;
|
||||||
const controls = [...form().querySelectorAll('input, select, button')];
|
const controls = [...form().querySelectorAll('input, select, button')];
|
||||||
@ -81,11 +121,11 @@ const ConfigUI = (() => {
|
|||||||
message('Guardando…');
|
message('Guardando…');
|
||||||
try {
|
try {
|
||||||
await persist(draft);
|
await persist(draft);
|
||||||
original = draft; baseline = snapshot(); message('Configuración guardada.');
|
original = draft; baseline = snapshot(); message('Configuración guardada.', false, true);
|
||||||
return draft;
|
return draft;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.fields) errors(error.fields);
|
if (error.fields) errors(error.fields);
|
||||||
message(error.message || 'No se pudo guardar. Tus cambios siguen en el formulario.', true);
|
message(error.message || 'Tus cambios siguen en el formulario. Volvé a intentarlo.', true, true);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
saving = false;
|
saving = false;
|
||||||
|
|||||||
@ -21,7 +21,6 @@ const EstadoUI = (() => {
|
|||||||
}
|
}
|
||||||
target.append(box);
|
target.append(box);
|
||||||
};
|
};
|
||||||
const configAction = {label: 'Revisar configuración', run() {document.getElementById('configuracion-tab')?.click();}};
|
|
||||||
if (data.error) {card('Conexión', 'Sin respuesta', data.error, 'danger', {label:'Reintentar', run: refresh}); return;}
|
if (data.error) {card('Conexión', 'Sin respuesta', data.error, 'danger', {label:'Reintentar', run: refresh}); return;}
|
||||||
const visor = data.mode === 'Visor';
|
const visor = data.mode === 'Visor';
|
||||||
const running = data.state?.[0] === true;
|
const running = data.state?.[0] === true;
|
||||||
@ -29,7 +28,7 @@ const EstadoUI = (() => {
|
|||||||
const reason = data.state?.[1];
|
const reason = data.state?.[1];
|
||||||
card('Conexión', visor ? 'Fuente remota' : running ? 'Recolector activo' : 'Recolector detenido',
|
card('Conexión', visor ? 'Fuente remota' : running ? 'Recolector activo' : 'Recolector detenido',
|
||||||
reason || (sensorFault ? 'La estación informa un problema de sensores. Revisá alimentación y señal.' : visor ? 'La fecha de lectura indica la vigencia del dato recibido.' : running ? 'El proceso está activo; revisá la última lectura para confirmar recepción.' : 'Iniciá el recolector desde Inicio o revisá la configuración.'),
|
reason || (sensorFault ? 'La estación informa un problema de sensores. Revisá alimentación y señal.' : visor ? 'La fecha de lectura indica la vigencia del dato recibido.' : running ? 'El proceso está activo; revisá la última lectura para confirmar recepción.' : 'Iniciá el recolector desde Inicio o revisá la configuración.'),
|
||||||
reason || sensorFault ? 'warning' : running ? 'success' : 'secondary', reason || !running ? configAction : null);
|
reason || sensorFault ? 'warning' : running ? 'success' : 'secondary');
|
||||||
const record = data.record;
|
const record = data.record;
|
||||||
const age = Date.now() - date(record?.fecha, data.utc);
|
const age = Date.now() - date(record?.fecha, data.utc);
|
||||||
const stale = Number.isFinite(age) && age > Math.max(120, Number(data.interval || 60) * 3) * 1000;
|
const stale = Number.isFinite(age) && age > Math.max(120, Number(data.interval || 60) * 3) * 1000;
|
||||||
@ -40,7 +39,7 @@ const EstadoUI = (() => {
|
|||||||
const failed = publications.find(p => p.estado !== true && !['Esperar', 'No enviado'].includes(p.estado));
|
const failed = publications.find(p => p.estado !== true && !['Esperar', 'No enviado'].includes(p.estado));
|
||||||
card('Última publicación', last ? `${last.red}: ${last.fecha}` : visor ? 'No corresponde al modo visor' : 'Sin publicaciones',
|
card('Última publicación', last ? `${last.red}: ${last.fecha}` : visor ? 'No corresponde al modo visor' : 'Sin publicaciones',
|
||||||
failed ? `${failed.red}: ${failed.error || 'No se pudo publicar'}. Revisá la red y las credenciales.` : last ? (last.estado === true ? 'Envío confirmado por la red.' : 'La red indica que hay que esperar antes de enviar.') : 'Todavía no hay un envío confirmado.',
|
failed ? `${failed.red}: ${failed.error || 'No se pudo publicar'}. Revisá la red y las credenciales.` : last ? (last.estado === true ? 'Envío confirmado por la red.' : 'La red indica que hay que esperar antes de enviar.') : 'Todavía no hay un envío confirmado.',
|
||||||
failed ? 'danger' : last?.estado === true ? 'success' : 'secondary', failed ? configAction : null);
|
failed ? 'danger' : last?.estado === true ? 'success' : 'secondary');
|
||||||
}
|
}
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
|
|||||||
@ -95,25 +95,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-lg-3 col-centered">
|
<div class="col-12 col-md-6 col-lg-3 col-centered">
|
||||||
<label class="control-label" for="Debug">Debug y Tamaño</label><br>
|
<label class="control-label" for="Debug">Debug y Tamaño</label><br>
|
||||||
<select id='Debug' name="Debug" class="form-select">
|
<div class="input-group flex-nowrap">
|
||||||
<optgroup label="Normal">
|
<select id='Debug' name="Debug" class="form-select">
|
||||||
<option value="1">1</option>
|
<optgroup label="Normal">
|
||||||
<option value="2">2</option>
|
<option value="1">1</option>
|
||||||
<option value="3">3</option>
|
<option value="2">2</option>
|
||||||
</optgroup>
|
<option value="3">3</option>
|
||||||
<optgroup label="Alto">
|
</optgroup>
|
||||||
<option value="4">4</option>
|
<optgroup label="Alto">
|
||||||
<option value="5">5</option>
|
<option value="4">4</option>
|
||||||
<option value="6">6</option>
|
<option value="5">5</option>
|
||||||
</optgroup>
|
<option value="6">6</option>
|
||||||
<optgroup label="Muy Alto">
|
</optgroup>
|
||||||
<option value="7">7</option>
|
<optgroup label="Muy Alto">
|
||||||
<option value="8">8</option>
|
<option value="7">7</option>
|
||||||
<option value="9">9</option>
|
<option value="8">8</option>
|
||||||
</optgroup>
|
<option value="9">9</option>
|
||||||
</select>
|
</optgroup>
|
||||||
<input type="text" class="form-control" id="debugMB" placeholder="MB Debug" maxlength="5" size="5">
|
</select>
|
||||||
<label class="control-label">MB</label>
|
<input type="text" class="form-control" id="debugMB" aria-label="Tamaño máximo del debug en MB" placeholder="MB Debug" maxlength="5" size="5">
|
||||||
|
<span class="input-group-text">MB</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-lg-1 col-centered">
|
<div class="col-12 col-md-6 col-lg-1 col-centered">
|
||||||
<label class="control-label" for="utc">UTC</label><br>
|
<label class="control-label" for="utc">UTC</label><br>
|
||||||
|
|||||||
@ -10,3 +10,23 @@
|
|||||||
27/09/2026 23:21:09 - 0|CORE|✅ Modulo node-hid cargado correctamente.
|
27/09/2026 23:21:09 - 0|CORE|✅ Modulo node-hid cargado correctamente.
|
||||||
27/09/2026 23:21:09 - 0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.
|
27/09/2026 23:21:09 - 0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.
|
||||||
27/09/2026 23:23:30 - 0|CORE|🔚 SALIR: Se cerro el core de EMA LIBRE. Hasta luego!!!.
|
27/09/2026 23:23:30 - 0|CORE|🔚 SALIR: Se cerro el core de EMA LIBRE. Hasta luego!!!.
|
||||||
|
28/09/2026 21:04:14 - 0|CORE|🕵️. Buscando Modulo USB para el S.O - linux_x64_gui
|
||||||
|
28/09/2026 21:04:14 - 0|CORE|✅ Modulo node-hid cargado correctamente.
|
||||||
|
28/09/2026 21:04:14 - 0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.
|
||||||
|
28/09/2026 21:09:57 - 0|CORE|🔚 SALIR: Se cerro el core de EMA LIBRE. Hasta luego!!!.
|
||||||
|
28/09/2026 21:10:04 - 0|CORE|🕵️. Buscando Modulo USB para el S.O - linux_x64_gui
|
||||||
|
28/09/2026 21:10:04 - 0|CORE|✅ Modulo node-hid cargado correctamente.
|
||||||
|
28/09/2026 21:10:04 - 0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.
|
||||||
|
28/09/2026 21:11:11 - 0|CORE|🔚 SALIR: Se cerro el core de EMA LIBRE. Hasta luego!!!.
|
||||||
|
28/09/2026 21:12:28 - 0|CORE|🕵️. Buscando Modulo USB para el S.O - linux_x64_gui
|
||||||
|
28/09/2026 21:12:28 - 0|CORE|✅ Modulo node-hid cargado correctamente.
|
||||||
|
28/09/2026 21:12:28 - 0|CORE|⏳ Iniciando Ema Libre en Modo gráfico o Web.
|
||||||
|
28/09/2026 21:25:06 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:25:10 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:25:40 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:25:44 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:25:55 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:27:46 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:28:00 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:28:39 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
28/09/2026 21:28:47 - 0|CORE|⚙️ RECONFIGURANDO: Se reconfigura el recolectorde EMA LIBRE.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user