This commit is contained in:
Slipstream 2025-05-05 20:43:11 -06:00
parent d97555d959
commit 59ef9f5a8a
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
3 changed files with 249 additions and 445 deletions

View File

@ -73,10 +73,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
Permissions
</a>
<a href="#ai-settings" class="nav-item" data-section="ai-settings-section" id="nav-ai-settings">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
AI Settings
</a>
<a href="#theme-settings" class="nav-item" data-section="theme-settings-section" id="nav-theme-settings">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
Theme Settings
@ -270,131 +266,12 @@
<p id="perms-feedback" class="mt-2"></p>
</div>
</div>
</div>
</div>
<!-- Include AI Settings Section -->
<!-- AI Settings Section -->
<div id="ai-settings-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">AI Settings</h2>
</div>
</div>
<!-- AI Settings Section Removed -->
<div id="ai-settings-form">
<!-- Model Settings Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Model Settings</h3>
</div>
<div class="form-group">
<label for="ai-model-select">AI Model:</label>
<select id="ai-model-select" class="w-full">
<option value="openai/gpt-3.5-turbo">GPT-3.5 Turbo</option>
<option value="openai/gpt-4">GPT-4</option>
<option value="anthropic/claude-3-opus">Claude 3 Opus</option>
<option value="anthropic/claude-3-sonnet">Claude 3 Sonnet</option>
<option value="anthropic/claude-3-haiku">Claude 3 Haiku</option>
<option value="google/gemini-pro">Gemini Pro</option>
</select>
</div>
<div class="form-group">
<label for="ai-temperature">Temperature: <span id="temperature-value">0.7</span></label>
<input type="range" id="ai-temperature" min="0" max="1" step="0.1" value="0.7" class="w-full">
</div>
<div class="form-group">
<label for="ai-max-tokens">Max Tokens:</label>
<input type="number" id="ai-max-tokens" min="100" max="8000" value="1000" class="w-full">
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="ai-reasoning-enabled" name="reasoning_enabled">
<label for="ai-reasoning-enabled">Enable Reasoning</label>
</div>
</div>
<div id="reasoning-effort-group" class="form-group" style="display: none;">
<label for="ai-reasoning-effort">Reasoning Effort:</label>
<select id="ai-reasoning-effort" class="w-full">
<option value="low">Low</option>
<option value="medium" selected>Medium</option>
<option value="high">High</option>
</select>
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="ai-web-search-enabled" name="web_search_enabled">
<label for="ai-web-search-enabled">Enable Web Search</label>
</div>
</div>
<div class="btn-group">
<button id="save-ai-settings-button" class="btn btn-primary">Save Model Settings</button>
<button id="reset-ai-settings-button" class="btn btn-warning">Reset to Defaults</button>
</div>
<p id="ai-settings-feedback" class="mt-2"></p>
</div>
<!-- System Prompt Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">System Prompt</h3>
</div>
<div class="form-group">
<label for="ai-system-prompt">System Prompt:</label>
<textarea id="ai-system-prompt" rows="6" class="w-full" placeholder="Enter a system prompt for the AI..."></textarea>
</div>
<div class="btn-group">
<button id="save-system-prompt-button" class="btn btn-primary">Save System Prompt</button>
<button id="reset-system-prompt-button" class="btn btn-warning">Reset to Default</button>
</div>
<p id="system-prompt-feedback" class="mt-2"></p>
</div>
<!-- Character Settings Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Character Settings</h3>
</div>
<div class="form-group">
<label for="ai-character">Character Name:</label>
<input type="text" id="ai-character" class="w-full" placeholder="Enter a character name...">
</div>
<div class="form-group">
<label for="ai-character-info">Character Information:</label>
<textarea id="ai-character-info" rows="6" class="w-full" placeholder="Enter character information..."></textarea>
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="ai-character-breakdown" name="character_breakdown">
<label for="ai-character-breakdown">Enable Character Breakdown</label>
</div>
</div>
<div class="btn-group">
<button id="save-character-settings-button" class="btn btn-primary">Save Character Settings</button>
<button id="clear-character-settings-button" class="btn btn-warning">Clear Character</button>
</div>
<p id="character-settings-feedback" class="mt-2"></p>
</div>
<!-- Custom Instructions Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Custom Instructions</h3>
</div>
<div class="form-group">
<label for="ai-custom-instructions">Custom Instructions:</label>
<textarea id="ai-custom-instructions" rows="6" class="w-full" placeholder="Enter custom instructions for the AI..."></textarea>
</div>
<div class="btn-group">
<button id="save-custom-instructions-button" class="btn btn-primary">Save Custom Instructions</button>
<button id="clear-custom-instructions-button" class="btn btn-warning">Clear Instructions</button>
</div>
<p id="custom-instructions-feedback" class="mt-2"></p>
</div>
</div>
</div>
<!-- Include Theme Settings Section -->
<div id="theme-settings-template" style="display: none;">
<!-- Include Theme Settings Section -->
<div id="theme-settings-template" style="display: none;">
<!-- This template will be used to restore the form after loading -->
<div class="card">
<div class="card-header">
@ -729,12 +606,12 @@
<!-- JavaScript files -->
<script src="js/utils.js"></script>
<script src="js/main.js"></script>
<script src="js/ai-settings.js"></script>
<script src="js/theme-settings.js"></script>
<script src="js/command-customization.js"></script>
<script src="js/cog-management.js"></script>
<!-- JavaScript files -->
<script src="js/utils.js"></script>
<script src="js/main.js"></script>
<!-- <script src="js/ai-settings.js"></script> --> <!-- Removed AI settings script -->
<script src="js/theme-settings.js"></script>
<script src="js/command-customization.js"></script>
<script src="js/cog-management.js"></script>
</body>
</html>

View File

@ -3,11 +3,11 @@
* Handles cog and command enabling/disabling functionality
*/
// Global variables
let cogsData = [];
let commandsData = {};
let selectedGuildId = null;
let cogManagementLoaded = false;
// Global variables for this specific module's state
let cogsData = []; // Holds the raw data fetched from the API for the current guild
let commandsData = {}; // Holds processed command data for the current guild
// let selectedGuildId = null; // This is now managed globally in main.js as window.selectedGuildId
let cogManagementLoadedGuild = null; // Track which guild's data is loaded for this module
// Initialize cog management when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
@ -17,11 +17,11 @@ document.addEventListener('DOMContentLoaded', () => {
/**
* Initialize cog management functionality
*/
function initCogManagement() {
// Get DOM elements
const cogGuildSelect = document.getElementById('cog-guild-select');
const cogFilter = document.getElementById('cog-filter');
const saveCogsButton = document.getElementById('save-cogs-button');
function initCogManagement() {
// Get DOM elements
// const cogGuildSelect = document.getElementById('cog-guild-select'); // Dropdown removed
const cogFilter = document.getElementById('cog-filter');
const saveCogsButton = document.getElementById('save-cogs-button');
const saveCommandsButton = document.getElementById('save-commands-button');
const navCogManagement = document.getElementById('nav-cog-management');
@ -31,95 +31,64 @@ function initCogManagement() {
// Show cog management section
showSection('cog-management');
// Load guilds if not already loaded
if (!cogManagementLoaded) {
loadGuildsForCogManagement();
cogManagementLoaded = true;
}
});
// Data loading is now handled by showSection in main.js when the section becomes visible
});
}
// Add event listener for guild select
if (cogGuildSelect) {
cogGuildSelect.addEventListener('change', () => {
selectedGuildId = cogGuildSelect.value;
if (selectedGuildId) {
loadCogsAndCommands(selectedGuildId);
} else {
// Hide content if no guild selected
document.getElementById('cog-management-content').style.display = 'none';
}
});
}
// Remove event listener for the old guild select dropdown
// if (cogGuildSelect) {
// cogGuildSelect.addEventListener('change', () => {
// // This logic is now handled by the main server selection flow in main.js
// // selectedGuildId = cogGuildSelect.value; // Use window.selectedGuildId from main.js
// // loadCogsAndCommands(window.selectedGuildId);
// });
// }
// Add event listener for cog filter
// Add event listener for cog filter
if (cogFilter) {
cogFilter.addEventListener('change', () => {
filterCommands(cogFilter.value);
});
}
// Add event listener for save cogs button
if (saveCogsButton) {
saveCogsButton.addEventListener('click', () => {
saveCogsSettings();
});
// Add event listener for save cogs button
if (saveCogsButton) {
saveCogsButton.addEventListener('click', () => {
saveCogsSettings(); // Will use window.selectedGuildId from main.js
});
}
// Add event listener for save commands button
if (saveCommandsButton) {
saveCommandsButton.addEventListener('click', () => {
saveCommandsSettings();
});
// Add event listener for save commands button
if (saveCommandsButton) {
saveCommandsButton.addEventListener('click', () => {
saveCommandsSettings(); // Will use window.selectedGuildId from main.js
});
}
}
/**
* Load cogs and commands for a guild. This function is now intended to be called
* by the main logic in main.js (via showSection) when the cog management section
* becomes visible and needs its data loaded for the currently selected guild.
* @param {string} guildId - The guild ID (passed from main.js, expected to be window.selectedGuildId)
*/
function loadCogManagementData(guildId) { // Renamed function
// Check if data for this guild is already loaded
if (cogManagementLoadedGuild === guildId) {
console.log(`Cog management data for guild ${guildId} already loaded.`);
// Ensure content is visible if navigating back
document.getElementById('cog-management-loading').style.display = 'none';
document.getElementById('cog-management-content').style.display = 'block';
return;
}
}
console.log(`Loading cog management data for guild: ${guildId}`);
/**
* Load guilds for cog management
*/
function loadGuildsForCogManagement() {
const cogGuildSelect = document.getElementById('cog-guild-select');
// Show loading state
cogGuildSelect.disabled = true;
cogGuildSelect.innerHTML = '<option value="">Loading servers...</option>';
// Fetch guilds from API
API.get('/dashboard/api/guilds')
.then(guilds => {
// Clear loading state
cogGuildSelect.innerHTML = '<option value="">--Please choose a server--</option>';
// Add guilds to select
guilds.forEach(guild => {
const option = document.createElement('option');
option.value = guild.id;
option.textContent = guild.name;
cogGuildSelect.appendChild(option);
});
// Enable select
cogGuildSelect.disabled = false;
})
.catch(error => {
console.error('Error loading guilds:', error);
cogGuildSelect.innerHTML = '<option value="">Error loading servers</option>';
cogGuildSelect.disabled = false;
Toast.error('Failed to load servers. Please try again.');
});
}
/**
* Load cogs and commands for a guild
* @param {string} guildId - The guild ID
*/
function loadCogsAndCommands(guildId) {
// Show loading state
document.getElementById('cog-management-loading').style.display = 'flex';
document.getElementById('cog-management-content').style.display = 'none';
// Fetch cogs and commands from API
console.log(`Loading cogs and commands for guild ${guildId}...`);
API.get(`/dashboard/api/guilds/${guildId}/cogs`)
.then(data => {
console.log('Cogs and commands loaded successfully:', data);
@ -135,11 +104,16 @@ function loadCogsAndCommands(guildId) {
// Hide loading state
document.getElementById('cog-management-loading').style.display = 'none';
document.getElementById('cog-management-content').style.display = 'block';
// Mark data as loaded for this guild
cogManagementLoadedGuild = guildId;
})
.catch(error => {
console.error('Error loading cogs and commands:', error);
document.getElementById('cog-management-loading').style.display = 'none';
Toast.error('Failed to load cogs and commands. Please try again.');
document.getElementById('cog-management-loading').style.display = 'none';
Toast.error('Failed to load cogs and commands. Please try again.');
});
}
@ -322,10 +296,13 @@ function filterCommands(cogName) {
}
/**
* Save cogs settings
* Save cogs settings. Uses the globally stored window.selectedGuildId.
*/
function saveCogsSettings() {
if (!selectedGuildId) return;
if (!window.selectedGuildId) { // Use global guild ID from main.js
Toast.error("No server selected.");
return;
}
// Show loading state
const saveButton = document.getElementById('save-cogs-button');
@ -343,7 +320,7 @@ function saveCogsSettings() {
});
// Send request to API
API.patch(`/dashboard/api/guilds/${selectedGuildId}/settings`, {
API.patch(`/dashboard/api/guilds/${window.selectedGuildId}/settings`, {
cogs: cogsPayload
})
.then(() => {
@ -379,10 +356,13 @@ function saveCogsSettings() {
}
/**
* Save commands settings
* Save commands settings. Uses the globally stored window.selectedGuildId.
*/
function saveCommandsSettings() {
if (!selectedGuildId) return;
if (!window.selectedGuildId) { // Use global guild ID from main.js
Toast.error("No server selected.");
return;
}
// Show loading state
const saveButton = document.getElementById('save-commands-button');
@ -398,7 +378,7 @@ function saveCommandsSettings() {
});
// Send request to API
API.patch(`/dashboard/api/guilds/${selectedGuildId}/settings`, {
API.patch(`/dashboard/api/guilds/${window.selectedGuildId}/settings`, {
commands: commandsPayload
})
.then(() => {

View File

@ -3,6 +3,9 @@
* Handles command customization functionality for the dashboard
*/
// Track loaded state
let commandCustomizationLoadedGuild = null;
// Initialize command customization when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
initCommandCustomization();
@ -30,55 +33,63 @@ function initCommandCustomization() {
addAliasButton.addEventListener('click', addAlias);
}
// Load command customizations when the section is shown
const navItem = document.querySelector('a[data-section="command-customization-section"]');
if (navItem) {
navItem.addEventListener('click', () => {
loadCommandCustomizations();
});
}
// Loading is now handled by showSection in main.js
// const navItem = document.querySelector('a[data-section="command-customization-section"]');
// if (navItem) {
// navItem.addEventListener('click', () => {
// loadCommandCustomizationData(window.selectedGuildId); // Pass guildId
// });
// }
}
/**
* Load command customizations from API
* @param {string} guildId - The guild ID (passed from main.js)
*/
async function loadCommandCustomizations() {
async function loadCommandCustomizationData(guildId) { // Renamed function
// Track loaded state for this module
if (commandCustomizationLoadedGuild === guildId) {
console.log(`Command customization data for guild ${guildId} already loaded.`);
// Ensure content is visible if navigating back
document.getElementById('command-list').style.display = 'block';
document.getElementById('group-list').style.display = 'block';
document.getElementById('alias-list').style.display = 'block';
return;
}
console.log(`Loading command customization data for guild: ${guildId}`);
try {
// Show loading spinners
document.getElementById('command-list').innerHTML = '<div class="loading-spinner-container"><div class="loading-spinner"></div></div>';
document.getElementById('group-list').innerHTML = '<div class="loading-spinner-container"><div class="loading-spinner"></div></div>';
document.getElementById('alias-list').innerHTML = '<div class="loading-spinner-container"><div class="loading-spinner"></div></div>';
// Get the current guild ID
const guildId = getCurrentGuildId();
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected for command customization.');
return;
}
// Fetch command customizations from API
const response = await fetch(`/dashboard/commands/customizations/${guildId}`);
if (!response.ok) {
throw new Error('Failed to load command customizations');
}
// Fetch command customizations from API using the API helper
const data = await API.get(`/dashboard/api/guilds/${guildId}/command-customizations`); // Updated endpoint
const data = await response.json();
// Render command customizations
renderCommandCustomizations(data.command_customizations);
renderCommandCustomizations(data.command_customizations || {});
// Render group customizations
renderGroupCustomizations(data.group_customizations);
renderGroupCustomizations(data.group_customizations || {});
// Render command aliases
renderCommandAliases(data.command_aliases);
renderCommandAliases(data.command_aliases || {});
// Populate command select for aliases
populateCommandSelect(Object.keys(data.command_customizations));
populateCommandSelect(Object.keys(data.command_customizations || {}));
// Mark as loaded for this guild
commandCustomizationLoadedGuild = guildId;
} catch (error) {
console.error('Error loading command customizations:', error);
showToast('error', 'Error', 'Failed to load command customizations');
Toast.error('Failed to load command customizations');
// Show error message in lists
document.getElementById('command-list').innerHTML = '<div class="alert alert-danger">Failed to load command customizations</div>';
document.getElementById('group-list').innerHTML = '<div class="alert alert-danger">Failed to load group customizations</div>';
@ -93,15 +104,15 @@ async function loadCommandCustomizations() {
function renderCommandCustomizations(commandCustomizations) {
const commandList = document.getElementById('command-list');
commandList.innerHTML = '';
if (Object.keys(commandCustomizations).length === 0) {
commandList.innerHTML = '<div class="alert alert-info">No commands found</div>';
commandList.innerHTML = '<div class="alert alert-info">No commands found or available for customization.</div>';
return;
}
// Sort commands alphabetically
const sortedCommands = Object.keys(commandCustomizations).sort();
// Create command items
sortedCommands.forEach(commandName => {
const customization = commandCustomizations[commandName];
@ -120,43 +131,43 @@ function createCommandItem(commandName, customization) {
// Clone the template
const template = document.getElementById('command-item-template');
const commandItem = template.content.cloneNode(true).querySelector('.command-item');
// Set command name
const nameElement = commandItem.querySelector('.command-name');
nameElement.textContent = commandName;
if (customization.name && customization.name !== commandName) {
nameElement.textContent = `${customization.name} (${commandName})`;
}
// Set command description
const descriptionElement = commandItem.querySelector('.command-description');
descriptionElement.textContent = customization.description || 'No description available';
// Set custom name input value
const customNameInput = commandItem.querySelector('.custom-command-name');
customNameInput.value = customization.name || '';
customNameInput.placeholder = commandName;
// Set custom description input value
const customDescriptionInput = commandItem.querySelector('.custom-command-description');
customDescriptionInput.value = customization.description || '';
// Add event listeners to buttons
const editButton = commandItem.querySelector('.edit-command-btn');
const resetButton = commandItem.querySelector('.reset-command-btn');
const saveButton = commandItem.querySelector('.save-command-btn');
const cancelButton = commandItem.querySelector('.cancel-command-btn');
const customizationDiv = commandItem.querySelector('.command-customization');
editButton.addEventListener('click', () => {
customizationDiv.style.display = 'block';
editButton.style.display = 'none';
});
resetButton.addEventListener('click', () => {
resetCommandCustomization(commandName);
});
saveButton.addEventListener('click', () => {
saveCommandCustomization(
commandName,
@ -168,19 +179,19 @@ function createCommandItem(commandName, customization) {
descriptionElement
);
});
cancelButton.addEventListener('click', () => {
customizationDiv.style.display = 'none';
editButton.style.display = 'inline-block';
// Reset input values
customNameInput.value = customization.name || '';
customDescriptionInput.value = customization.description || '';
});
// Add data attribute for filtering
commandItem.dataset.commandName = commandName.toLowerCase();
return commandItem;
}
@ -206,63 +217,55 @@ async function saveCommandCustomization(
try {
// Validate custom name format if provided
if (customName && (!/^[a-z][a-z0-9_]*$/.test(customName) || customName.length > 32)) {
showToast('error', 'Error', 'Custom command names must be lowercase, start with a letter, and contain only letters, numbers, and underscores (max 32 characters)');
Toast.error('Custom command names must be lowercase, start with a letter, and contain only letters, numbers, and underscores (max 32 characters)');
return;
}
// Validate custom description if provided
if (customDescription && customDescription.length > 100) {
showToast('error', 'Error', 'Custom command descriptions must be 100 characters or less');
Toast.error('Custom command descriptions must be 100 characters or less');
return;
}
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Prepare request data
const requestData = {
command_name: commandName,
custom_name: customName || null,
custom_description: customDescription || null
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/commands`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to save command customization');
}
await API.post(`/dashboard/api/guilds/${guildId}/command-customizations/commands`, requestData); // Updated endpoint
// Update UI
customizationDiv.style.display = 'none';
editButton.style.display = 'inline-block';
if (customName) {
nameElement.textContent = `${customName} (${commandName})`;
} else {
nameElement.textContent = commandName;
}
if (customDescription) {
descriptionElement.textContent = customDescription;
} else {
descriptionElement.textContent = 'No description available';
// Fetch the original description if resetting
// This might require an extra API call or storing original data
descriptionElement.textContent = 'No description available'; // Placeholder
}
showToast('success', 'Success', 'Command customization saved successfully');
Toast.success('Command customization saved successfully');
} catch (error) {
console.error('Error saving command customization:', error);
showToast('error', 'Error', 'Failed to save command customization');
Toast.error(`Failed to save command customization: ${error.message || error}`);
}
}
@ -273,39 +276,29 @@ async function saveCommandCustomization(
async function resetCommandCustomization(commandName) {
try {
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Prepare request data
const requestData = {
command_name: commandName,
custom_name: null,
custom_description: null
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/commands`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to reset command customization');
}
await API.post(`/dashboard/api/guilds/${guildId}/command-customizations/commands`, requestData); // Updated endpoint
// Reload command customizations
loadCommandCustomizations();
showToast('success', 'Success', 'Command customization reset successfully');
loadCommandCustomizationData(guildId); // Reload data for the current guild
Toast.success('Command customization reset successfully');
} catch (error) {
console.error('Error resetting command customization:', error);
showToast('error', 'Error', 'Failed to reset command customization');
Toast.error(`Failed to reset command customization: ${error.message || error}`);
}
}
@ -316,15 +309,15 @@ async function resetCommandCustomization(commandName) {
function renderGroupCustomizations(groupCustomizations) {
const groupList = document.getElementById('group-list');
groupList.innerHTML = '';
if (Object.keys(groupCustomizations).length === 0) {
groupList.innerHTML = '<div class="alert alert-info">No command groups found</div>';
groupList.innerHTML = '<div class="alert alert-info">No command groups found or available for customization.</div>';
return;
}
// Sort groups alphabetically
const sortedGroups = Object.keys(groupCustomizations).sort();
// Create group items
sortedGroups.forEach(groupName => {
const customName = groupCustomizations[groupName];
@ -343,35 +336,35 @@ function createGroupItem(groupName, customName) {
// Clone the template
const template = document.getElementById('group-item-template');
const groupItem = template.content.cloneNode(true).querySelector('.command-item');
// Set group name
const nameElement = groupItem.querySelector('.group-name');
nameElement.textContent = groupName;
if (customName && customName !== groupName) {
nameElement.textContent = `${customName} (${groupName})`;
}
// Set custom name input value
const customNameInput = groupItem.querySelector('.custom-group-name');
customNameInput.value = customName || '';
customNameInput.placeholder = groupName;
// Add event listeners to buttons
const editButton = groupItem.querySelector('.edit-group-btn');
const resetButton = groupItem.querySelector('.reset-group-btn');
const saveButton = groupItem.querySelector('.save-group-btn');
const cancelButton = groupItem.querySelector('.cancel-group-btn');
const customizationDiv = groupItem.querySelector('.group-customization');
editButton.addEventListener('click', () => {
customizationDiv.style.display = 'block';
editButton.style.display = 'none';
});
resetButton.addEventListener('click', () => {
resetGroupCustomization(groupName);
});
saveButton.addEventListener('click', () => {
saveGroupCustomization(
groupName,
@ -381,15 +374,15 @@ function createGroupItem(groupName, customName) {
nameElement
);
});
cancelButton.addEventListener('click', () => {
customizationDiv.style.display = 'none';
editButton.style.display = 'inline-block';
// Reset input value
customNameInput.value = customName || '';
});
return groupItem;
}
@ -411,50 +404,40 @@ async function saveGroupCustomization(
try {
// Validate custom name format if provided
if (customName && (!/^[a-z][a-z0-9_]*$/.test(customName) || customName.length > 32)) {
showToast('error', 'Error', 'Custom group names must be lowercase, start with a letter, and contain only letters, numbers, and underscores (max 32 characters)');
Toast.error('Custom group names must be lowercase, start with a letter, and contain only letters, numbers, and underscores (max 32 characters)');
return;
}
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Prepare request data
const requestData = {
group_name: groupName,
custom_name: customName || null
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/groups`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to save group customization');
}
await API.post(`/dashboard/api/guilds/${guildId}/command-customizations/groups`, requestData); // Updated endpoint
// Update UI
customizationDiv.style.display = 'none';
editButton.style.display = 'inline-block';
if (customName) {
nameElement.textContent = `${customName} (${groupName})`;
} else {
nameElement.textContent = groupName;
}
showToast('success', 'Success', 'Group customization saved successfully');
Toast.success('Group customization saved successfully');
} catch (error) {
console.error('Error saving group customization:', error);
showToast('error', 'Error', 'Failed to save group customization');
Toast.error(`Failed to save group customization: ${error.message || error}`);
}
}
@ -465,38 +448,28 @@ async function saveGroupCustomization(
async function resetGroupCustomization(groupName) {
try {
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Prepare request data
const requestData = {
group_name: groupName,
custom_name: null
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/groups`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to reset group customization');
}
await API.post(`/dashboard/api/guilds/${guildId}/command-customizations/groups`, requestData); // Updated endpoint
// Reload command customizations
loadCommandCustomizations();
showToast('success', 'Success', 'Group customization reset successfully');
loadCommandCustomizationData(guildId); // Reload data for the current guild
Toast.success('Group customization reset successfully');
} catch (error) {
console.error('Error resetting group customization:', error);
showToast('error', 'Error', 'Failed to reset group customization');
Toast.error(`Failed to reset group customization: ${error.message || error}`);
}
}
@ -507,15 +480,15 @@ async function resetGroupCustomization(groupName) {
function renderCommandAliases(commandAliases) {
const aliasList = document.getElementById('alias-list');
aliasList.innerHTML = '';
if (Object.keys(commandAliases).length === 0) {
aliasList.innerHTML = '<div class="alert alert-info">No command aliases found</div>';
aliasList.innerHTML = '<div class="alert alert-info">No command aliases found.</div>';
return;
}
// Sort commands alphabetically
const sortedCommands = Object.keys(commandAliases).sort();
// Create alias items
sortedCommands.forEach(commandName => {
const aliases = commandAliases[commandName];
@ -536,18 +509,18 @@ function createAliasItem(commandName, aliases) {
// Clone the template
const template = document.getElementById('alias-item-template');
const aliasItem = template.content.cloneNode(true).querySelector('.alias-item');
// Set command name
const nameElement = aliasItem.querySelector('.command-name');
nameElement.textContent = commandName;
// Add alias tags
const aliasTagsList = aliasItem.querySelector('.alias-tags');
aliases.forEach(alias => {
const aliasTag = createAliasTag(commandName, alias);
aliasTagsList.appendChild(aliasTag);
});
return aliasItem;
}
@ -561,17 +534,17 @@ function createAliasTag(commandName, alias) {
// Clone the template
const template = document.getElementById('alias-tag-template');
const aliasTag = template.content.cloneNode(true).querySelector('.alias-tag');
// Set alias name
const nameElement = aliasTag.querySelector('.alias-name');
nameElement.textContent = alias;
// Add event listener to remove button
const removeButton = aliasTag.querySelector('.remove-alias-btn');
removeButton.addEventListener('click', () => {
removeAlias(commandName, alias);
});
return aliasTag;
}
@ -582,10 +555,10 @@ function createAliasTag(commandName, alias) {
function populateCommandSelect(commands) {
const commandSelect = document.getElementById('alias-command-select');
commandSelect.innerHTML = '<option value="">Select a command</option>';
// Sort commands alphabetically
const sortedCommands = commands.sort();
// Add command options
sortedCommands.forEach(commandName => {
const option = document.createElement('option');
@ -604,76 +577,66 @@ async function addAlias() {
const commandSelect = document.getElementById('alias-command-select');
const aliasInput = document.getElementById('alias-name-input');
const feedbackElement = document.getElementById('alias-feedback');
const commandName = commandSelect.value;
const aliasName = aliasInput.value.trim();
// Validate inputs
if (!commandName) {
feedbackElement.textContent = 'Please select a command';
feedbackElement.className = 'mt-2 text-danger';
return;
}
if (!aliasName) {
feedbackElement.textContent = 'Please enter an alias name';
feedbackElement.className = 'mt-2 text-danger';
return;
}
// Validate alias format
if (!/^[a-z][a-z0-9_]*$/.test(aliasName) || aliasName.length > 32) {
feedbackElement.textContent = 'Alias names must be lowercase, start with a letter, and contain only letters, numbers, and underscores (max 32 characters)';
feedbackElement.className = 'mt-2 text-danger';
return;
}
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
feedbackElement.textContent = 'No guild selected';
feedbackElement.className = 'mt-2 text-danger';
return;
}
// Prepare request data
const requestData = {
command_name: commandName,
alias_name: aliasName
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/aliases`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to add command alias');
}
await API.post(`/dashboard/api/guilds/${guildId}/command-customizations/aliases`, requestData); // Updated endpoint
// Clear input
aliasInput.value = '';
// Show success message
feedbackElement.textContent = 'Alias added successfully';
feedbackElement.className = 'mt-2 text-success';
// Reload command customizations
loadCommandCustomizations();
showToast('success', 'Success', 'Command alias added successfully');
loadCommandCustomizationData(guildId); // Reload data for the current guild
Toast.success('Command alias added successfully');
} catch (error) {
console.error('Error adding command alias:', error);
const feedbackElement = document.getElementById('alias-feedback');
feedbackElement.textContent = 'Failed to add command alias';
feedbackElement.textContent = `Failed to add command alias: ${error.message || error}`;
feedbackElement.className = 'mt-2 text-danger';
showToast('error', 'Error', 'Failed to add command alias');
Toast.error('Failed to add command alias');
}
}
@ -685,38 +648,28 @@ async function addAlias() {
async function removeAlias(commandName, aliasName) {
try {
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Prepare request data
const requestData = {
command_name: commandName,
alias_name: aliasName
};
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/aliases`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error('Failed to remove command alias');
}
await API.delete(`/dashboard/api/guilds/${guildId}/command-customizations/aliases`, requestData); // Updated endpoint
// Reload command customizations
loadCommandCustomizations();
showToast('success', 'Success', 'Command alias removed successfully');
loadCommandCustomizationData(guildId); // Reload data for the current guild
Toast.success('Command alias removed successfully');
} catch (error) {
console.error('Error removing command alias:', error);
showToast('error', 'Error', 'Failed to remove command alias');
Toast.error(`Failed to remove command alias: ${error.message || error}`);
}
}
@ -726,40 +679,34 @@ async function removeAlias(commandName, aliasName) {
async function syncCommands() {
try {
// Get the current guild ID
const guildId = getCurrentGuildId();
const guildId = window.selectedGuildId; // Use global guild ID
if (!guildId) {
showToast('error', 'Error', 'No guild selected');
Toast.error('No guild selected');
return;
}
// Show feedback
const feedbackElement = document.getElementById('sync-feedback');
feedbackElement.textContent = 'Syncing commands...';
feedbackElement.className = 'mt-2 text-info';
// Send request to API
const response = await fetch(`/dashboard/commands/customizations/${guildId}/sync`, {
method: 'POST'
});
if (!response.ok) {
throw new Error('Failed to sync commands');
}
await API.post(`/dashboard/api/guilds/${guildId}/sync-commands`); // Updated endpoint
// Show success message
feedbackElement.textContent = 'Commands synced successfully';
feedbackElement.className = 'mt-2 text-success';
showToast('success', 'Success', 'Commands synced successfully');
Toast.success('Commands synced successfully');
} catch (error) {
console.error('Error syncing commands:', error);
// Show error message
const feedbackElement = document.getElementById('sync-feedback');
feedbackElement.textContent = 'Failed to sync commands';
feedbackElement.textContent = `Failed to sync commands: ${error.message || error}`;
feedbackElement.className = 'mt-2 text-danger';
showToast('error', 'Error', 'Failed to sync commands');
Toast.error('Failed to sync commands');
}
}
@ -769,7 +716,7 @@ async function syncCommands() {
function filterCommands() {
const searchQuery = document.getElementById('command-search').value.toLowerCase();
const commandItems = document.querySelectorAll('#command-list .command-item');
commandItems.forEach(item => {
const commandName = item.dataset.commandName;
if (commandName.includes(searchQuery)) {