fix(electron): added macos file associations

This commit is contained in:
2025-08-11 08:30:44 -04:00
parent 6c53e9ca6c
commit d7d7615376
18 changed files with 2497 additions and 43 deletions

View File

@@ -7,9 +7,18 @@ let stateManager, domManager, opatPlotting;
// OPAT File Inspector variables
let opatFileInput, opatBrowseBtn, opatView, opatCloseBtn;
let opatHeaderInfo, opatAllTagsList, opatIndexSelector, opatTablesDisplay, opatTableDataContent;
let opatElementsInitialized = false;
// Initialize OPAT UI elements
function initializeOPATElements() {
console.log('[OPAT_HANDLER] initializeOPATElements called, already initialized:', opatElementsInitialized);
// Prevent duplicate initialization
if (opatElementsInitialized) {
console.log('[OPAT_HANDLER] OPAT elements already initialized, skipping...');
return;
}
opatFileInput = document.getElementById('opat-file-input');
opatBrowseBtn = document.getElementById('opat-browse-btn');
opatView = document.getElementById('opat-view');
@@ -20,11 +29,41 @@ function initializeOPATElements() {
opatTablesDisplay = document.getElementById('opat-tables-display');
opatTableDataContent = document.getElementById('opat-table-data-content');
console.log('[OPAT_HANDLER] Found elements:', {
opatFileInput: !!opatFileInput,
opatBrowseBtn: !!opatBrowseBtn,
opatView: !!opatView,
opatCloseBtn: !!opatCloseBtn
});
// Event listeners
opatBrowseBtn.addEventListener('click', () => opatFileInput.click());
opatFileInput.addEventListener('change', handleOPATFileSelection);
opatIndexSelector.addEventListener('change', handleIndexVectorChange);
opatCloseBtn.addEventListener('click', closeOPATFile);
if (opatBrowseBtn) {
console.log('[OPAT_HANDLER] Adding click listener to browse button');
opatBrowseBtn.addEventListener('click', () => {
console.log('[OPAT_HANDLER] Browse button clicked, triggering file input');
if (opatFileInput) {
opatFileInput.click();
} else {
console.error('[OPAT_HANDLER] File input element not found!');
}
});
}
if (opatFileInput) {
console.log('[OPAT_HANDLER] Adding change listener to file input');
opatFileInput.addEventListener('change', handleOPATFileSelection);
}
if (opatIndexSelector) {
opatIndexSelector.addEventListener('change', handleIndexVectorChange);
}
if (opatCloseBtn) {
opatCloseBtn.addEventListener('click', closeOPATFile);
}
opatElementsInitialized = true;
console.log('[OPAT_HANDLER] OPAT elements initialization complete');
// Initialize OPAT tab navigation
initializeOPATTabs();
@@ -96,48 +135,171 @@ function resetOPATViewerState() {
// Handle OPAT file selection
async function handleOPATFileSelection(event) {
const file = event.target.files[0];
if (!file) return;
console.log('[OPAT_HANDLER] ===== FILE SELECTION EVENT TRIGGERED =====');
console.log('[OPAT_HANDLER] Event target:', event.target);
console.log('[OPAT_HANDLER] Files array:', event.target.files);
console.log('[OPAT_HANDLER] Number of files:', event.target.files ? event.target.files.length : 0);
const file = event.target.files[0];
if (!file) {
console.log('[OPAT_HANDLER] No file selected - event fired but no file found');
return;
}
console.log('[OPAT_HANDLER] File selected:', {
name: file.name,
size: file.size,
type: file.type,
lastModified: new Date(file.lastModified)
});
try {
console.log('Loading OPAT file:', file.name);
domManager.showSpinner();
console.log('[OPAT_HANDLER] Starting file processing...');
// Reset the viewer state
console.log('[OPAT_HANDLER] Resetting viewer state...');
resetOPATViewerState();
// Show the OPAT view first to ensure UI is visible
console.log('[OPAT_HANDLER] Showing OPAT view...');
domManager.showView('opat-view');
// Read and parse the file
console.log('[OPAT_HANDLER] Reading file as ArrayBuffer...');
const arrayBuffer = await file.arrayBuffer();
const currentOPATFile = parseOPAT(arrayBuffer);
stateManager.setOPATFile(currentOPATFile);
console.log('[OPAT_HANDLER] File read successfully, arrayBuffer size:', arrayBuffer.byteLength);
displayOPATFileInfo();
displayAllTableTags();
populateIndexSelector();
// Check if parseOPAT is available
console.log('[OPAT_HANDLER] Checking parseOPAT availability...');
console.log('[OPAT_HANDLER] typeof parseOPAT:', typeof parseOPAT);
console.log('[OPAT_HANDLER] window.parseOPAT:', typeof window.parseOPAT);
// Populate plotting selectors if module is available
if (opatPlotting) {
opatPlotting.populatePlotIndexSelector();
if (typeof parseOPAT === 'undefined' && typeof window.parseOPAT === 'undefined') {
throw new Error('parseOPAT function is not available. Make sure opatParser.js is loaded.');
}
// Show OPAT view
hideAllViews();
opatView.classList.remove('hidden');
// Use global parseOPAT if local one is undefined
const parseFunction = typeof parseOPAT !== 'undefined' ? parseOPAT : window.parseOPAT;
console.log('[OPAT_HANDLER] Using parse function:', typeof parseFunction);
domManager.hideSpinner();
console.log('OPAT file loaded successfully');
console.log('[OPAT_HANDLER] Calling parseOPAT...');
const currentOPATFile = parseFunction(arrayBuffer);
console.log('[OPAT_HANDLER] Parse result:', currentOPATFile ? 'SUCCESS' : 'FAILED');
console.log('[OPAT_HANDLER] Parsed file object:', currentOPATFile);
if (currentOPATFile) {
console.log('[OPAT_HANDLER] Setting file in state manager...');
stateManager.setOPATFile(currentOPATFile);
// Display file information
console.log('[OPAT_HANDLER] Displaying file information...');
displayOPATFileInfo();
displayAllTableTags();
populateIndexSelector();
console.log('[OPAT_HANDLER] ===== OPAT FILE LOADED SUCCESSFULLY =====');
} else {
console.error('[OPAT_HANDLER] parseOPAT returned null/undefined');
domManager.showModal('Error', 'Failed to parse OPAT file. Please check the file format.');
}
} catch (error) {
console.error('Error loading OPAT file:', error);
domManager.hideSpinner();
alert('Error loading OPAT file: ' + error.message);
console.error('[OPAT_HANDLER] ===== ERROR IN FILE PROCESSING =====');
console.error('[OPAT_HANDLER] Error details:', error);
console.error('[OPAT_HANDLER] Error stack:', error.stack);
domManager.showModal('Error', `Failed to load OPAT file: ${error.message}`);
} finally {
console.log('[OPAT_HANDLER] Cleaning up file input...');
// Clear the file input to prevent issues with reopening the same file
if (event.target) {
event.target.value = '';
console.log('[OPAT_HANDLER] File input cleared');
}
console.log('[OPAT_HANDLER] ===== FILE SELECTION HANDLER COMPLETE =====');
}
}
// Open OPAT file from file path (for file associations)
async function openOpatFromPath(filePath) {
if (!filePath) {
console.log('[OPAT_HANDLER] openOpatFromPath: No file path provided');
return;
}
try {
console.log('[OPAT_HANDLER] Opening OPAT file from path:', filePath);
// Ensure OPAT UI elements are initialized
console.log('[OPAT_HANDLER] Initializing OPAT UI elements...');
initializeOPATElements();
initializeOPATTabs();
// Reset the viewer state
resetOPATViewerState();
// Show the OPAT view first to ensure UI is visible
console.log('[OPAT_HANDLER] Showing OPAT view...');
domManager.showView('opat-view');
// Read the file using Node.js fs
const fs = require('fs');
console.log('[OPAT_HANDLER] Reading file from disk...');
const fileBuffer = fs.readFileSync(filePath);
const arrayBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
console.log('[OPAT_HANDLER] File read successfully, arrayBuffer size:', arrayBuffer.byteLength);
// Parse the OPAT file
console.log('[OPAT_HANDLER] Parsing OPAT file...');
if (typeof parseOPAT === 'undefined') {
throw new Error('parseOPAT function is not available. Make sure opatParser.js is loaded.');
}
const currentOPATFile = parseOPAT(arrayBuffer);
console.log('[OPAT_HANDLER] Parse result:', currentOPATFile ? 'SUCCESS' : 'FAILED');
if (currentOPATFile) {
console.log('[OPAT_HANDLER] Setting file in state manager...');
stateManager.setOPATFile(currentOPATFile);
// Display file information
console.log('[OPAT_HANDLER] Displaying file information...');
displayOPATFileInfo();
displayAllTableTags();
populateIndexSelector();
console.log('[OPAT_HANDLER] OPAT file opened successfully via file association');
} else {
console.error('[OPAT_HANDLER] parseOPAT returned null/undefined for file association');
throw new Error('Failed to parse OPAT file. Please check the file format.');
}
} catch (error) {
console.error('[OPAT_HANDLER] Error opening OPAT file via file association:', error);
domManager.showModal('Error', `Failed to open OPAT file: ${error.message}`);
}
}
// Display OPAT file information
function displayOPATFileInfo() {
console.log('[OPAT_HANDLER] displayOPATFileInfo called');
const currentOPATFile = stateManager.getOPATFile();
if (!currentOPATFile) return;
console.log('[OPAT_HANDLER] Current OPAT file from state:', currentOPATFile);
if (!currentOPATFile) {
console.error('[OPAT_HANDLER] No OPAT file in state manager!');
return;
}
console.log('[OPAT_HANDLER] opatHeaderInfo element:', opatHeaderInfo);
console.log('[OPAT_HANDLER] opatHeaderInfo exists:', !!opatHeaderInfo);
if (!opatHeaderInfo) {
console.error('[OPAT_HANDLER] opatHeaderInfo element not found! Re-initializing...');
opatHeaderInfo = document.getElementById('opat-header-info');
console.log('[OPAT_HANDLER] After re-init, opatHeaderInfo:', !!opatHeaderInfo);
}
const header = currentOPATFile.header;
opatHeaderInfo.innerHTML = `
console.log('[OPAT_HANDLER] Header object:', header);
const headerHTML = `
<div class="opat-info-section">
<h4 class="opat-section-title">Header Information</h4>
<div class="info-grid">
@@ -155,14 +317,42 @@ function displayOPATFileInfo() {
</div>
`;
console.log('[OPAT_HANDLER] Generated header HTML length:', headerHTML.length);
if (opatHeaderInfo) {
opatHeaderInfo.innerHTML = headerHTML;
console.log('[OPAT_HANDLER] Header info updated successfully');
console.log('[OPAT_HANDLER] opatHeaderInfo.innerHTML length:', opatHeaderInfo.innerHTML.length);
} else {
console.error('[OPAT_HANDLER] Cannot update header info - element still not found');
}
// Display all unique table tags
console.log('[OPAT_HANDLER] Calling displayAllTableTags...');
displayAllTableTags();
}
// Display all table tags
function displayAllTableTags() {
console.log('[OPAT_HANDLER] displayAllTableTags called');
const currentOPATFile = stateManager.getOPATFile();
if (!currentOPATFile) return;
console.log('[OPAT_HANDLER] Current OPAT file in displayAllTableTags:', currentOPATFile);
if (!currentOPATFile) {
console.error('[OPAT_HANDLER] No OPAT file in displayAllTableTags!');
return;
}
console.log('[OPAT_HANDLER] opatAllTagsList element:', opatAllTagsList);
console.log('[OPAT_HANDLER] opatAllTagsList exists:', !!opatAllTagsList);
if (!opatAllTagsList) {
console.error('[OPAT_HANDLER] opatAllTagsList element not found! Re-initializing...');
opatAllTagsList = document.getElementById('opat-all-tags-list');
console.log('[OPAT_HANDLER] After re-init, opatAllTagsList:', !!opatAllTagsList);
}
console.log('[OPAT_HANDLER] Number of cards:', currentOPATFile.cards.size);
const allTags = new Set();
for (const card of currentOPATFile.cards.values()) {
@@ -171,12 +361,19 @@ function displayAllTableTags() {
}
}
opatAllTagsList.innerHTML = '';
Array.from(allTags).sort().forEach(tag => {
const li = document.createElement('li');
li.textContent = tag;
opatAllTagsList.appendChild(li);
});
console.log('[OPAT_HANDLER] Found', allTags.size, 'unique tags:', Array.from(allTags));
if (opatAllTagsList) {
opatAllTagsList.innerHTML = '';
Array.from(allTags).sort().forEach(tag => {
const li = document.createElement('li');
li.textContent = tag;
opatAllTagsList.appendChild(li);
});
console.log('[OPAT_HANDLER] Tags list updated successfully');
} else {
console.error('[OPAT_HANDLER] Cannot update tags list - element still not found');
}
}
// Populate index selector
@@ -398,6 +595,7 @@ module.exports = {
initializeOPATTabs,
resetOPATViewerState,
handleOPATFileSelection,
openOpatFromPath,
displayOPATFileInfo,
displayAllTableTags,
populateIndexSelector,