Slipstream 0677b7e168
feat: Implement custom bot configuration dashboard
This commit introduces a new custom bot configuration dashboard, providing a streamlined interface for managing bot settings.

Key changes include:
- **UI/UX Enhancements:**
    - Added new CSS for a modern, responsive dashboard layout, including header, navigation, and form styling.
    - Implemented a dynamic bot status indicator (online/offline).
    - Improved form validation and user feedback mechanisms.
- **Frontend Logic:**
    - Refactored `custom-bot.js` to handle loading, saving, and validating bot settings.
    - Integrated `showFeedback` utility for consistent user notifications.
    - Updated API calls to use `fetch` for better control and error handling.
- **HTML Structure:**
    - Modified `index.html` to incorporate the new dashboard layout and elements.
- **Utility Functions:**
    - Added `showFeedback` function in `utils.js` for displaying success/error messages.

This feature significantly improves the user experience for configuring custom bots.
2025-05-26 15:19:26 -06:00

375 lines
11 KiB
JavaScript

/**
* Custom Bot Configuration Dashboard
* Streamlined interface for bot setup and management
*/
// Status constants
const BOT_STATUS = {
NOT_CREATED: 'not_created',
RUNNING: 'running',
STOPPED: 'stopped',
ERROR: 'error'
};
// DOM elements
let botTokenInput;
let botPrefixInput;
let botStatusTypeSelect;
let botStatusTextInput;
let saveBotConfigButton;
let startBotButton;
let stopBotButton;
let statusDot;
let statusText;
let botError;
let botConfigFeedback;
/**
* Initialize the custom bot functionality
*/
function initCustomBot() {
console.log('Initializing custom bot dashboard...');
// Get DOM elements
botTokenInput = document.getElementById('bot-token-input');
botPrefixInput = document.getElementById('bot-prefix-input');
botStatusTypeSelect = document.getElementById('bot-status-type-select');
botStatusTextInput = document.getElementById('bot-status-text-input');
saveBotConfigButton = document.getElementById('save-bot-config-button');
startBotButton = document.getElementById('start-bot-button');
stopBotButton = document.getElementById('stop-bot-button');
statusDot = document.getElementById('status-dot');
statusText = document.getElementById('status-text');
botError = document.getElementById('bot-error');
botConfigFeedback = document.getElementById('bot-config-feedback');
// Add event listeners
if (saveBotConfigButton) {
saveBotConfigButton.addEventListener('click', saveCustomBotConfig);
}
if (startBotButton) {
startBotButton.addEventListener('click', startCustomBot);
}
if (stopBotButton) {
stopBotButton.addEventListener('click', stopCustomBot);
}
// Load custom bot settings
loadCustomBotSettings();
// Check bot status periodically
checkBotStatus();
setInterval(checkBotStatus, 10000); // Check every 10 seconds
}
/**
* Load custom bot settings from the server
*/
async function loadCustomBotSettings() {
try {
console.log('Loading custom bot settings...');
const response = await fetch('/dashboard/api/settings', {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Loaded bot settings:', data);
// Fill in the form fields
if (botTokenInput && data.custom_bot_token) {
botTokenInput.value = data.custom_bot_token;
}
if (botPrefixInput) {
botPrefixInput.value = data.custom_bot_prefix || '!';
}
if (botStatusTypeSelect) {
botStatusTypeSelect.value = data.custom_bot_status_type || 'listening';
}
if (botStatusTextInput) {
botStatusTextInput.value = data.custom_bot_status_text || '!help';
}
showFeedback('Bot settings loaded successfully', false);
} catch (error) {
console.error('Error loading custom bot settings:', error);
showFeedback('Failed to load custom bot settings: ' + error.message, true);
}
}
/**
* Save custom bot configuration
*/
async function saveCustomBotConfig() {
try {
console.log('Saving custom bot configuration...');
// Validate inputs
if (!botTokenInput.value.trim()) {
showFeedback('Bot token is required', true);
return;
}
if (!botPrefixInput.value.trim()) {
showFeedback('Command prefix is required', true);
return;
}
if (!botStatusTextInput.value.trim()) {
showFeedback('Status text is required', true);
return;
}
// Prepare the settings object
const settings = {
custom_bot_token: botTokenInput.value.trim(),
custom_bot_prefix: botPrefixInput.value.trim(),
custom_bot_status_type: botStatusTypeSelect.value,
custom_bot_status_text: botStatusTextInput.value.trim()
};
console.log('Sending bot configuration:', settings);
// Save the settings
const response = await fetch('/dashboard/api/settings', {
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(settings)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('Bot configuration saved:', result);
showFeedback('Custom bot configuration saved successfully', false);
// Check bot status after saving
setTimeout(checkBotStatus, 1000);
} catch (error) {
console.error('Error saving custom bot configuration:', error);
showFeedback('Failed to save custom bot configuration: ' + error.message, true);
}
}
/**
* Start the custom bot
*/
async function startCustomBot() {
try {
console.log('Starting custom bot...');
startBotButton.disabled = true;
startBotButton.textContent = 'Starting...';
const response = await fetch('/dashboard/api/custom-bot/start', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('Bot start result:', result);
showFeedback('Custom bot started successfully', false);
// Check bot status after starting
setTimeout(checkBotStatus, 2000);
} catch (error) {
console.error('Error starting custom bot:', error);
showFeedback('Failed to start custom bot: ' + error.message, true);
// Re-enable the button
startBotButton.disabled = false;
startBotButton.textContent = 'Start Bot';
}
}
/**
* Stop the custom bot
*/
async function stopCustomBot() {
try {
console.log('Stopping custom bot...');
stopBotButton.disabled = true;
stopBotButton.textContent = 'Stopping...';
const response = await fetch('/dashboard/api/custom-bot/stop', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('Bot stop result:', result);
showFeedback('Custom bot stopped successfully', false);
// Check bot status after stopping
setTimeout(checkBotStatus, 2000);
} catch (error) {
console.error('Error stopping custom bot:', error);
showFeedback('Failed to stop custom bot: ' + error.message, true);
// Re-enable the button
stopBotButton.disabled = false;
stopBotButton.textContent = 'Stop Bot';
}
}
/**
* Check the status of the custom bot
*/
async function checkBotStatus() {
try {
const response = await fetch('/dashboard/api/custom-bot/status', {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const status = await response.json();
console.log('Bot status:', status);
// Update the status indicator
updateStatusIndicator(status);
// Update button states
updateButtonStates(status);
// Show error if any
if (status.error && botError) {
botError.textContent = status.error;
botError.classList.remove('hidden');
} else if (botError) {
botError.classList.add('hidden');
}
} catch (error) {
console.error('Error checking custom bot status:', error);
// Set status to unknown
if (statusDot) {
statusDot.className = 'w-4 h-4 rounded-full bg-gray-400 mr-2';
}
if (statusText) {
statusText.textContent = 'Unable to check status';
}
// Disable buttons
if (startBotButton) {
startBotButton.disabled = true;
}
if (stopBotButton) {
stopBotButton.disabled = true;
}
}
}
/**
* Update the status indicator based on the bot status
*/
function updateStatusIndicator(status) {
if (!statusDot || !statusText) return;
if (status.is_running) {
statusDot.className = 'w-4 h-4 rounded-full bg-green-500 mr-2';
statusText.textContent = 'Bot is running';
} else if (status.status === BOT_STATUS.ERROR) {
statusDot.className = 'w-4 h-4 rounded-full bg-red-500 mr-2';
statusText.textContent = 'Bot has an error';
} else if (status.exists) {
statusDot.className = 'w-4 h-4 rounded-full bg-yellow-500 mr-2';
statusText.textContent = 'Bot is stopped';
} else {
statusDot.className = 'w-4 h-4 rounded-full bg-gray-400 mr-2';
statusText.textContent = 'Bot not created yet';
}
}
/**
* Update button states based on the bot status
*/
function updateButtonStates(status) {
if (!startBotButton || !stopBotButton) return;
if (status.is_running) {
startBotButton.disabled = true;
stopBotButton.disabled = false;
startBotButton.textContent = 'Bot Running';
stopBotButton.textContent = 'Stop Bot';
} else if (status.exists) {
startBotButton.disabled = false;
stopBotButton.disabled = true;
startBotButton.textContent = 'Start Bot';
stopBotButton.textContent = 'Bot Stopped';
} else {
startBotButton.disabled = false;
stopBotButton.disabled = true;
startBotButton.textContent = 'Create & Start Bot';
stopBotButton.textContent = 'Stop Bot';
}
}
/**
* Show feedback message to user
*/
function showFeedback(message, isError = false) {
if (botConfigFeedback) {
botConfigFeedback.textContent = message;
botConfigFeedback.className = isError ? 'mt-2 text-red-500' : 'mt-2 text-green-500';
// Clear feedback after 5 seconds
setTimeout(() => {
if (botConfigFeedback) {
botConfigFeedback.textContent = '';
botConfigFeedback.className = 'mt-2';
}
}, 5000);
}
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded, initializing custom bot dashboard...');
initCustomBot();
});
// Export the initialization function
window.initCustomBot = initCustomBot;