This commit is contained in:
Slipstream 2025-05-03 19:01:41 -06:00
parent e8bd48da11
commit f971fe87b8
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
5 changed files with 700 additions and 33 deletions

View File

@ -534,18 +534,52 @@ async def get_global_settings(
):
"""Get global settings for the current user."""
try:
# This would normally fetch settings from the database
# For now, we'll return a mock response
settings = GlobalSettings(
system_message="You are a helpful assistant.",
character="Kasane Teto",
character_info="Kasane Teto is a cheerful and energetic character.",
custom_instructions="Be helpful and friendly.",
model="gpt-4",
temperature=0.7,
max_tokens=2048
# Import the database module for user settings
try:
from discordbot.api_service.api_server import db
except ImportError:
from api_server import db
if not db:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Database connection not available"
)
# Get user settings from the database
user_id = _user.get('user_id')
if not user_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="User ID not found in session"
)
user_settings = db.get_user_settings(user_id)
if not user_settings:
# Return default settings if none exist
return GlobalSettings(
system_message="",
character="",
character_info="",
custom_instructions="",
model="openai/gpt-3.5-turbo",
temperature=0.7,
max_tokens=1000
)
# Convert from UserSettings to GlobalSettings
return GlobalSettings(
system_message=user_settings.get("system_message", ""),
character=user_settings.get("character", ""),
character_info=user_settings.get("character_info", ""),
custom_instructions=user_settings.get("custom_instructions", ""),
model=user_settings.get("model_id", "openai/gpt-3.5-turbo"),
temperature=user_settings.get("temperature", 0.7),
max_tokens=user_settings.get("max_tokens", 1000)
)
return settings
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
log.error(f"Error getting global settings: {e}")
raise HTTPException(
@ -554,15 +588,59 @@ async def get_global_settings(
)
@router.post("/settings", status_code=status.HTTP_200_OK)
@router.put("/settings", status_code=status.HTTP_200_OK)
async def update_global_settings(
settings: GlobalSettings,
_user: dict = Depends(get_dashboard_user)
):
"""Update global settings for the current user."""
try:
# This would normally update settings in the database
# For now, we'll just return a success message
# Import the database module for user settings
try:
from discordbot.api_service.api_server import db
from discordbot.api_service.api_models import UserSettings
except ImportError:
from api_server import db
from api_models import UserSettings
if not db:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Database connection not available"
)
# Get user ID from session
user_id = _user.get('user_id')
if not user_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="User ID not found in session"
)
# Convert from GlobalSettings to UserSettings
user_settings = UserSettings(
model_id=settings.model,
temperature=settings.temperature,
max_tokens=settings.max_tokens,
system_message=settings.system_message,
character=settings.character,
character_info=settings.character_info,
custom_instructions=settings.custom_instructions
)
# Save user settings to the database
updated_settings = db.save_user_settings(user_id, user_settings)
if not updated_settings:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to save user settings"
)
log.info(f"Updated global settings for user {user_id}")
return {"message": "Settings updated successfully"}
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
log.error(f"Error updating global settings: {e}")
raise HTTPException(

View File

@ -0,0 +1,119 @@
<!-- 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>
<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>

View File

@ -50,6 +50,10 @@
<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>
</div>
<div class="sidebar-footer">
<button id="logout-button" class="btn btn-danger w-full">
@ -241,6 +245,126 @@
</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>
<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>
</div>
</div>
@ -251,5 +375,6 @@
<!-- JavaScript files -->
<script src="js/utils.js"></script>
<script src="js/main.js"></script>
<script src="js/ai-settings.js"></script>
</body>
</html>

View File

@ -0,0 +1,328 @@
/**
* AI Settings JavaScript for the Discord Bot Dashboard
*/
// Flag to track if AI settings have been loaded
let aiSettingsLoaded = false;
/**
* Load AI settings from the API
*/
async function loadAiSettings() {
try {
const response = await API.get('/dashboard/api/settings');
if (response) {
// Populate AI model dropdown
const modelSelect = document.getElementById('ai-model-select');
if (response.model) {
// Find the option with the matching value or create a new one if it doesn't exist
let option = Array.from(modelSelect.options).find(opt => opt.value === response.model);
if (!option) {
option = new Option(response.model, response.model);
modelSelect.add(option);
}
modelSelect.value = response.model;
}
// Set temperature
const temperatureSlider = document.getElementById('ai-temperature');
const temperatureValue = document.getElementById('temperature-value');
if (response.temperature !== undefined) {
temperatureSlider.value = response.temperature;
temperatureValue.textContent = response.temperature;
}
// Set max tokens
const maxTokensInput = document.getElementById('ai-max-tokens');
if (response.max_tokens !== undefined) {
maxTokensInput.value = response.max_tokens;
}
// Set reasoning settings
const reasoningCheckbox = document.getElementById('ai-reasoning-enabled');
const reasoningEffortSelect = document.getElementById('ai-reasoning-effort');
const reasoningEffortGroup = document.getElementById('reasoning-effort-group');
if (response.reasoning_enabled !== undefined) {
reasoningCheckbox.checked = response.reasoning_enabled;
reasoningEffortGroup.style.display = response.reasoning_enabled ? 'block' : 'none';
}
if (response.reasoning_effort) {
reasoningEffortSelect.value = response.reasoning_effort;
}
// Set web search
const webSearchCheckbox = document.getElementById('ai-web-search-enabled');
if (response.web_search_enabled !== undefined) {
webSearchCheckbox.checked = response.web_search_enabled;
}
// Set system prompt
const systemPromptTextarea = document.getElementById('ai-system-prompt');
if (response.system_message) {
systemPromptTextarea.value = response.system_message;
}
// Set character settings
const characterInput = document.getElementById('ai-character');
const characterInfoTextarea = document.getElementById('ai-character-info');
const characterBreakdownCheckbox = document.getElementById('ai-character-breakdown');
if (response.character) {
characterInput.value = response.character;
}
if (response.character_info) {
characterInfoTextarea.value = response.character_info;
}
if (response.character_breakdown !== undefined) {
characterBreakdownCheckbox.checked = response.character_breakdown;
}
// Set custom instructions
const customInstructionsTextarea = document.getElementById('ai-custom-instructions');
if (response.custom_instructions) {
customInstructionsTextarea.value = response.custom_instructions;
}
aiSettingsLoaded = true;
Toast.success('AI settings loaded successfully');
}
} catch (error) {
console.error('Error loading AI settings:', error);
Toast.error('Failed to load AI settings. Please try again.');
}
}
/**
* Initialize AI settings functionality
*/
function initAiSettings() {
// Temperature slider
const temperatureSlider = document.getElementById('ai-temperature');
const temperatureValue = document.getElementById('temperature-value');
if (temperatureSlider && temperatureValue) {
temperatureSlider.addEventListener('input', function() {
temperatureValue.textContent = this.value;
});
}
// Reasoning checkbox
const reasoningCheckbox = document.getElementById('ai-reasoning-enabled');
const reasoningEffortGroup = document.getElementById('reasoning-effort-group');
if (reasoningCheckbox && reasoningEffortGroup) {
reasoningCheckbox.addEventListener('change', function() {
reasoningEffortGroup.style.display = this.checked ? 'block' : 'none';
});
}
// Save AI Settings button
const saveAiSettingsButton = document.getElementById('save-ai-settings-button');
if (saveAiSettingsButton) {
saveAiSettingsButton.addEventListener('click', async () => {
try {
const settings = {
model: document.getElementById('ai-model-select').value,
temperature: parseFloat(document.getElementById('ai-temperature').value),
max_tokens: parseInt(document.getElementById('ai-max-tokens').value),
reasoning_enabled: document.getElementById('ai-reasoning-enabled').checked,
reasoning_effort: document.getElementById('ai-reasoning-effort').value,
web_search_enabled: document.getElementById('ai-web-search-enabled').checked
};
await API.put('/dashboard/api/settings', settings);
Toast.success('AI settings saved successfully');
} catch (error) {
console.error('Error saving AI settings:', error);
Toast.error('Failed to save AI settings. Please try again.');
}
});
}
// Reset AI Settings button
const resetAiSettingsButton = document.getElementById('reset-ai-settings-button');
if (resetAiSettingsButton) {
resetAiSettingsButton.addEventListener('click', async () => {
if (!confirm('Are you sure you want to reset AI settings to defaults?')) return;
try {
const defaultSettings = {
model: "openai/gpt-3.5-turbo",
temperature: 0.7,
max_tokens: 1000,
reasoning_enabled: false,
reasoning_effort: "medium",
web_search_enabled: false
};
await API.put('/dashboard/api/settings', defaultSettings);
// Update UI with default values
document.getElementById('ai-model-select').value = defaultSettings.model;
document.getElementById('ai-temperature').value = defaultSettings.temperature;
document.getElementById('temperature-value').textContent = defaultSettings.temperature;
document.getElementById('ai-max-tokens').value = defaultSettings.max_tokens;
document.getElementById('ai-reasoning-enabled').checked = defaultSettings.reasoning_enabled;
document.getElementById('reasoning-effort-group').style.display = defaultSettings.reasoning_enabled ? 'block' : 'none';
document.getElementById('ai-reasoning-effort').value = defaultSettings.reasoning_effort;
document.getElementById('ai-web-search-enabled').checked = defaultSettings.web_search_enabled;
Toast.success('AI settings reset to defaults');
} catch (error) {
console.error('Error resetting AI settings:', error);
Toast.error('Failed to reset AI settings. Please try again.');
}
});
}
// Save System Prompt button
const saveSystemPromptButton = document.getElementById('save-system-prompt-button');
if (saveSystemPromptButton) {
saveSystemPromptButton.addEventListener('click', async () => {
try {
const settings = {
system_message: document.getElementById('ai-system-prompt').value
};
await API.put('/dashboard/api/settings', settings);
Toast.success('System prompt saved successfully');
} catch (error) {
console.error('Error saving system prompt:', error);
Toast.error('Failed to save system prompt. Please try again.');
}
});
}
// Reset System Prompt button
const resetSystemPromptButton = document.getElementById('reset-system-prompt-button');
if (resetSystemPromptButton) {
resetSystemPromptButton.addEventListener('click', async () => {
if (!confirm('Are you sure you want to reset the system prompt to default?')) return;
try {
const settings = {
system_message: ""
};
await API.put('/dashboard/api/settings', settings);
// Clear UI
document.getElementById('ai-system-prompt').value = '';
Toast.success('System prompt reset to default');
} catch (error) {
console.error('Error resetting system prompt:', error);
Toast.error('Failed to reset system prompt. Please try again.');
}
});
}
// Save Character Settings button
const saveCharacterSettingsButton = document.getElementById('save-character-settings-button');
if (saveCharacterSettingsButton) {
saveCharacterSettingsButton.addEventListener('click', async () => {
try {
const settings = {
character: document.getElementById('ai-character').value,
character_info: document.getElementById('ai-character-info').value,
character_breakdown: document.getElementById('ai-character-breakdown').checked
};
await API.put('/dashboard/api/settings', settings);
Toast.success('Character settings saved successfully');
} catch (error) {
console.error('Error saving character settings:', error);
Toast.error('Failed to save character settings. Please try again.');
}
});
}
// Clear Character button
const clearCharacterSettingsButton = document.getElementById('clear-character-settings-button');
if (clearCharacterSettingsButton) {
clearCharacterSettingsButton.addEventListener('click', async () => {
if (!confirm('Are you sure you want to clear character settings?')) return;
try {
const settings = {
character: "",
character_info: "",
character_breakdown: false
};
await API.put('/dashboard/api/settings', settings);
// Clear UI
document.getElementById('ai-character').value = '';
document.getElementById('ai-character-info').value = '';
document.getElementById('ai-character-breakdown').checked = false;
Toast.success('Character settings cleared');
} catch (error) {
console.error('Error clearing character settings:', error);
Toast.error('Failed to clear character settings. Please try again.');
}
});
}
// Save Custom Instructions button
const saveCustomInstructionsButton = document.getElementById('save-custom-instructions-button');
if (saveCustomInstructionsButton) {
saveCustomInstructionsButton.addEventListener('click', async () => {
try {
const settings = {
custom_instructions: document.getElementById('ai-custom-instructions').value
};
await API.put('/dashboard/api/settings', settings);
Toast.success('Custom instructions saved successfully');
} catch (error) {
console.error('Error saving custom instructions:', error);
Toast.error('Failed to save custom instructions. Please try again.');
}
});
}
// Clear Custom Instructions button
const clearCustomInstructionsButton = document.getElementById('clear-custom-instructions-button');
if (clearCustomInstructionsButton) {
clearCustomInstructionsButton.addEventListener('click', async () => {
if (!confirm('Are you sure you want to clear custom instructions?')) return;
try {
const settings = {
custom_instructions: ""
};
await API.put('/dashboard/api/settings', settings);
// Clear UI
document.getElementById('ai-custom-instructions').value = '';
Toast.success('Custom instructions cleared');
} catch (error) {
console.error('Error clearing custom instructions:', error);
Toast.error('Failed to clear custom instructions. Please try again.');
}
});
}
// Add event listener for AI settings tab
const navAiSettings = document.getElementById('nav-ai-settings');
if (navAiSettings) {
navAiSettings.addEventListener('click', () => {
// Load AI settings if not already loaded
if (!aiSettingsLoaded) {
loadAiSettings();
}
});
}
}
// Initialize AI settings when the DOM is loaded
document.addEventListener('DOMContentLoaded', initAiSettings);

View File

@ -57,27 +57,11 @@ function initSidebar() {
if (href && href.startsWith('#')) {
event.preventDefault();
// Remove active class from all nav items
document.querySelectorAll('.nav-item').forEach(navItem => {
navItem.classList.remove('active');
});
// Get the section ID from the href (remove the # symbol)
const sectionId = href.substring(1);
// Add active class to clicked item
item.classList.add('active');
// Hide all sections
document.querySelectorAll('.dashboard-section').forEach(section => {
section.style.display = 'none';
});
// Show the target section
const sectionId = item.getAttribute('data-section');
if (sectionId) {
const section = document.getElementById(sectionId);
if (section) {
section.style.display = 'block';
}
}
// Show the section
showSection(sectionId);
// Close sidebar on mobile
if (window.innerWidth <= 768 && sidebar) {
@ -297,6 +281,39 @@ function initTabs() {
});
}
/**
* Show a specific section of the dashboard
* @param {string} sectionId - The ID of the section to show
*/
function showSection(sectionId) {
// Hide all sections
document.querySelectorAll('.dashboard-section').forEach(section => {
section.style.display = 'none';
});
// Remove active class from all nav items
document.querySelectorAll('.nav-item').forEach(item => {
item.classList.remove('active');
});
// Show the selected section
const section = document.getElementById(`${sectionId}-section`);
if (section) {
section.style.display = 'block';
}
// Add active class to the corresponding nav item
const navItem = document.querySelector(`.nav-item[data-section="${sectionId}-section"]`);
if (navItem) {
navItem.classList.add('active');
}
// Load AI settings if needed
if (sectionId === 'ai-settings' && typeof loadAiSettings === 'function' && typeof aiSettingsLoaded !== 'undefined' && !aiSettingsLoaded) {
loadAiSettings();
}
}
/**
* Initialize dropdown functionality
*/