revit-journal-assist
Version:
A web-based interface for viewing Autodesk Revit journal logs
240 lines (197 loc) • 9.05 kB
JavaScript
// Initialize socket connection
const socket = io();
// DOM elements
const fileTree = document.getElementById('fileTree');
const journalContent = document.getElementById('journalContent');
const currentFileElement = document.getElementById('currentFile');
const downloadBtn = document.getElementById('downloadBtn');
const loadingOverlay = document.getElementById('loadingOverlay');
const hostnameElement = document.getElementById('hostname');
const localIPElement = document.getElementById('localIP');
// Global variables
let currentFilePath = null;
// Display hostname
hostnameElement.textContent = `Connected to: ${window.location.hostname}`;
// Get and display local IP address
async function getLocalIP() {
try {
// Check if we're already using an IP address (not localhost)
if (window.location.hostname !== 'localhost' &&
/^(\d{1,3}\.){3}\d{1,3}$/.test(window.location.hostname)) {
localIPElement.innerHTML = `<i class="fas fa-network-wired"></i> Remote access: <a href="http://${window.location.hostname}:${window.location.port}" target="_blank">${window.location.hostname}:${window.location.port}</a>`;
return;
}
// Ask server for local IP address via socket.io
socket.emit('getLocalIP');
socket.once('localIP', (ip) => {
if (ip) {
localIPElement.innerHTML = `<i class="fas fa-network-wired"></i> Remote access: <a href="http://${ip}:${window.location.port}" target="_blank">${ip}:${window.location.port}</a>`;
}
});
} catch (error) {
console.error('Error getting local IP:', error);
}
}
// Load user directories
async function loadUsers() {
try {
const response = await fetch('/api/users');
const users = await response.json();
fileTree.innerHTML = '';
if (users.length === 0) {
fileTree.innerHTML = '<div class="loading">No users found</div>';
return;
}
// Create user folders in the file tree
users.forEach(user => {
const userItem = createTreeItem(user, 'fas fa-user', async () => {
const userChildren = userItem.querySelector('.tree-children');
if (userItem.classList.contains('expanded')) {
userItem.classList.remove('expanded');
} else {
userItem.classList.add('expanded');
// Only load Revit versions if not already loaded
if (userChildren.children.length === 0) {
userChildren.innerHTML = '<div class="loading">Loading Revit versions...</div>';
await loadRevitVersions(user, userChildren);
}
}
});
fileTree.appendChild(userItem);
});
} catch (error) {
console.error('Error loading users:', error);
fileTree.innerHTML = '<div class="loading">Error loading users</div>';
}
}
// Load Revit versions for a specific user
async function loadRevitVersions(user, parentElement) {
try {
const response = await fetch(`/api/user/${user}/revit`);
const versions = await response.json();
parentElement.innerHTML = '';
if (versions.length === 0) {
parentElement.innerHTML = '<div class="loading">No Revit versions found</div>';
return;
}
// Create Revit version folders in the file tree
versions.forEach(version => {
const versionName = version.version.replace('Revit ', '');
const versionItem = createTreeItem(versionName, 'fas fa-folder', async () => {
const versionChildren = versionItem.querySelector('.tree-children');
if (versionItem.classList.contains('expanded')) {
versionItem.classList.remove('expanded');
} else {
versionItem.classList.add('expanded');
// Only load journal files if not already loaded
if (versionChildren.children.length === 0) {
versionChildren.innerHTML = '<div class="loading">Loading journal files...</div>';
await loadJournalFiles(user, versionName, versionChildren);
}
}
});
parentElement.appendChild(versionItem);
});
} catch (error) {
console.error('Error loading Revit versions:', error);
parentElement.innerHTML = '<div class="loading">Error loading Revit versions</div>';
}
}
// Load journal files for a specific Revit version
async function loadJournalFiles(user, version, parentElement) {
try {
const response = await fetch(`/api/user/${user}/revit/${version}`);
const files = await response.json();
parentElement.innerHTML = '';
if (files.length === 0) {
parentElement.innerHTML = '<div class="loading">No journal files found</div>';
return;
}
// Create journal file items in the file tree
files.forEach(file => {
const fileItem = createTreeItem(file.name, 'fas fa-file-alt', () => {
// Deselect previously selected item
const selected = fileTree.querySelector('.selected');
if (selected) selected.classList.remove('selected');
// Select current item
fileItem.classList.add('selected');
// Show loading overlay
loadingOverlay.style.display = 'flex';
// Load journal file content
loadJournalContent(file.path, file.name);
});
// Add file info
const fileInfo = document.createElement('div');
fileInfo.className = 'file-info';
fileInfo.innerHTML = `
<span>Size: ${formatFileSize(file.size)}</span>
<span>Modified: ${new Date(file.modified).toLocaleDateString()}</span>
`;
fileItem.appendChild(fileInfo);
parentElement.appendChild(fileItem);
});
} catch (error) {
console.error('Error loading journal files:', error);
parentElement.innerHTML = '<div class="loading">Error loading journal files</div>';
}
}
// Load journal file content
async function loadJournalContent(filePath, fileName) {
try {
const response = await fetch(`/api/journal?path=${encodeURIComponent(filePath)}`);
if (!response.ok) {
throw new Error(`Error: ${response.status} ${response.statusText}`);
}
const content = await response.text();
// Update UI
currentFileElement.textContent = fileName;
journalContent.innerHTML = '';
journalContent.textContent = content;
// Enable download button
downloadBtn.disabled = false;
currentFilePath = filePath;
} catch (error) {
console.error('Error loading journal content:', error);
journalContent.innerHTML = `<div class="placeholder">Error loading file: ${error.message}</div>`;
// Disable download button
downloadBtn.disabled = true;
currentFilePath = null;
} finally {
// Hide loading overlay
loadingOverlay.style.display = 'none';
}
}
// Create a tree item with icon, label, and click handler
function createTreeItem(label, iconClass, clickHandler) {
const item = document.createElement('div');
item.className = 'tree-item';
const labelContainer = document.createElement('div');
labelContainer.className = 'tree-label';
labelContainer.innerHTML = `<i class="${iconClass} icon"></i><span class="label">${label}</span>`;
const children = document.createElement('div');
children.className = 'tree-children';
item.appendChild(labelContainer);
item.appendChild(children);
if (clickHandler) {
labelContainer.addEventListener('click', clickHandler);
}
return item;
}
// Format file size to human-readable format
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
return (bytes / (1024 * 1024 * 1024)).toFixed(1) + ' GB';
}
// Download button event handler
downloadBtn.addEventListener('click', () => {
if (currentFilePath) {
window.open(`/api/download?path=${encodeURIComponent(currentFilePath)}`);
}
});
// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
loadUsers();
getLocalIP();
});