fix(reports): resolve loadFTPFiles collision breaking Browse Files on the NRL tab
ftp_browser.html and slm_live_view.html are both loaded on the per-NRL detail page (Data Files + Command Center tabs) and each defined loadFTPFiles / downloadToServer / downloadFTPFile / enableFTP / formatFileSize as globals — last to load won. 'Browse Files' then called slm_live_view's loadFTPFiles, which renders into the hidden Command Center's #ftp-files-list, so the FTP request fired but nothing appeared. Prefix ftp_browser's five colliding functions with fb* so each partial keeps its own. (Element IDs don't collide: per-unit vs fixed.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
Settings
|
Settings
|
||||||
</button>
|
</button>
|
||||||
<button onclick="enableFTP('{{ unit_item.unit.id }}')"
|
<button onclick="fbEnableFTP('{{ unit_item.unit.id }}')"
|
||||||
id="enable-ftp-{{ unit_item.unit.id }}"
|
id="enable-ftp-{{ unit_item.unit.id }}"
|
||||||
class="px-3 py-1 text-xs bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
|
class="px-3 py-1 text-xs bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
|
||||||
disabled>
|
disabled>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
disabled>
|
disabled>
|
||||||
Disable FTP
|
Disable FTP
|
||||||
</button>
|
</button>
|
||||||
<button onclick="loadFTPFiles('{{ unit_item.unit.id }}', '/NL-43')"
|
<button onclick="fbLoadFTPFiles('{{ unit_item.unit.id }}', '/NL-43')"
|
||||||
id="browse-ftp-{{ unit_item.unit.id }}"
|
id="browse-ftp-{{ unit_item.unit.id }}"
|
||||||
class="px-3 py-1 text-xs bg-seismo-orange text-white rounded-lg hover:bg-seismo-navy transition-colors"
|
class="px-3 py-1 text-xs bg-seismo-orange text-white rounded-lg hover:bg-seismo-navy transition-colors"
|
||||||
disabled>
|
disabled>
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<span id="current-path-{{ unit_item.unit.id }}" class="text-sm font-mono text-gray-600 dark:text-gray-400">/NL-43</span>
|
<span id="current-path-{{ unit_item.unit.id }}" class="text-sm font-mono text-gray-600 dark:text-gray-400">/NL-43</span>
|
||||||
<button onclick="loadFTPFiles('{{ unit_item.unit.id }}', '/NL-43')"
|
<button onclick="fbLoadFTPFiles('{{ unit_item.unit.id }}', '/NL-43')"
|
||||||
class="ml-auto text-xs px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded hover:bg-gray-200 dark:hover:bg-gray-600">
|
class="ml-auto text-xs px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded hover:bg-gray-200 dark:hover:bg-gray-600">
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||||
@@ -117,7 +117,7 @@ async function checkFTPStatus(unitId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enableFTP(unitId) {
|
async function fbEnableFTP(unitId) {
|
||||||
const enableBtn = document.getElementById(`enable-ftp-${unitId}`);
|
const enableBtn = document.getElementById(`enable-ftp-${unitId}`);
|
||||||
enableBtn.disabled = true;
|
enableBtn.disabled = true;
|
||||||
enableBtn.textContent = 'Enabling...';
|
enableBtn.textContent = 'Enabling...';
|
||||||
@@ -130,7 +130,7 @@ async function enableFTP(unitId) {
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
await checkFTPStatus(unitId);
|
await checkFTPStatus(unitId);
|
||||||
// Auto-load files after enabling
|
// Auto-load files after enabling
|
||||||
setTimeout(() => loadFTPFiles(unitId, '/NL-43'), 1000);
|
setTimeout(() => fbLoadFTPFiles(unitId, '/NL-43'), 1000);
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to enable FTP');
|
alert('Failed to enable FTP');
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ async function disableFTP(unitId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadFTPFiles(unitId, path) {
|
async function fbLoadFTPFiles(unitId, path) {
|
||||||
const fileListDiv = document.getElementById(`ftp-file-list-${unitId}`);
|
const fileListDiv = document.getElementById(`ftp-file-list-${unitId}`);
|
||||||
const filesContainer = document.getElementById(`ftp-files-${unitId}`);
|
const filesContainer = document.getElementById(`ftp-files-${unitId}`);
|
||||||
const currentPathSpan = document.getElementById(`current-path-${unitId}`);
|
const currentPathSpan = document.getElementById(`current-path-${unitId}`);
|
||||||
@@ -220,7 +220,7 @@ async function loadFTPFiles(unitId, path) {
|
|||||||
let html = '<div class="space-y-1">';
|
let html = '<div class="space-y-1">';
|
||||||
for (const file of sorted) {
|
for (const file of sorted) {
|
||||||
const icon = getFileIcon(file);
|
const icon = getFileIcon(file);
|
||||||
const sizeStr = file.is_dir ? '' : formatFileSize(file.size);
|
const sizeStr = file.is_dir ? '' : fbFormatFileSize(file.size);
|
||||||
const folderId = 'proj-folder-' + file.path.replace(/[^a-zA-Z0-9]/g, '-');
|
const folderId = 'proj-folder-' + file.path.replace(/[^a-zA-Z0-9]/g, '-');
|
||||||
|
|
||||||
if (file.is_dir) {
|
if (file.is_dir) {
|
||||||
@@ -264,7 +264,7 @@ async function loadFTPFiles(unitId, path) {
|
|||||||
<div class="flex items-center gap-3 flex-shrink-0 ml-4">
|
<div class="flex items-center gap-3 flex-shrink-0 ml-4">
|
||||||
<span class="text-xs text-gray-500 hidden sm:inline">${sizeStr}</span>
|
<span class="text-xs text-gray-500 hidden sm:inline">${sizeStr}</span>
|
||||||
<span class="text-xs text-gray-500 hidden md:inline">${file.modified || ''}</span>
|
<span class="text-xs text-gray-500 hidden md:inline">${file.modified || ''}</span>
|
||||||
<button onclick="downloadToServer('${unitId}', '${escapeForAttribute(file.path)}', '${escapeForAttribute(file.name)}')"
|
<button onclick="fbDownloadToServer('${unitId}', '${escapeForAttribute(file.path)}', '${escapeForAttribute(file.name)}')"
|
||||||
class="px-3 py-1 text-xs bg-seismo-orange text-white rounded hover:bg-seismo-navy transition-colors flex items-center"
|
class="px-3 py-1 text-xs bg-seismo-orange text-white rounded hover:bg-seismo-navy transition-colors flex items-center"
|
||||||
title="Download file from device to server and add to project database">
|
title="Download file from device to server and add to project database">
|
||||||
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -371,7 +371,7 @@ async function toggleFTPFolderProject(unitId, folderPath, folderId, headerElemen
|
|||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const fullPath = file.path || `${folderPath}/${file.name}`;
|
const fullPath = file.path || `${folderPath}/${file.name}`;
|
||||||
const icon = getFileIcon(file);
|
const icon = getFileIcon(file);
|
||||||
const sizeText = file.size ? formatFileSize(file.size) : '';
|
const sizeText = file.size ? fbFormatFileSize(file.size) : '';
|
||||||
const subFolderId = 'proj-folder-' + fullPath.replace(/[^a-zA-Z0-9]/g, '-');
|
const subFolderId = 'proj-folder-' + fullPath.replace(/[^a-zA-Z0-9]/g, '-');
|
||||||
|
|
||||||
if (file.is_dir) {
|
if (file.is_dir) {
|
||||||
@@ -412,7 +412,7 @@ async function toggleFTPFolderProject(unitId, folderPath, folderId, headerElemen
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2 flex-shrink-0 ml-2">
|
<div class="flex items-center gap-2 flex-shrink-0 ml-2">
|
||||||
<span class="text-xs text-gray-500 hidden sm:inline">${sizeText}</span>
|
<span class="text-xs text-gray-500 hidden sm:inline">${sizeText}</span>
|
||||||
<button onclick="downloadToServer('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
|
<button onclick="fbDownloadToServer('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
|
||||||
class="px-2 py-1 bg-seismo-orange hover:bg-seismo-navy text-white text-xs rounded transition-colors"
|
class="px-2 py-1 bg-seismo-orange hover:bg-seismo-navy text-white text-xs rounded transition-colors"
|
||||||
title="Download to server">
|
title="Download to server">
|
||||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -436,7 +436,7 @@ async function toggleFTPFolderProject(unitId, folderPath, folderId, headerElemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadFTPFile(unitId, remotePath, fileName) {
|
async function fbDownloadFTPFile(unitId, remotePath, fileName) {
|
||||||
const btn = event.target;
|
const btn = event.target;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = 'Downloading...';
|
btn.textContent = 'Downloading...';
|
||||||
@@ -561,7 +561,7 @@ async function downloadFolderToServer(unitId, remotePath, folderName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadToServer(unitId, remotePath, fileName) {
|
async function fbDownloadToServer(unitId, remotePath, fileName) {
|
||||||
const btn = event.target;
|
const btn = event.target;
|
||||||
const originalText = btn.innerHTML;
|
const originalText = btn.innerHTML;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
@@ -588,7 +588,7 @@ async function downloadToServer(unitId, remotePath, fileName) {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// Show success message
|
// Show success message
|
||||||
const sizeLine = `\nSize: ${formatFileSize(data.file_size)}`;
|
const sizeLine = `\nSize: ${fbFormatFileSize(data.file_size)}`;
|
||||||
const msg = data.ingested
|
const msg = data.ingested
|
||||||
? `✓ ${fileName} imported as measurement data!` + formatRunLength(data) + sizeLine
|
? `✓ ${fileName} imported as measurement data!` + formatRunLength(data) + sizeLine
|
||||||
: `✓ ${fileName} downloaded to server successfully!\n\nFile ID: ${data.file_id}` + sizeLine;
|
: `✓ ${fileName} downloaded to server successfully!\n\nFile ID: ${data.file_id}` + sizeLine;
|
||||||
@@ -607,7 +607,7 @@ async function downloadToServer(unitId, remotePath, fileName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatFileSize(bytes) {
|
function fbFormatFileSize(bytes) {
|
||||||
if (bytes < 1024) return bytes + ' B';
|
if (bytes < 1024) return bytes + ' B';
|
||||||
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
||||||
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
||||||
|
|||||||
Reference in New Issue
Block a user