style(electron): more ui bug fixes
This commit is contained in:
@@ -207,7 +207,7 @@ function setupInfoModal() {
|
||||
|
||||
// Info tab navigation
|
||||
infoTabLinks.forEach(link => {
|
||||
link.addEventListener('click', (e) => {
|
||||
link.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
const targetTab = link.dataset.tab;
|
||||
|
||||
@@ -218,6 +218,14 @@ function setupInfoModal() {
|
||||
link.classList.add('active');
|
||||
const targetPane = document.getElementById(targetTab);
|
||||
if (targetPane) targetPane.classList.add('active');
|
||||
|
||||
// Load license content when license tab is clicked
|
||||
if (targetTab === 'license-info-tab') {
|
||||
console.log('[FRONTEND] License tab clicked, loading content...');
|
||||
await loadLicenseContent();
|
||||
} else {
|
||||
console.log(`[FRONTEND] Tab clicked: ${targetTab}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -226,7 +234,9 @@ function setupInfoModal() {
|
||||
if (githubLink) {
|
||||
githubLink.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
ipcRenderer.invoke('open-external-url', 'https://github.com/tboudreaux/4DSTAR');
|
||||
// Get the URL from the href attribute instead of hardcoding
|
||||
const url = githubLink.getAttribute('href');
|
||||
ipcRenderer.invoke('open-external-url', url);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -237,6 +247,47 @@ function hideInfoModal() {
|
||||
if (infoModal) infoModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Load license content from LICENSE.txt file
|
||||
async function loadLicenseContent() {
|
||||
console.log('[FRONTEND] loadLicenseContent() called');
|
||||
const licenseTextarea = document.querySelector('.license-text');
|
||||
console.log('[FRONTEND] License textarea found:', licenseTextarea);
|
||||
if (!licenseTextarea) {
|
||||
console.error('[FRONTEND] License textarea not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't reload if already loaded (not placeholder)
|
||||
if (licenseTextarea.value && !licenseTextarea.value.includes('GPL v3 license text will be pasted here')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[FRONTEND] Requesting license content...');
|
||||
const result = await ipcRenderer.invoke('read-license');
|
||||
console.log('[FRONTEND] License result:', result);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`[FRONTEND] License content length: ${result.content.length} characters`);
|
||||
console.log(`[FRONTEND] License starts with: "${result.content.substring(0, 100)}..."`);
|
||||
console.log(`[FRONTEND] License ends with: "...${result.content.substring(result.content.length - 100)}"`);
|
||||
|
||||
licenseTextarea.value = result.content;
|
||||
licenseTextarea.placeholder = '';
|
||||
// Scroll to the top to show the beginning of the license
|
||||
licenseTextarea.scrollTop = 0;
|
||||
} else {
|
||||
licenseTextarea.value = result.content; // Fallback error message
|
||||
licenseTextarea.placeholder = '';
|
||||
console.error('Failed to load license:', result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading license content:', error);
|
||||
licenseTextarea.value = 'Error loading license content. Please check that LICENSE.txt exists in the application directory.';
|
||||
licenseTextarea.placeholder = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle save metadata with option for save as new
|
||||
async function handleSaveMetadata(saveAsNew = false) {
|
||||
const currentBundlePath = stateManager.getCurrentBundlePath();
|
||||
|
||||
@@ -185,7 +185,46 @@ function setupFillTargetEventListeners() {
|
||||
return;
|
||||
}
|
||||
|
||||
await startFillProcess(selectedTargetsByPlugin);
|
||||
// Show signature warning before starting fill process
|
||||
const currentBundle = stateManager.getCurrentBundle();
|
||||
console.log('[FRONTEND] Checking signature for modal:', currentBundle);
|
||||
console.log('[FRONTEND] Bundle report:', currentBundle?.report);
|
||||
console.log('[FRONTEND] Signature info:', currentBundle?.report?.signature);
|
||||
console.log('[FRONTEND] Full signature object:', JSON.stringify(currentBundle?.report?.signature, null, 2));
|
||||
|
||||
// Check multiple possible signature indicators
|
||||
const signature = currentBundle?.report?.signature;
|
||||
const isSignedBundle = signature && (
|
||||
signature.valid === true ||
|
||||
signature.status === 'VALID' ||
|
||||
signature.status === 'SIGNED' ||
|
||||
(signature.fingerprint && signature.fingerprint !== '') ||
|
||||
(signature.publicKeyFingerprint && signature.publicKeyFingerprint !== '') ||
|
||||
signature.verified === true
|
||||
);
|
||||
|
||||
console.log('[FRONTEND] Signature check result:', isSignedBundle);
|
||||
console.log('[FRONTEND] Signature properties:', {
|
||||
valid: signature?.valid,
|
||||
status: signature?.status,
|
||||
fingerprint: signature?.fingerprint,
|
||||
publicKeyFingerprint: signature?.publicKeyFingerprint,
|
||||
verified: signature?.verified
|
||||
});
|
||||
|
||||
if (currentBundle && currentBundle.report && isSignedBundle) {
|
||||
console.log('[FRONTEND] Bundle is signed, showing confirmation dialog');
|
||||
const confirmed = confirm('Warning: Signature Will Be Invalidated\n\nBuilding new binaries will invalidate the current bundle signature. The bundle will need to be re-signed after the fill process completes.\n\nDo you want to continue?');
|
||||
if (confirmed) {
|
||||
console.log('[FRONTEND] User confirmed, starting fill process');
|
||||
await startFillProcess(selectedTargetsByPlugin);
|
||||
} else {
|
||||
console.log('[FRONTEND] User cancelled fill process due to signature warning');
|
||||
}
|
||||
} else {
|
||||
console.log('[FRONTEND] Bundle is not signed or signature is invalid, proceeding without warning');
|
||||
await startFillProcess(selectedTargetsByPlugin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -198,15 +237,35 @@ function populateFillProgress(selectedTargetsByPlugin) {
|
||||
targets.forEach(target => {
|
||||
const progressItem = document.createElement('div');
|
||||
progressItem.className = 'fill-progress-item';
|
||||
progressItem.id = `progress-${target.triplet}`;
|
||||
// Create unique ID using both plugin and target to avoid duplicates
|
||||
progressItem.id = `progress-${pluginName}-${target.triplet}`;
|
||||
progressItem.innerHTML = `
|
||||
<div class="progress-target">${pluginName}: ${target.triplet}</div>
|
||||
<div class="progress-status">Waiting...</div>
|
||||
<div class="progress-status building">
|
||||
<span class="spinner"></span>
|
||||
Building...
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style="width: 0%"></div>
|
||||
</div>
|
||||
<div class="progress-logs">
|
||||
<button class="toggle-logs-btn">Hide Build Output</button>
|
||||
<div class="logs-content">
|
||||
<pre class="terminal-output">Starting build...\n</pre>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
elements.fillProgressContent.appendChild(progressItem);
|
||||
|
||||
// Add toggle functionality for logs
|
||||
const toggleBtn = progressItem.querySelector('.toggle-logs-btn');
|
||||
const logsContent = progressItem.querySelector('.logs-content');
|
||||
|
||||
toggleBtn.addEventListener('click', () => {
|
||||
const isVisible = !logsContent.classList.contains('hidden');
|
||||
logsContent.classList.toggle('hidden', isVisible);
|
||||
toggleBtn.textContent = isVisible ? 'Show Build Output' : 'Hide Build Output';
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -261,33 +320,98 @@ async function startFillProcess(selectedTargetsByPlugin) {
|
||||
}
|
||||
}
|
||||
|
||||
// Track current building target for stderr routing
|
||||
let currentBuildingTarget = null;
|
||||
|
||||
// Update progress display during fill process
|
||||
function updateFillProgress(progressData) {
|
||||
console.log('Fill progress update:', progressData);
|
||||
|
||||
if (progressData.target) {
|
||||
const progressItem = document.getElementById(`progress-${progressData.target}`);
|
||||
// Handle stderr output - route to current building target
|
||||
if (progressData.type === 'stderr' && progressData.stderr) {
|
||||
console.log(`[FRONTEND] Received stderr: ${progressData.stderr}`);
|
||||
console.log(`[FRONTEND] Current building target: ${currentBuildingTarget}`);
|
||||
|
||||
// Route stderr to the currently building target's terminal
|
||||
if (currentBuildingTarget) {
|
||||
const targetTerminal = document.querySelector(`#progress-${currentBuildingTarget} .terminal-output`);
|
||||
console.log(`[FRONTEND] Found target terminal:`, targetTerminal);
|
||||
if (targetTerminal) {
|
||||
const currentOutput = targetTerminal.textContent;
|
||||
targetTerminal.textContent = currentOutput + progressData.stderr + '\n';
|
||||
|
||||
// Auto-scroll to bottom
|
||||
targetTerminal.scrollTop = targetTerminal.scrollHeight;
|
||||
} else {
|
||||
console.warn(`[FRONTEND] Could not find terminal for target: ${currentBuildingTarget}`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`[FRONTEND] No current building target, adding stderr to all terminals`);
|
||||
// Fallback: add to all terminals if no current target
|
||||
document.querySelectorAll('.terminal-output').forEach(terminalOutput => {
|
||||
const currentOutput = terminalOutput.textContent;
|
||||
terminalOutput.textContent = currentOutput + progressData.stderr + '\n';
|
||||
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (progressData.target && progressData.plugin) {
|
||||
console.log(`[FRONTEND] Processing target update for: ${progressData.plugin}-${progressData.target}, status: ${progressData.status}`);
|
||||
console.log(`[FRONTEND] Looking for element with ID: progress-${progressData.plugin}-${progressData.target}`);
|
||||
|
||||
// Debug: list all existing progress item IDs
|
||||
const allProgressItems = document.querySelectorAll('[id^="progress-"]');
|
||||
console.log(`[FRONTEND] Existing progress item IDs:`, Array.from(allProgressItems).map(item => item.id));
|
||||
|
||||
const progressItem = document.getElementById(`progress-${progressData.plugin}-${progressData.target}`);
|
||||
console.log(`[FRONTEND] Found progress item:`, progressItem);
|
||||
|
||||
if (progressItem) {
|
||||
const statusElement = progressItem.querySelector('.progress-status');
|
||||
const progressBar = progressItem.querySelector('.progress-fill');
|
||||
const logsContainer = progressItem.querySelector('.progress-logs');
|
||||
const terminalOutput = progressItem.querySelector('.terminal-output');
|
||||
|
||||
if (progressData.status) {
|
||||
statusElement.textContent = progressData.status;
|
||||
|
||||
// Update progress bar based on status
|
||||
console.log(`[FRONTEND] Updating status to: ${progressData.status}`);
|
||||
// Update progress bar and status based on status
|
||||
let percentage = 0;
|
||||
switch (progressData.status) {
|
||||
case 'Building':
|
||||
switch (progressData.status.toLowerCase()) {
|
||||
case 'building':
|
||||
percentage = 50;
|
||||
statusElement.className = 'progress-status building';
|
||||
statusElement.innerHTML = '<span class="spinner"></span> Building...';
|
||||
progressItem.className = 'fill-progress-item building';
|
||||
// Track this target as currently building for stderr routing
|
||||
currentBuildingTarget = progressData.target;
|
||||
console.log(`[FRONTEND] Now building target: ${currentBuildingTarget}`);
|
||||
break;
|
||||
case 'Success':
|
||||
case 'success':
|
||||
percentage = 100;
|
||||
statusElement.className = 'progress-status success';
|
||||
statusElement.innerHTML = '✓ Built';
|
||||
progressItem.className = 'fill-progress-item success';
|
||||
if (logsContainer) logsContainer.style.display = 'block';
|
||||
// Clear current building target when done
|
||||
if (currentBuildingTarget === progressData.target) {
|
||||
currentBuildingTarget = null;
|
||||
console.log(`[FRONTEND] Cleared building target after success`);
|
||||
}
|
||||
break;
|
||||
case 'Failed':
|
||||
case 'failure':
|
||||
case 'failed':
|
||||
percentage = 100;
|
||||
statusElement.className = 'progress-status failed';
|
||||
statusElement.innerHTML = '✗ Failed';
|
||||
progressItem.className = 'fill-progress-item failed';
|
||||
if (logsContainer) logsContainer.style.display = 'block';
|
||||
// Clear current building target when done
|
||||
if (currentBuildingTarget === progressData.target) {
|
||||
currentBuildingTarget = null;
|
||||
console.log(`[FRONTEND] Cleared building target after failure`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -295,6 +419,15 @@ function updateFillProgress(progressData) {
|
||||
progressBar.style.width = `${percentage}%`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add stderr output if available (for target-specific messages)
|
||||
if (progressData.stderr && terminalOutput) {
|
||||
const currentOutput = terminalOutput.textContent;
|
||||
terminalOutput.textContent = currentOutput + progressData.stderr + '\n';
|
||||
|
||||
// Auto-scroll to bottom
|
||||
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user