diff --git a/pkg/channels/http.go b/pkg/channels/http.go index e46201f23..c05bef4eb 100644 --- a/pkg/channels/http.go +++ b/pkg/channels/http.go @@ -7,6 +7,7 @@ import ( "fmt" "html/template" "net/http" + "regexp" "strings" "sync" "time" @@ -301,7 +302,24 @@ func renderMarkdown(input string) string { logger.ErrorCF("http", "renderMarkdown error", map[string]any{"error": err.Error()}) return input // fallback to plain text on error } - return buf.String() + + // Add target="_blank" to all links for security and UX + html := buf.String() + + // Pattern to match links + // This regex adds target="_blank" and rel="noopener noreferrer" to all tags + // that don't already have a target attribute + re := regexp.MustCompile(`]*?)href="([^"]*?)"([^>]*?)>`) + html = re.ReplaceAllStringFunc(html, func(match string) string { + // Check if target attribute already exists + if strings.Contains(match, `target=`) { + return match + } + // Insert target and rel attributes before closing > + return strings.Replace(match, `>`, ` target="_blank" rel="noopener noreferrer">`, 1) + }) + + return html } func min(a, b int) int { diff --git a/pkg/channels/http_templates/index.html b/pkg/channels/http_templates/index.html index bfff7ef70..0f8f7c036 100644 --- a/pkg/channels/http_templates/index.html +++ b/pkg/channels/http_templates/index.html @@ -17,18 +17,18 @@ display: flex; justify-content: center; align-items: center; - padding: 20px; + padding: 10px; } .container { width: 100%; - max-width: 1200px; + max-width: 1400px; background: #0f0f23; border-radius: 16px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); overflow: hidden; display: flex; flex-direction: column; - height: 90vh; + height: 95vh; min-height: 600px; } .header { @@ -83,6 +83,7 @@ border-radius: 16px; line-height: 1.5; word-wrap: break-word; + white-space: normal; /* Evita que los \n del HTML se rendericen como espacios */ } .message.user { align-self: flex-end; @@ -96,6 +97,31 @@ color: #e2e8f0; border-bottom-left-radius: 4px; } + /* Estilos para tablas en HTTP */ + .message.assistant table { + border-collapse: collapse; + width: 100%; + max-width: 100%; + display: block; + overflow-x: auto; + margin: 1em 0; + border: 1px solid #334155; + } + .message.assistant th, + .message.assistant td { + border: 1px solid #475569; + padding: 8px 12px; + text-align: left; + white-space: nowrap; /* Evita saltos dentro de celdas */ + background: #0f172a; + } + .message.assistant th { + background: #1e293b; + font-weight: 600; + } + .message.assistant tr:nth-child(even) td { + background: #162032; + } .message.assistant pre { background: #0f172a; padding: 12px; @@ -253,11 +279,15 @@ function addMessage(content, type) { const div = document.createElement('div'); div.className = `message ${type}`; - // Convert newlines to
for proper rendering in HTML - // For user messages, we need to preserve line breaks from textarea - let processedContent = content.replace(/\n/g, '
'); - // Also handle double newlines as paragraphs (optional, for better readability) - processedContent = processedContent.replace(/\n\n/g, '

'); + let processedContent; + if (type === 'user') { + // For user messages (plain text), convert newlines to
+ processedContent = content.replace(/\n/g, '
'); + processedContent = processedContent.replace(/\n\n/g, '

'); + } else { + // For assistant messages (HTML from backend), use as-is + processedContent = content; + } div.innerHTML = processedContent; chatContainer.appendChild(div); chatContainer.scrollTop = chatContainer.scrollHeight; diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 77fcfd929..81c405ec3 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -114,9 +114,9 @@ func DefaultConfig() *Config { ReplyTimeout: 5, }, HTTP: HTTPConfig{ - Enabled: false, - Host: "0.0.0.0", - Port: 8080, + Enabled: true, + Host: "127.0.0.1", + Port: 8070, AllowFrom: FlexibleStringSlice{}, }, },