Files
SuperCharged-Claude-Code-Up…/public/js/app.js
uroma efb3ecfb19 feat: AI auto-fix bug tracker with real-time error monitoring
- Real-time error monitoring system with WebSocket
- Auto-fix agent that triggers on browser errors
- Bug tracker dashboard with floating button (🐛)
- Live activity stream showing AI thought process
- Fixed 4 JavaScript errors (SyntaxError, TypeError)
- Fixed SessionPicker API endpoint error
- Enhanced chat input with Monaco editor
- Session picker component for project management

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-21 10:53:11 +00:00

333 lines
10 KiB
JavaScript

// API Base URL
const API_BASE = '/claude/api';
// State
let currentFile = null;
let isEditing = false;
let fileTree = [];
// DOM Elements
const loginScreen = document.getElementById('login-screen');
const mainApp = document.getElementById('main-app');
const loginForm = document.getElementById('login-form');
const loginError = document.getElementById('login-error');
const logoutBtn = document.getElementById('logout-btn');
const searchInput = document.getElementById('search-input');
const fileTreeEl = document.getElementById('file-tree');
const recentFilesEl = document.getElementById('recent-files');
const contentView = document.getElementById('content-view');
const contentEditor = document.getElementById('content-editor');
const breadcrumb = document.getElementById('breadcrumb');
const editBtn = document.getElementById('edit-btn');
const saveBtn = document.getElementById('save-btn');
const cancelBtn = document.getElementById('cancel-btn');
// Initialize
document.addEventListener('DOMContentLoaded', () => {
checkAuth();
setupEventListeners();
});
function setupEventListeners() {
// Login form
const loginForm = document.getElementById('login-form');
if (loginForm) {
loginForm.addEventListener('submit', handleLogin);
}
// Logout
const logoutBtn = document.getElementById('logout-btn');
if (logoutBtn) {
logoutBtn.addEventListener('click', handleLogout);
}
// Search
const searchInput = document.getElementById('search-input');
if (searchInput) {
let searchTimeout;
searchInput.addEventListener('input', (e) => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => handleSearch(e.target.value), 300);
});
}
// Edit/Save/Cancel buttons
const editBtn = document.getElementById('edit-btn');
const saveBtn = document.getElementById('save-btn');
const cancelBtn = document.getElementById('cancel-btn');
if (editBtn) {
editBtn.addEventListener('click', startEditing);
}
if (saveBtn) {
saveBtn.addEventListener('click', saveFile);
}
if (cancelBtn) {
cancelBtn.addEventListener('click', stopEditing);
}
}
// Auth functions
async function checkAuth() {
try {
const res = await fetch(`${API_BASE}/auth/status`);
const data = await res.json();
if (data.authenticated) {
// Redirect to landing page if authenticated
window.location.href = '/claude/';
} else {
showLogin();
}
} catch (error) {
console.error('Auth check failed:', error);
showLogin();
}
}
async function handleLogin(e) {
e.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
try {
const res = await fetch(`${API_BASE}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await res.json();
if (data.success) {
// Redirect to landing page after successful login
window.location.href = '/claude/';
} else {
loginError.textContent = data.error || 'Login failed';
}
} catch (error) {
loginError.textContent = 'Network error. Please try again.';
}
}
async function handleLogout() {
try {
await fetch(`${API_BASE}/logout`, { method: 'POST' });
showLogin();
} catch (error) {
console.error('Logout failed:', error);
}
}
function showLogin() {
loginScreen.style.display = 'flex';
mainApp.style.display = 'none';
}
function showApp() {
loginScreen.style.display = 'none';
mainApp.style.display = 'flex';
loadFileTree();
loadRecentFiles();
}
// File functions
async function loadFileTree() {
try {
const res = await fetch(`${API_BASE}/files`);
const data = await res.json();
fileTree = data.tree;
renderFileTree(fileTree, fileTreeEl);
} catch (error) {
console.error('Failed to load file tree:', error);
}
}
function renderFileTree(tree, container, level = 0) {
container.innerHTML = '';
tree.forEach(item => {
const div = document.createElement('div');
div.className = 'tree-item ' + item.type;
div.style.paddingLeft = (level * 1 + 0.75) + 'rem';
const icon = document.createElement('span');
icon.className = 'tree-icon';
icon.textContent = item.type === 'folder' ? '📁' : '📄';
div.appendChild(icon);
const name = document.createElement('span');
name.textContent = item.name;
div.appendChild(name);
if (item.type === 'folder' && item.children) {
const children = document.createElement('div');
children.className = 'tree-children';
children.style.display = 'none';
div.addEventListener('click', () => {
children.style.display = children.style.display === 'none' ? 'block' : 'none';
icon.textContent = children.style.display === 'none' ? '📁' : '📂';
});
renderFileTree(item.children, children, level + 1);
div.appendChild(children);
} else if (item.type === 'file') {
div.addEventListener('click', () => loadFile(item.path));
}
container.appendChild(div);
});
}
async function loadRecentFiles() {
try {
const res = await fetch(`${API_BASE}/recent?limit=10`);
const data = await res.json();
recentFilesEl.innerHTML = '';
data.files.forEach(file => {
const li = document.createElement('li');
li.textContent = file.name;
li.title = file.path;
li.addEventListener('click', () => loadFile(file.path));
recentFilesEl.appendChild(li);
});
} catch (error) {
console.error('Failed to load recent files:', error);
}
}
async function loadFile(filePath) {
try {
const res = await fetch(`${API_BASE}/file/${encodeURIComponent(filePath)}`);
const data = await res.json();
if (data.error) {
console.error('Error loading file:', data.error);
return;
}
currentFile = data;
breadcrumb.textContent = data.path;
contentView.innerHTML = data.html;
contentEditor.value = data.content;
editBtn.style.display = 'inline-block';
stopEditing();
} catch (error) {
console.error('Failed to load file:', error);
}
}
async function handleSearch(query) {
if (!query.trim()) {
return;
}
try {
const res = await fetch(`${API_BASE}/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
// Show search results in file tree
fileTreeEl.innerHTML = '';
if (data.results.length === 0) {
fileTreeEl.innerHTML = '<div style="padding: 1rem; color: var(--text-secondary);">No results found</div>';
return;
}
data.results.forEach(result => {
const div = document.createElement('div');
div.className = 'tree-item file';
const name = document.createElement('div');
name.textContent = result.name;
name.style.fontWeight = '500';
div.appendChild(name);
const preview = document.createElement('div');
preview.textContent = result.preview;
preview.style.fontSize = '0.8rem';
preview.style.color = 'var(--text-secondary)';
preview.style.marginTop = '0.25rem';
div.appendChild(preview);
div.addEventListener('click', () => loadFile(result.path));
fileTreeEl.appendChild(div);
});
} catch (error) {
console.error('Search failed:', error);
}
}
// Edit functions
function startEditing() {
if (!currentFile) return;
isEditing = true;
contentView.style.display = 'none';
contentEditor.style.display = 'block';
editBtn.style.display = 'none';
saveBtn.style.display = 'inline-block';
cancelBtn.style.display = 'inline-block';
contentEditor.focus();
}
function stopEditing() {
isEditing = false;
contentView.style.display = 'block';
contentEditor.style.display = 'none';
editBtn.style.display = 'inline-block';
saveBtn.style.display = 'none';
cancelBtn.style.display = 'none';
}
async function saveFile() {
if (!currentFile || !isEditing) return;
const content = contentEditor.value;
try {
const res = await fetch(`${API_BASE}/file/${encodeURIComponent(currentFile.path)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content })
});
const data = await res.json();
if (data.success) {
// Reload the file to show updated content
await loadFile(currentFile.path);
} else {
alert('Failed to save: ' + (data.error || 'Unknown error'));
}
} catch (error) {
console.error('Failed to save file:', error);
alert('Failed to save file. Please try again.');
}
}
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
// Ctrl/Cmd + S to save
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
if (isEditing) {
saveFile();
}
}
// Escape to cancel editing
if (e.key === 'Escape' && isEditing) {
stopEditing();
}
// Ctrl/Cmd + E to edit
if ((e.ctrlKey || e.metaKey) && e.key === 'e' && !isEditing && currentFile) {
e.preventDefault();
startEditing();
}
});