Fix all app CSS loading - add all app CSS to index.html head

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-12-15 16:48:36 -03:00
parent c9602593a4
commit 3439a5722c
2 changed files with 110 additions and 70 deletions

View file

@ -1,54 +1,73 @@
<link rel="stylesheet" href="/chat/chat.css" /> <link rel="stylesheet" href="chat/chat.css" />
<script> <script>
// WebSocket URL - use relative path to go through botui proxy // WebSocket URL - use relative path to go through botui proxy
const WS_BASE_URL = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; const WS_BASE_URL =
window.location.protocol === "https:" ? "wss://" : "ws://";
const WS_URL = `${WS_BASE_URL}${window.location.host}`; const WS_URL = `${WS_BASE_URL}${window.location.host}`;
// Message Type Constants // Message Type Constants
const MessageType = { EXTERNAL: 0, USER: 1, BOT_RESPONSE: 2, CONTINUE: 3, SUGGESTION: 4, CONTEXT_CHANGE: 5 }; const MessageType = {
EXTERNAL: 0,
USER: 1,
BOT_RESPONSE: 2,
CONTINUE: 3,
SUGGESTION: 4,
CONTEXT_CHANGE: 5,
};
// State // State
let ws = null, currentSessionId = null, currentUserId = null, currentBotId = "default"; let ws = null,
let isStreaming = false, streamingMessageId = null, currentStreamingContent = ""; currentSessionId = null,
currentUserId = null,
currentBotId = "default";
let isStreaming = false,
streamingMessageId = null,
currentStreamingContent = "";
let reconnectAttempts = 0; let reconnectAttempts = 0;
const maxReconnectAttempts = 5; const maxReconnectAttempts = 5;
// Initialize auth and WebSocket // Initialize auth and WebSocket
async function initChat() { async function initChat() {
try { try {
updateConnectionStatus('connecting'); updateConnectionStatus("connecting");
const botName = 'default'; const botName = "default";
// Use the botui proxy for auth (handles SSL cert issues) // Use the botui proxy for auth (handles SSL cert issues)
const response = await fetch(`/api/auth?bot_name=${encodeURIComponent(botName)}`); const response = await fetch(
`/api/auth?bot_name=${encodeURIComponent(botName)}`,
);
const auth = await response.json(); const auth = await response.json();
currentUserId = auth.user_id; currentUserId = auth.user_id;
currentSessionId = auth.session_id; currentSessionId = auth.session_id;
currentBotId = auth.bot_id || "default"; currentBotId = auth.bot_id || "default";
console.log("Auth:", { currentUserId, currentSessionId, currentBotId }); console.log("Auth:", {
currentUserId,
currentSessionId,
currentBotId,
});
connectWebSocket(); connectWebSocket();
} catch (e) { } catch (e) {
console.error("Auth failed:", e); console.error("Auth failed:", e);
updateConnectionStatus('disconnected'); updateConnectionStatus("disconnected");
setTimeout(initChat, 3000); setTimeout(initChat, 3000);
} }
} }
function connectWebSocket() { function connectWebSocket() {
if (ws) ws.close(); if (ws) ws.close();
// Use the botui proxy for WebSocket (handles SSL cert issues) // Use the botui proxy for WebSocket (handles SSL cert issues)
const url = `${WS_URL}/ws?session_id=${currentSessionId}&user_id=${currentUserId}`; const url = `${WS_URL}/ws?session_id=${currentSessionId}&user_id=${currentUserId}`;
ws = new WebSocket(url); ws = new WebSocket(url);
ws.onopen = () => { ws.onopen = () => {
console.log("WebSocket connected"); console.log("WebSocket connected");
updateConnectionStatus('connected'); updateConnectionStatus("connected");
reconnectAttempts = 0; reconnectAttempts = 0;
}; };
ws.onmessage = (event) => { ws.onmessage = (event) => {
try { try {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.type === 'connected') return; if (data.type === "connected") return;
if (data.message_type === MessageType.BOT_RESPONSE) { if (data.message_type === MessageType.BOT_RESPONSE) {
processMessage(data); processMessage(data);
} }
@ -56,46 +75,46 @@
console.error("WS message error:", e); console.error("WS message error:", e);
} }
}; };
ws.onclose = () => { ws.onclose = () => {
updateConnectionStatus('disconnected'); updateConnectionStatus("disconnected");
if (reconnectAttempts < maxReconnectAttempts) { if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++; reconnectAttempts++;
setTimeout(connectWebSocket, 1000 * reconnectAttempts); setTimeout(connectWebSocket, 1000 * reconnectAttempts);
} }
}; };
ws.onerror = (e) => console.error("WebSocket error:", e); ws.onerror = (e) => console.error("WebSocket error:", e);
} }
function processMessage(data) { function processMessage(data) {
if (data.is_complete) { if (data.is_complete) {
if (isStreaming) { if (isStreaming) {
finalizeStreaming(); finalizeStreaming();
} else { } else {
addMessage('bot', data.content); addMessage("bot", data.content);
} }
isStreaming = false; isStreaming = false;
} else { } else {
if (!isStreaming) { if (!isStreaming) {
isStreaming = true; isStreaming = true;
streamingMessageId = 'streaming-' + Date.now(); streamingMessageId = "streaming-" + Date.now();
currentStreamingContent = data.content || ''; currentStreamingContent = data.content || "";
addMessage('bot', currentStreamingContent, streamingMessageId); addMessage("bot", currentStreamingContent, streamingMessageId);
} else { } else {
currentStreamingContent += data.content || ''; currentStreamingContent += data.content || "";
updateStreaming(currentStreamingContent); updateStreaming(currentStreamingContent);
} }
} }
} }
function addMessage(sender, content, msgId = null) { function addMessage(sender, content, msgId = null) {
const messages = document.getElementById('messages'); const messages = document.getElementById("messages");
const div = document.createElement('div'); const div = document.createElement("div");
div.className = `message ${sender}`; div.className = `message ${sender}`;
if (msgId) div.id = msgId; if (msgId) div.id = msgId;
if (sender === 'user') { if (sender === "user") {
div.innerHTML = `<div class="message-content user-message">${escapeHtml(content)}</div>`; div.innerHTML = `<div class="message-content user-message">${escapeHtml(content)}</div>`;
} else { } else {
div.innerHTML = `<div class="message-content bot-message">${marked.parse(content)}</div>`; div.innerHTML = `<div class="message-content bot-message">${marked.parse(content)}</div>`;
@ -103,82 +122,91 @@
messages.appendChild(div); messages.appendChild(div);
messages.scrollTop = messages.scrollHeight; messages.scrollTop = messages.scrollHeight;
} }
function updateStreaming(content) { function updateStreaming(content) {
const el = document.getElementById(streamingMessageId); const el = document.getElementById(streamingMessageId);
if (el) el.querySelector('.message-content').innerHTML = marked.parse(content); if (el)
el.querySelector(".message-content").innerHTML =
marked.parse(content);
} }
function finalizeStreaming() { function finalizeStreaming() {
const el = document.getElementById(streamingMessageId); const el = document.getElementById(streamingMessageId);
if (el) { if (el) {
el.querySelector('.message-content').innerHTML = marked.parse(currentStreamingContent); el.querySelector(".message-content").innerHTML = marked.parse(
el.removeAttribute('id'); currentStreamingContent,
);
el.removeAttribute("id");
} }
streamingMessageId = null; streamingMessageId = null;
currentStreamingContent = ''; currentStreamingContent = "";
} }
function sendMessage() { function sendMessage() {
const input = document.getElementById('messageInput'); const input = document.getElementById("messageInput");
const content = input.value.trim(); const content = input.value.trim();
if (!content || !ws || ws.readyState !== WebSocket.OPEN) return; if (!content || !ws || ws.readyState !== WebSocket.OPEN) return;
addMessage('user', content); addMessage("user", content);
ws.send(JSON.stringify({ ws.send(
bot_id: currentBotId, JSON.stringify({
user_id: currentUserId, bot_id: currentBotId,
session_id: currentSessionId, user_id: currentUserId,
channel: 'web', session_id: currentSessionId,
content: content, channel: "web",
message_type: MessageType.USER, content: content,
timestamp: new Date().toISOString() message_type: MessageType.USER,
})); timestamp: new Date().toISOString(),
}),
input.value = ''; );
input.value = "";
input.focus(); input.focus();
} }
function updateConnectionStatus(status) { function updateConnectionStatus(status) {
const el = document.getElementById('connectionStatus'); const el = document.getElementById("connectionStatus");
if (el) el.className = `connection-status ${status}`; if (el) el.className = `connection-status ${status}`;
} }
function escapeHtml(text) { function escapeHtml(text) {
const div = document.createElement('div'); const div = document.createElement("div");
div.textContent = text; div.textContent = text;
return div.innerHTML; return div.innerHTML;
} }
// Initialize chat - runs immediately when script is executed // Initialize chat - runs immediately when script is executed
// (works both on full page load and HTMX partial load) // (works both on full page load and HTMX partial load)
function setupChat() { function setupChat() {
const input = document.getElementById('messageInput'); const input = document.getElementById("messageInput");
const sendBtn = document.getElementById('sendBtn'); const sendBtn = document.getElementById("sendBtn");
if (sendBtn) sendBtn.onclick = sendMessage; if (sendBtn) sendBtn.onclick = sendMessage;
if (input) { if (input) {
input.addEventListener('keypress', (e) => { input.addEventListener("keypress", (e) => {
if (e.key === 'Enter') sendMessage(); if (e.key === "Enter") sendMessage();
}); });
} }
initChat(); initChat();
} }
// Initialize after a micro-delay to ensure DOM is ready // Initialize after a micro-delay to ensure DOM is ready
// This works for both full page loads and HTMX partial loads // This works for both full page loads and HTMX partial loads
setTimeout(() => { setTimeout(() => {
if (document.getElementById('messageInput') && !window.chatInitialized) { if (
document.getElementById("messageInput") &&
!window.chatInitialized
) {
window.chatInitialized = true; window.chatInitialized = true;
setupChat(); setupChat();
} }
}, 0); }, 0);
// Fallback for full page load // Fallback for full page load
if (document.readyState === 'loading') { if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', () => { document.addEventListener("DOMContentLoaded", () => {
if (!window.chatInitialized) { if (!window.chatInitialized) {
window.chatInitialized = true; window.chatInitialized = true;
setupChat(); setupChat();

View file

@ -14,7 +14,19 @@
<link rel="stylesheet" href="css/app.css" /> <link rel="stylesheet" href="css/app.css" />
<link rel="stylesheet" href="css/apps-extended.css" /> <link rel="stylesheet" href="css/apps-extended.css" />
<link rel="stylesheet" href="css/components.css" /> <link rel="stylesheet" href="css/components.css" />
<link rel="stylesheet" href="css/base.css" />
<!-- App-specific CSS -->
<link rel="stylesheet" href="chat/chat.css" /> <link rel="stylesheet" href="chat/chat.css" />
<link rel="stylesheet" href="calendar/calendar.css" />
<link rel="stylesheet" href="drive/drive.css" />
<link rel="stylesheet" href="mail/mail.css" />
<link rel="stylesheet" href="meet/meet.css" />
<link rel="stylesheet" href="paper/paper.css" />
<link rel="stylesheet" href="research/research.css" />
<link rel="stylesheet" href="tasks/tasks.css" />
<link rel="stylesheet" href="analytics/analytics.css" />
<link rel="stylesheet" href="monitoring/monitoring.css" />
<!-- Local Libraries (no external CDN dependencies) --> <!-- Local Libraries (no external CDN dependencies) -->
<script src="js/vendor/htmx.min.js"></script> <script src="js/vendor/htmx.min.js"></script>