n8n-nodes-enhanced-chat
Version:
Enhanced Chat UI for n8n - Complete interactive chat solution with Enhanced Chat Trigger, Chat UI Renderer, HTML Renderer, and Callback Handler nodes. Features dynamic forms, media, WebRTC, and interactive workflows.
189 lines (175 loc) • 6.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatTestUtils = exports.sanitizeInput = exports.generateSessionId = void 0;
function generateSessionId() {
return 'sess_' + Math.random().toString(36).substr(2, 9);
}
exports.generateSessionId = generateSessionId;
function sanitizeInput(input) {
// Basic sanitization: escape < and >
return input.replace(/</g, '<').replace(/>/g, '>');
}
exports.sanitizeInput = sanitizeInput;
class ChatTestUtils {
static generateTestChatPopup(config) {
const { webhookUrl, method, title, width, height } = config;
return `
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 100%;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 20px;
}
.test-button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 10px;
}
.test-button:hover {
background-color: #0056b3;
}
.response-container {
margin-top: 20px;
padding: 15px;
background-color: #f8f9fa;
border-radius: 5px;
border: 1px solid #dee2e6;
}
.loading {
text-align: center;
color: #666;
font-style: italic;
}
.error {
color: #dc3545;
font-weight: bold;
}
.success {
color: #28a745;
font-weight: bold;
}
.webhook-info {
background-color: #e9ecef;
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
font-family: monospace;
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>${title}</h1>
<p>Test your chat webhook functionality</p>
</div>
<div class="webhook-info">
<strong>Webhook URL:</strong> ${webhookUrl}<br>
<strong>Method:</strong> ${method}
</div>
<div style="text-align: center;">
<button class="test-button" onclick="testWebhook()">Test Webhook</button>
<button class="test-button" onclick="clearResponse()">Clear Response</button>
</div>
<div id="response-container" class="response-container" style="display: none;">
<h3>Response:</h3>
<div id="response-content"></div>
</div>
</div>
<script>
async function testWebhook() {
const responseContainer = document.getElementById('response-container');
const responseContent = document.getElementById('response-content');
responseContainer.style.display = 'block';
responseContent.innerHTML = '<div class="loading">Loading...</div>';
try {
const options = {
method: '${method}',
headers: {
'Content-Type': 'application/json',
}
};
if ('${method}' === 'POST') {
options.body = JSON.stringify({
testMessage: 'Test message from popup',
timestamp: new Date().toISOString(),
chatInput: 'Hello from Test Chat!',
sessionId: 'test-session-' + Date.now()
});
}
const response = await fetch('${webhookUrl}', options);
const data = await response.json();
if (response.ok) {
responseContent.innerHTML = '<div class="success">✅ Success!</div>';
// Check if response contains HTML content
if (data.html) {
responseContent.innerHTML += '<div style="margin-top: 10px;">' + data.html + '</div>';
} else if (data.response && data.response.html) {
responseContent.innerHTML += '<div style="margin-top: 10px;">' + data.response.html + '</div>';
} else {
responseContent.innerHTML += '<pre style="background: #f8f9fa; padding: 10px; border-radius: 5px; margin-top: 10px; text-align: left;">' + JSON.stringify(data, null, 2) + '</pre>';
}
} else {
responseContent.innerHTML = '<div class="error">❌ Error: ' + response.status + ' - ' + response.statusText + '</div>';
}
} catch (error) {
responseContent.innerHTML = '<div class="error">❌ Error: ' + error.message + '</div>';
console.error('Test webhook error:', error);
}
}
function clearResponse() {
document.getElementById('response-container').style.display = 'none';
}
// Auto-resize window if needed
window.addEventListener('load', function() {
const content = document.body.scrollHeight;
if (content > ${height}) {
window.resizeTo(${width}, Math.min(content + 100, screen.height - 100));
}
});
// Focus on the window when it loads
window.focus();
</script>
</body>
</html>
`;
}
static openTestChatWindow(config) {
const html = this.generateTestChatPopup(config);
const blob = new Blob([html], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const popup = window.open(url, 'testChatWindow', `width=${config.width},height=${config.height},scrollbars=yes,resizable=yes`);
// Clean up the blob URL after the window is closed
if (popup) {
popup.addEventListener('beforeunload', () => {
URL.revokeObjectURL(url);
});
}
}
}
exports.ChatTestUtils = ChatTestUtils;