mirror of
https://git.sanhost.net/sanasol/hytale-f2p
synced 2026-02-26 14:01:48 -03:00
Collects launcher logs, game client logs, and config snapshot into a ZIP file and uploads to auth server. Shows submission ID for sharing with support. Includes i18n for all 11 locales.
206 lines
7.4 KiB
JavaScript
206 lines
7.4 KiB
JavaScript
|
|
// Logs Page Logic
|
|
|
|
async function loadLogs() {
|
|
const terminal = document.getElementById('logsTerminal');
|
|
if (!terminal) return;
|
|
|
|
terminal.innerHTML = '<div class="text-gray-500 text-center mt-10">Loading logs...</div>';
|
|
|
|
try {
|
|
const logs = await window.electronAPI.getRecentLogs(500); // Fetch last 500 lines
|
|
|
|
if (logs) {
|
|
// Escape HTML to prevent XSS and preserve format
|
|
const safeLogs = logs.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
|
|
terminal.innerHTML = `<pre class="logs-content">${safeLogs}</pre>`;
|
|
|
|
// Auto scroll to bottom
|
|
terminal.scrollTop = terminal.scrollHeight;
|
|
} else {
|
|
terminal.innerHTML = '<div class="text-gray-500 text-center mt-10">No logs found.</div>';
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load logs:', error);
|
|
terminal.innerHTML = `<div class="text-red-500 text-center mt-10">Error loading logs: ${error.message}</div>`;
|
|
}
|
|
}
|
|
|
|
async function refreshLogs() {
|
|
const btn = document.querySelector('button[onclick="refreshLogs()"] i');
|
|
if (btn) btn.classList.add('fa-spin');
|
|
|
|
await loadLogs();
|
|
|
|
if (btn) setTimeout(() => btn.classList.remove('fa-spin'), 500);
|
|
}
|
|
|
|
async function copyLogs() {
|
|
const terminal = document.getElementById('logsTerminal');
|
|
if (!terminal) return;
|
|
|
|
const content = terminal.innerText;
|
|
if (!content) return;
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(content);
|
|
|
|
const btn = document.querySelector('button[onclick="copyLogs()"]');
|
|
const originalText = btn.innerHTML;
|
|
|
|
btn.innerHTML = '<i class="fas fa-check"></i> Copied!';
|
|
setTimeout(() => {
|
|
btn.innerHTML = originalText;
|
|
}, 2000);
|
|
} catch (err) {
|
|
console.error('Failed to copy logs:', err);
|
|
}
|
|
}
|
|
|
|
async function openLogsFolder() {
|
|
await window.electronAPI.openLogsFolder();
|
|
}
|
|
|
|
async function sendLogs() {
|
|
const btn = document.getElementById('sendLogsBtn');
|
|
if (!btn || btn.disabled) return;
|
|
|
|
// Get i18n strings with fallbacks
|
|
const i18n = window.i18n || {};
|
|
const sendingText = (i18n.settings && i18n.settings.logsSending) || 'Sending...';
|
|
const sentText = (i18n.settings && i18n.settings.logsSent) || 'Sent!';
|
|
const failedText = (i18n.settings && i18n.settings.logsSendFailed) || 'Failed';
|
|
const sendText = (i18n.settings && i18n.settings.logsSend) || 'Send Logs';
|
|
|
|
const originalHTML = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${sendingText}`;
|
|
|
|
try {
|
|
const result = await window.electronAPI.sendLogs();
|
|
|
|
if (result.success) {
|
|
btn.innerHTML = `<i class="fas fa-check"></i> ${sentText}`;
|
|
showLogSubmissionResult(result.id);
|
|
} else {
|
|
btn.innerHTML = `<i class="fas fa-times"></i> ${failedText}`;
|
|
console.error('Send logs failed:', result.error);
|
|
|
|
// Show error notification if available
|
|
if (window.LauncherUI && window.LauncherUI.showNotification) {
|
|
window.LauncherUI.showNotification(result.error || 'Failed to send logs', 'error');
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('Send logs error:', err);
|
|
btn.innerHTML = `<i class="fas fa-times"></i> ${failedText}`;
|
|
}
|
|
|
|
setTimeout(() => {
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHTML;
|
|
}, 3000);
|
|
}
|
|
|
|
function showLogSubmissionResult(id) {
|
|
// Remove existing popup if any
|
|
const existing = document.getElementById('logSubmissionPopup');
|
|
if (existing) existing.remove();
|
|
|
|
const i18n = window.i18n || {};
|
|
const idLabel = (i18n.settings && i18n.settings.logsSubmissionId) || 'Submission ID';
|
|
const copyText = (i18n.common && i18n.common.copy) || 'Copy';
|
|
const closeText = (i18n.common && i18n.common.close) || 'Close';
|
|
const shareText = (i18n.settings && i18n.settings.logsShareId) || 'Share this ID with support when reporting issues';
|
|
|
|
const popup = document.createElement('div');
|
|
popup.id = 'logSubmissionPopup';
|
|
popup.style.cssText = `
|
|
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
|
background: rgba(20, 20, 35, 0.98); border: 1px solid rgba(0, 212, 255, 0.3);
|
|
border-radius: 12px; padding: 24px 32px; z-index: 10000;
|
|
box-shadow: 0 20px 60px rgba(0,0,0,0.5); text-align: center;
|
|
min-width: 320px; backdrop-filter: blur(10px);
|
|
`;
|
|
|
|
popup.innerHTML = `
|
|
<div style="margin-bottom: 16px;">
|
|
<i class="fas fa-check-circle" style="font-size: 2em; color: #00d4ff;"></i>
|
|
</div>
|
|
<div style="color: #888; font-size: 0.85em; margin-bottom: 8px;">${idLabel}</div>
|
|
<div id="logSubId" style="font-family: monospace; font-size: 1.5em; color: #00d4ff; letter-spacing: 2px; margin-bottom: 12px; user-select: all;">${id}</div>
|
|
<div style="color: #666; font-size: 0.8em; margin-bottom: 20px;">${shareText}</div>
|
|
<div style="display: flex; gap: 10px; justify-content: center;">
|
|
<button onclick="copyLogSubmissionId('${id}')" style="
|
|
background: rgba(0,212,255,0.2); border: 1px solid rgba(0,212,255,0.3);
|
|
color: #00d4ff; padding: 8px 20px; border-radius: 6px; cursor: pointer;
|
|
font-size: 0.9em;
|
|
"><i class="fas fa-copy"></i> ${copyText}</button>
|
|
<button onclick="document.getElementById('logSubmissionPopup').remove()" style="
|
|
background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2);
|
|
color: #ccc; padding: 8px 20px; border-radius: 6px; cursor: pointer;
|
|
font-size: 0.9em;
|
|
">${closeText}</button>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(popup);
|
|
|
|
// Auto-close after 30s
|
|
setTimeout(() => {
|
|
if (document.getElementById('logSubmissionPopup')) {
|
|
popup.remove();
|
|
}
|
|
}, 30000);
|
|
}
|
|
|
|
async function copyLogSubmissionId(id) {
|
|
try {
|
|
await navigator.clipboard.writeText(id);
|
|
const btn = event.target.closest('button');
|
|
if (btn) {
|
|
const orig = btn.innerHTML;
|
|
btn.innerHTML = '<i class="fas fa-check"></i> Copied!';
|
|
setTimeout(() => { btn.innerHTML = orig; }, 1500);
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to copy submission ID:', err);
|
|
}
|
|
}
|
|
|
|
function openLogs() {
|
|
// Navigation is handled by sidebar logic, but we can trigger a refresh
|
|
window.LauncherUI.showPage('logs-page');
|
|
window.LauncherUI.setActiveNav('logs');
|
|
refreshLogs();
|
|
}
|
|
|
|
// Expose functions globally
|
|
window.refreshLogs = refreshLogs;
|
|
window.copyLogs = copyLogs;
|
|
window.openLogsFolder = openLogsFolder;
|
|
window.sendLogs = sendLogs;
|
|
window.copyLogSubmissionId = copyLogSubmissionId;
|
|
window.openLogs = openLogs;
|
|
|
|
// Auto-load logs when the page becomes active
|
|
const logsObserver = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutation) => {
|
|
if (mutation.target.classList.contains('active') && mutation.target.id === 'logs-page') {
|
|
loadLogs();
|
|
}
|
|
});
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const logsPage = document.getElementById('logs-page');
|
|
if (logsPage) {
|
|
logsObserver.observe(logsPage, { attributes: true, attributeFilter: ['class'] });
|
|
}
|
|
});
|