Manager Info UI improvements and voice search enhancements
- Removed duplicate Links section above notes - Updated file icons to use SVG badges (w-3 h-3) - PDF red, Word blue, image icons - Reduced notes viewing area height to 120px with vertical scroll - Voice search: Clear text when all highlighted and mic clicked - Voice search: Replace 'new' with 'latest' in dictations - Voice search: Remove trailing 'job' from dictations - Voice search: Auto-open Manager Info when exactly 1 result found
This commit is contained in:
+84
-134
@@ -698,6 +698,12 @@
|
|||||||
// Remove trailing punctuation (period, comma, etc.)
|
// Remove trailing punctuation (period, comma, etc.)
|
||||||
transcript = transcript.replace(/[.,!?;:]+$/, '');
|
transcript = transcript.replace(/[.,!?;:]+$/, '');
|
||||||
|
|
||||||
|
// Remove trailing "job" if present
|
||||||
|
transcript = transcript.replace(/\s+job$/i, '');
|
||||||
|
|
||||||
|
// Replace "new" with "latest"
|
||||||
|
transcript = transcript.replace(/\bnew\b/gi, 'latest');
|
||||||
|
|
||||||
// Capitalize each word (title case)
|
// Capitalize each word (title case)
|
||||||
transcript = transcript.split(' ').map(word =>
|
transcript = transcript.split(' ').map(word =>
|
||||||
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
||||||
@@ -721,6 +727,16 @@
|
|||||||
// Trigger search with results
|
// Trigger search with results
|
||||||
applyFiltersAndRender();
|
applyFiltersAndRender();
|
||||||
|
|
||||||
|
// If exactly 1 result, automatically open Manager Info
|
||||||
|
if (visibleJobs.length === 1) {
|
||||||
|
const job = visibleJobs[0];
|
||||||
|
currentJob = job;
|
||||||
|
detailModal.classList.remove('hidden');
|
||||||
|
document.getElementById('detailBox').scrollTop = 0;
|
||||||
|
switchTab('managerInfo');
|
||||||
|
populateManagerInfo(job);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if all results are final, if so prepare to stop
|
// Check if all results are final, if so prepare to stop
|
||||||
const allFinal = Array.from(event.results).every(r => r.isFinal);
|
const allFinal = Array.from(event.results).every(r => r.isFinal);
|
||||||
if (allFinal && event.results.length > 0) {
|
if (allFinal && event.results.length > 0) {
|
||||||
@@ -770,6 +786,12 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if text is highlighted and clear it if so
|
||||||
|
if (searchBox.selectionStart === 0 && searchBox.selectionEnd === searchBox.value.length && searchBox.value.length > 0) {
|
||||||
|
searchBox.value = '';
|
||||||
|
baseSearchText = '';
|
||||||
|
}
|
||||||
|
|
||||||
// Request permission first time
|
// Request permission first time
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
const granted = await requestMicPermission();
|
const granted = await requestMicPermission();
|
||||||
@@ -1314,102 +1336,6 @@
|
|||||||
row5.appendChild(estimatedEndDate);
|
row5.appendChild(estimatedEndDate);
|
||||||
managerInfoTable.appendChild(row5);
|
managerInfoTable.appendChild(row5);
|
||||||
|
|
||||||
// Links Section: Plans, Estimates, Documents & Files
|
|
||||||
if(job.Job_Folder_Link && String(job.Job_Folder_Link).trim() !== ''){
|
|
||||||
try {
|
|
||||||
const files = await fetchJobFiles(job);
|
|
||||||
|
|
||||||
// Categorize files
|
|
||||||
const plans = [];
|
|
||||||
const estimates = [];
|
|
||||||
const documentsAndFiles = [];
|
|
||||||
|
|
||||||
files.forEach(file => {
|
|
||||||
const name = file.name.toLowerCase();
|
|
||||||
if(name.includes('plan') || name.includes('drawing') || name.includes('dwg')) {
|
|
||||||
plans.push(file);
|
|
||||||
} else if(name.includes('estimate') || name.includes('est')) {
|
|
||||||
estimates.push(file);
|
|
||||||
} else {
|
|
||||||
documentsAndFiles.push(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Links Section Container
|
|
||||||
const linksSection = document.createElement('div');
|
|
||||||
linksSection.className = 'mt-4 pb-3 border-b border-gray-200';
|
|
||||||
linksSection.innerHTML = `<div class="font-bold text-gray-700 uppercase tracking-wide mb-2" style="font-size: 8px;">Links</div>`;
|
|
||||||
|
|
||||||
const linksGrid = document.createElement('div');
|
|
||||||
linksGrid.className = 'grid grid-cols-3 gap-4';
|
|
||||||
|
|
||||||
// Plans column
|
|
||||||
const plansCol = document.createElement('div');
|
|
||||||
plansCol.innerHTML = `<div class="font-bold text-gray-700 uppercase tracking-wide mb-1" style="font-size: 8px;">Plans</div>`;
|
|
||||||
const plansList = document.createElement('div');
|
|
||||||
plansList.className = 'space-y-1';
|
|
||||||
if(plans.length > 0) {
|
|
||||||
plans.forEach(file => {
|
|
||||||
const fileItem = document.createElement('div');
|
|
||||||
fileItem.className = 'text-blue-600 hover:text-blue-800 cursor-pointer underline';
|
|
||||||
fileItem.style.fontSize = '10px';
|
|
||||||
fileItem.textContent = file.name;
|
|
||||||
fileItem.onclick = () => openFilePreview(file);
|
|
||||||
plansList.appendChild(fileItem);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
plansList.innerHTML = `<div class="text-gray-400 italic" style="font-size: 10px;">No plans</div>`;
|
|
||||||
}
|
|
||||||
plansCol.appendChild(plansList);
|
|
||||||
|
|
||||||
// Estimates column
|
|
||||||
const estimatesCol = document.createElement('div');
|
|
||||||
estimatesCol.innerHTML = `<div class="font-bold text-gray-700 uppercase tracking-wide mb-1" style="font-size: 8px;">Estimates</div>`;
|
|
||||||
const estimatesList = document.createElement('div');
|
|
||||||
estimatesList.className = 'space-y-1';
|
|
||||||
if(estimates.length > 0) {
|
|
||||||
estimates.forEach(file => {
|
|
||||||
const fileItem = document.createElement('div');
|
|
||||||
fileItem.className = 'text-blue-600 hover:text-blue-800 cursor-pointer underline';
|
|
||||||
fileItem.style.fontSize = '10px';
|
|
||||||
fileItem.textContent = file.name;
|
|
||||||
fileItem.onclick = () => openFilePreview(file);
|
|
||||||
estimatesList.appendChild(fileItem);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
estimatesList.innerHTML = `<div class="text-gray-400 italic" style="font-size: 10px;">No estimates</div>`;
|
|
||||||
}
|
|
||||||
estimatesCol.appendChild(estimatesList);
|
|
||||||
|
|
||||||
// Documents & Files column
|
|
||||||
const docsCol = document.createElement('div');
|
|
||||||
docsCol.innerHTML = `<div class="font-bold text-gray-700 uppercase tracking-wide mb-1" style="font-size: 8px;">Documents & Files</div>`;
|
|
||||||
const docsList = document.createElement('div');
|
|
||||||
docsList.className = 'space-y-1';
|
|
||||||
if(documentsAndFiles.length > 0) {
|
|
||||||
documentsAndFiles.forEach(file => {
|
|
||||||
const fileItem = document.createElement('div');
|
|
||||||
fileItem.className = 'text-blue-600 hover:text-blue-800 cursor-pointer underline';
|
|
||||||
fileItem.style.fontSize = '10px';
|
|
||||||
fileItem.textContent = file.name;
|
|
||||||
fileItem.onclick = () => openFilePreview(file);
|
|
||||||
docsList.appendChild(fileItem);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
docsList.innerHTML = `<div class="text-gray-400 italic" style="font-size: 10px;">No documents</div>`;
|
|
||||||
}
|
|
||||||
docsCol.appendChild(docsList);
|
|
||||||
|
|
||||||
linksGrid.appendChild(plansCol);
|
|
||||||
linksGrid.appendChild(estimatesCol);
|
|
||||||
linksGrid.appendChild(docsCol);
|
|
||||||
linksSection.appendChild(linksGrid);
|
|
||||||
managerInfoTable.appendChild(linksSection);
|
|
||||||
} catch(err) {
|
|
||||||
console.log('Error loading files for Manager Info:', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notes Section with Tabs
|
// Notes Section with Tabs
|
||||||
const notesSection = document.createElement('div');
|
const notesSection = document.createElement('div');
|
||||||
notesSection.className = 'mt-4';
|
notesSection.className = 'mt-4';
|
||||||
@@ -1439,12 +1365,21 @@
|
|||||||
jobNotesContent.id = 'jobNotesContent';
|
jobNotesContent.id = 'jobNotesContent';
|
||||||
jobNotesContent.className = 'notes-tab-content';
|
jobNotesContent.className = 'notes-tab-content';
|
||||||
|
|
||||||
|
// Container for display with expand button
|
||||||
|
const jobNotesDisplayContainer = document.createElement('div');
|
||||||
|
jobNotesDisplayContainer.className = 'relative mb-3';
|
||||||
|
|
||||||
// Display notes first
|
// Display notes first
|
||||||
const jobNotesDisplay = document.createElement('div');
|
const jobNotesDisplay = document.createElement('div');
|
||||||
jobNotesDisplay.className = 'text-gray-600 whitespace-pre-wrap break-words p-2 border border-gray-300 rounded bg-gray-50 min-h-[80px] mb-3';
|
jobNotesDisplay.id = 'jobNotesDisplay';
|
||||||
|
jobNotesDisplay.className = 'text-gray-600 whitespace-pre-wrap break-words p-2 border border-gray-300 rounded bg-gray-50 overflow-y-auto';
|
||||||
jobNotesDisplay.style.fontSize = '10px';
|
jobNotesDisplay.style.fontSize = '10px';
|
||||||
|
jobNotesDisplay.style.height = '120px';
|
||||||
|
jobNotesDisplay.style.maxHeight = '120px';
|
||||||
jobNotesDisplay.innerHTML = job.Notes || '<span class="text-gray-400 italic">No notes available</span>';
|
jobNotesDisplay.innerHTML = job.Notes || '<span class="text-gray-400 italic">No notes available</span>';
|
||||||
jobNotesContent.appendChild(jobNotesDisplay);
|
jobNotesDisplayContainer.appendChild(jobNotesDisplay);
|
||||||
|
|
||||||
|
jobNotesContent.appendChild(jobNotesDisplayContainer);
|
||||||
|
|
||||||
// Add Note button below notes display
|
// Add Note button below notes display
|
||||||
const addNoteBtn = document.createElement('button');
|
const addNoteBtn = document.createElement('button');
|
||||||
@@ -1509,12 +1444,21 @@
|
|||||||
managerNotesContent.id = 'managerNotesContent';
|
managerNotesContent.id = 'managerNotesContent';
|
||||||
managerNotesContent.className = 'notes-tab-content hidden';
|
managerNotesContent.className = 'notes-tab-content hidden';
|
||||||
|
|
||||||
|
// Container for display with expand button
|
||||||
|
const managerNotesDisplayContainer = document.createElement('div');
|
||||||
|
managerNotesDisplayContainer.className = 'relative mb-3';
|
||||||
|
|
||||||
// Display manager notes first
|
// Display manager notes first
|
||||||
const managerNotesDisplay = document.createElement('div');
|
const managerNotesDisplay = document.createElement('div');
|
||||||
managerNotesDisplay.className = 'text-gray-600 whitespace-pre-wrap break-words p-2 border border-gray-300 rounded bg-gray-50 min-h-[80px] mb-3';
|
managerNotesDisplay.id = 'managerNotesDisplay';
|
||||||
|
managerNotesDisplay.className = 'text-gray-600 whitespace-pre-wrap break-words p-2 border border-gray-300 rounded bg-gray-50 overflow-y-auto';
|
||||||
managerNotesDisplay.style.fontSize = '10px';
|
managerNotesDisplay.style.fontSize = '10px';
|
||||||
|
managerNotesDisplay.style.height = '120px';
|
||||||
|
managerNotesDisplay.style.maxHeight = '120px';
|
||||||
managerNotesDisplay.innerHTML = '<span class="text-gray-400 italic">No manager notes available</span>';
|
managerNotesDisplay.innerHTML = '<span class="text-gray-400 italic">No manager notes available</span>';
|
||||||
managerNotesContent.appendChild(managerNotesDisplay);
|
managerNotesDisplayContainer.appendChild(managerNotesDisplay);
|
||||||
|
|
||||||
|
managerNotesContent.appendChild(managerNotesDisplayContainer);
|
||||||
|
|
||||||
// Add Note button for manager below notes display
|
// Add Note button for manager below notes display
|
||||||
const addManagerNoteBtn = document.createElement('button');
|
const addManagerNoteBtn = document.createElement('button');
|
||||||
@@ -1899,7 +1843,7 @@
|
|||||||
});
|
});
|
||||||
const currentUserName = getDisplayName();
|
const currentUserName = getDisplayName();
|
||||||
const noteType = isManagerNote ? 'manager' : 'job';
|
const noteType = isManagerNote ? 'manager' : 'job';
|
||||||
const typeLabel = isManagerNote ? '[MANAGER NOTE]' : '';
|
const typeLabel = isManagerNote ? '[MANAGER]' : '';
|
||||||
const formatted = `${typeLabel}[${currentUserName} - ${timestamp}] ${html}`;
|
const formatted = `${typeLabel}[${currentUserName} - ${timestamp}] ${html}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -2008,8 +1952,8 @@
|
|||||||
const jobNotes = allNotes.filter(n => !n.type || n.type === 'job');
|
const jobNotes = allNotes.filter(n => !n.type || n.type === 'job');
|
||||||
const managerNotes = allNotes.filter(n => n.type === 'manager');
|
const managerNotes = allNotes.filter(n => n.type === 'manager');
|
||||||
|
|
||||||
// Update job notes display
|
// Update job notes display using ID selector
|
||||||
const jobNotesDisplay = document.querySelector('#jobNotesContent > div:first-child');
|
const jobNotesDisplay = document.getElementById('jobNotesDisplay');
|
||||||
if(jobNotesDisplay) {
|
if(jobNotesDisplay) {
|
||||||
if(jobNotes.length > 0) {
|
if(jobNotes.length > 0) {
|
||||||
jobNotesDisplay.innerHTML = jobNotes.map(n => n.Note).join('\n\n');
|
jobNotesDisplay.innerHTML = jobNotes.map(n => n.Note).join('\n\n');
|
||||||
@@ -2018,8 +1962,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update manager notes display
|
// Update manager notes display using ID selector
|
||||||
const managerNotesDisplay = document.querySelector('#managerNotesContent > div:first-child');
|
const managerNotesDisplay = document.getElementById('managerNotesDisplay');
|
||||||
if(managerNotesDisplay) {
|
if(managerNotesDisplay) {
|
||||||
if(managerNotes.length > 0) {
|
if(managerNotes.length > 0) {
|
||||||
managerNotesDisplay.innerHTML = managerNotes.map(n => n.Note).join('\n\n');
|
managerNotesDisplay.innerHTML = managerNotes.map(n => n.Note).join('\n\n');
|
||||||
@@ -2061,6 +2005,7 @@
|
|||||||
otherFiles.push(file);
|
otherFiles.push(file);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
console.log('Categorized - Plans:', plans.length, 'Estimates:', estimates.length, 'Other:', otherFiles.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plans column
|
// Plans column
|
||||||
@@ -2074,10 +2019,11 @@
|
|||||||
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
||||||
fileItem.style.fontSize = '10px';
|
fileItem.style.fontSize = '10px';
|
||||||
|
|
||||||
// File icon
|
// File icon using getFileIcon
|
||||||
const icon = document.createElement('span');
|
const iconWrapper = document.createElement('span');
|
||||||
icon.textContent = '📄';
|
iconWrapper.className = 'flex-shrink-0';
|
||||||
fileItem.appendChild(icon);
|
iconWrapper.innerHTML = getFileIcon(file.name, file.contentType);
|
||||||
|
fileItem.appendChild(iconWrapper);
|
||||||
|
|
||||||
const fileName = document.createElement('span');
|
const fileName = document.createElement('span');
|
||||||
fileName.textContent = file.name;
|
fileName.textContent = file.name;
|
||||||
@@ -2103,10 +2049,11 @@
|
|||||||
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
||||||
fileItem.style.fontSize = '10px';
|
fileItem.style.fontSize = '10px';
|
||||||
|
|
||||||
// File icon
|
// File icon using getFileIcon
|
||||||
const icon = document.createElement('span');
|
const iconWrapper = document.createElement('span');
|
||||||
icon.textContent = '📊';
|
iconWrapper.className = 'flex-shrink-0';
|
||||||
fileItem.appendChild(icon);
|
iconWrapper.innerHTML = getFileIcon(file.name, file.contentType);
|
||||||
|
fileItem.appendChild(iconWrapper);
|
||||||
|
|
||||||
const fileName = document.createElement('span');
|
const fileName = document.createElement('span');
|
||||||
fileName.textContent = file.name;
|
fileName.textContent = file.name;
|
||||||
@@ -2132,19 +2079,11 @@
|
|||||||
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
fileItem.className = 'flex items-center gap-1 text-blue-600 hover:text-blue-800 cursor-pointer';
|
||||||
fileItem.style.fontSize = '10px';
|
fileItem.style.fontSize = '10px';
|
||||||
|
|
||||||
// File icon based on extension
|
// File icon using getFileIcon
|
||||||
const ext = file.name.split('.').pop().toLowerCase();
|
const iconWrapper = document.createElement('span');
|
||||||
const icon = document.createElement('span');
|
iconWrapper.className = 'flex-shrink-0';
|
||||||
if(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) {
|
iconWrapper.innerHTML = getFileIcon(file.name, file.contentType);
|
||||||
icon.textContent = '🖼️';
|
fileItem.appendChild(iconWrapper);
|
||||||
} else if(['pdf'].includes(ext)) {
|
|
||||||
icon.textContent = '📕';
|
|
||||||
} else if(['doc', 'docx'].includes(ext)) {
|
|
||||||
icon.textContent = '📝';
|
|
||||||
} else {
|
|
||||||
icon.textContent = '📄';
|
|
||||||
}
|
|
||||||
fileItem.appendChild(icon);
|
|
||||||
|
|
||||||
const fileName = document.createElement('span');
|
const fileName = document.createElement('span');
|
||||||
fileName.textContent = file.name;
|
fileName.textContent = file.name;
|
||||||
@@ -2410,28 +2349,28 @@
|
|||||||
const type = (contentType || '').toLowerCase();
|
const type = (contentType || '').toLowerCase();
|
||||||
|
|
||||||
if (ext === 'pdf' || type.includes('pdf'))
|
if (ext === 'pdf' || type.includes('pdf'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none"><rect fill="#D32F2F" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">PDF</text></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none"><rect fill="#D32F2F" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">PDF</text></svg>';
|
||||||
|
|
||||||
// Show Word icon with PDF badge to indicate it will be converted
|
// Show Word icon with PDF badge to indicate it will be converted
|
||||||
if (['doc', 'docx'].includes(ext) || type.includes('word'))
|
if (['doc', 'docx'].includes(ext) || type.includes('word'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none"><rect fill="#2B579A" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">W</text></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none"><rect fill="#2B579A" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">W</text></svg>';
|
||||||
|
|
||||||
if (['xls', 'xlsx'].includes(ext) || type.includes('excel') || type.includes('spreadsheet'))
|
if (['xls', 'xlsx'].includes(ext) || type.includes('excel') || type.includes('spreadsheet'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none"><rect fill="#217346" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">X</text></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none"><rect fill="#217346" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">X</text></svg>';
|
||||||
|
|
||||||
if (['ppt', 'pptx'].includes(ext) || type.includes('powerpoint') || type.includes('presentation'))
|
if (['ppt', 'pptx'].includes(ext) || type.includes('powerpoint') || type.includes('presentation'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none"><rect fill="#D35230" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">P</text></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none"><rect fill="#D35230" width="24" height="24" rx="2"/><text x="12" y="16" font-size="10" font-weight="bold" fill="white" text-anchor="middle">P</text></svg>';
|
||||||
|
|
||||||
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'].includes(ext) || type.includes('image'))
|
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'].includes(ext) || type.includes('image'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="20" rx="2"/><circle cx="8" cy="8" r="2"/><path d="M21 15l-5-5L5 21"/></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="20" rx="2"/><circle cx="8" cy="8" r="2"/><path d="M21 15l-5-5L5 21"/></svg>';
|
||||||
|
|
||||||
if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext) || type.includes('zip') || type.includes('compressed'))
|
if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext) || type.includes('zip') || type.includes('compressed'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-9h-3v4h3v-4zm0-3h-3v2h3V7z"/></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-9h-3v4h3v-4zm0-3h-3v2h3V7z"/></svg>';
|
||||||
|
|
||||||
if (['txt', 'csv', 'log'].includes(ext) || type.includes('text'))
|
if (['txt', 'csv', 'log'].includes(ext) || type.includes('text'))
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/><path d="M16 13H8M16 17H8M10 9H8"/></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/><path d="M16 13H8M16 17H8M10 9H8"/></svg>';
|
||||||
|
|
||||||
return '<svg class="w-6 h-6" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/></svg>';
|
return '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/></svg>';
|
||||||
};
|
};
|
||||||
|
|
||||||
const canPreviewInline = (name, contentType) => {
|
const canPreviewInline = (name, contentType) => {
|
||||||
@@ -3069,6 +3008,17 @@
|
|||||||
const prefs = await loadUserPreferences();
|
const prefs = await loadUserPreferences();
|
||||||
console.log('Init: loaded prefs=', prefs);
|
console.log('Init: loaded prefs=', prefs);
|
||||||
applyPrefsToFilters(prefs);
|
applyPrefsToFilters(prefs);
|
||||||
|
|
||||||
|
// Proactively refresh Graph token on load
|
||||||
|
console.log('Init: refreshing Graph token');
|
||||||
|
await refreshGraphToken();
|
||||||
|
|
||||||
|
// Set up background token refresh every 50 minutes (tokens typically expire after 60 min)
|
||||||
|
setInterval(async () => {
|
||||||
|
console.log('Background: refreshing Graph token');
|
||||||
|
await refreshGraphToken();
|
||||||
|
}, 50 * 60 * 1000); // 50 minutes
|
||||||
|
|
||||||
console.log('Init: about to fetch jobs');
|
console.log('Init: about to fetch jobs');
|
||||||
fetchAllJobs();
|
fetchAllJobs();
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user