enhance update form

Signed-off-by: mudler <mudler@localai.io>
This commit is contained in:
mudler
2025-03-17 16:13:03 +01:00
parent 3c3b5a774c
commit 29a8713427
5 changed files with 681 additions and 184 deletions

254
webui/public/css/wizard.css Normal file
View File

@@ -0,0 +1,254 @@
/* Agent Form Wizard Styles */
.agent-form-container {
display: flex;
gap: 2rem;
margin-bottom: 2rem;
}
/* Wizard Sidebar */
.wizard-sidebar {
width: 250px;
background: var(--surface);
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 1.5rem 0;
flex-shrink: 0;
}
.wizard-nav {
list-style: none;
padding: 0;
margin: 0;
}
.wizard-nav-item {
padding: 12px 20px;
cursor: pointer;
transition: all 0.2s ease;
border-left: 4px solid transparent;
display: flex;
align-items: center;
}
.wizard-nav-item i {
margin-right: 10px;
width: 20px;
text-align: center;
}
.wizard-nav-item:hover {
background: rgba(var(--primary-rgb), 0.1);
}
.wizard-nav-item.active {
background: rgba(var(--primary-rgb), 0.15);
border-left-color: var(--primary);
color: var(--primary);
font-weight: 600;
}
/* Form Content Area */
.form-content-area {
flex: 1;
padding: 1.5rem;
background: var(--surface);
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 1.5rem;
margin-bottom: 1.5rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid rgba(var(--border-rgb), 0.5);
color: var(--text);
}
.form-section {
display: none;
}
.form-section.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Improved input styles */
.mb-4 {
margin-bottom: 1.5rem;
}
.form-section label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: var(--text);
}
.form-section input[type="text"],
.form-section input[type="number"],
.form-section textarea,
.form-section select {
width: 100%;
padding: 10px 12px;
border-radius: 6px;
border: 1px solid rgba(var(--border-rgb), 0.8);
background-color: var(--input-bg);
color: var(--text);
font-size: 16px;
transition: border-color 0.2s ease;
}
.form-section textarea {
min-height: 120px;
resize: vertical;
}
.form-section input[type="text"]:focus,
.form-section input[type="number"]:focus,
.form-section textarea:focus,
.form-section select:focus {
border-color: var(--primary);
outline: none;
box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.2);
}
/* Button Styles */
.button-container {
margin: 1.5rem 0;
}
.action-btn {
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.action-btn i {
margin-right: 6px;
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.action-btn:active {
transform: translateY(0);
}
/* Navigation controls - improved layout */
.wizard-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 1px solid rgba(var(--border-rgb), 0.5);
}
.wizard-controls-left {
flex: 1;
text-align: left;
}
.wizard-controls-center {
flex: 2;
text-align: center;
}
.wizard-controls-right {
flex: 1;
text-align: right;
}
.nav-btn {
background: var(--surface);
color: var(--text);
border: 1px solid rgba(var(--border-rgb), 0.8);
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
}
.nav-btn i {
margin-right: 6px;
}
.nav-btn:last-child i {
margin-right: 0;
margin-left: 6px;
}
.nav-btn:hover {
background: rgba(var(--primary-rgb), 0.1);
}
.progress-indicator {
display: inline-block;
font-size: 0.9rem;
color: var(--text-muted);
font-weight: 500;
margin-top: 0.5rem;
}
.progress-dots {
display: flex;
justify-content: center;
margin-bottom: 8px;
gap: 6px;
}
.progress-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: rgba(var(--border-rgb), 0.4);
transition: all 0.2s ease;
}
.progress-dot.active {
background-color: var(--primary);
transform: scale(1.2);
}
/* Responsive adjustments */
@media (max-width: 768px) {
.wizard-controls {
flex-direction: column;
gap: 1rem;
}
.wizard-controls-left,
.wizard-controls-center,
.wizard-controls-right {
width: 100%;
text-align: center;
}
.progress-dots {
margin: 12px 0;
}
}

139
webui/public/js/wizard.js Normal file
View File

@@ -0,0 +1,139 @@
/**
* Agent Form Wizard - Navigation and UI functionality
*/
document.addEventListener('DOMContentLoaded', function() {
// Check if the wizard exists on the page
const wizardSidebar = document.querySelector('.wizard-sidebar');
if (!wizardSidebar) return;
// Get all sections and nav items
const navItems = document.querySelectorAll('.wizard-nav-item');
const sections = document.querySelectorAll('.form-section');
const prevButton = document.getElementById('prevSection');
const nextButton = document.getElementById('nextSection');
const currentStepLabelEl = document.getElementById('currentStepLabel');
const progressDotsContainer = document.getElementById('progressDots');
// Create progress dots
const totalSteps = sections.length;
// Create dots for each section
if (progressDotsContainer) {
for (let i = 0; i < totalSteps; i++) {
const dot = document.createElement('div');
dot.className = 'progress-dot';
dot.setAttribute('data-index', i);
dot.addEventListener('click', () => setActiveSection(i));
progressDotsContainer.appendChild(dot);
}
}
// Get all progress dots
const progressDots = document.querySelectorAll('.progress-dot');
// Track current active section
let currentSectionIndex = 0;
// Initialize
updateNavigation();
// Add click events to nav items
navItems.forEach((item, index) => {
item.addEventListener('click', () => {
setActiveSection(index);
});
});
// Add click events to prev/next buttons
if (prevButton) {
prevButton.addEventListener('click', () => {
if (currentSectionIndex > 0) {
setActiveSection(currentSectionIndex - 1);
}
});
}
if (nextButton) {
nextButton.addEventListener('click', () => {
if (currentSectionIndex < sections.length - 1) {
setActiveSection(currentSectionIndex + 1);
}
});
}
/**
* Set the active section and update navigation
*/
function setActiveSection(index) {
// Remove active class from all sections and nav items
sections.forEach(section => section.classList.remove('active'));
navItems.forEach(item => item.classList.remove('active'));
progressDots.forEach(dot => dot.classList.remove('active'));
// Add active class to current section, nav item, and dot
sections[index].classList.add('active');
navItems[index].classList.add('active');
if (progressDots[index]) {
progressDots[index].classList.add('active');
}
// Update current section index
currentSectionIndex = index;
// Update navigation state
updateNavigation();
// Scroll to top of section
sections[index].scrollIntoView({behavior: 'smooth', block: 'start'});
}
/**
* Update navigation buttons and progress
*/
function updateNavigation() {
// Update section label
if (currentStepLabelEl && navItems[currentSectionIndex]) {
// Extract text content without the icon
const navText = navItems[currentSectionIndex].textContent.trim();
currentStepLabelEl.textContent = navText;
}
// Update prev/next buttons
if (prevButton) {
prevButton.disabled = currentSectionIndex === 0;
prevButton.style.opacity = currentSectionIndex === 0 ? 0.5 : 1;
}
if (nextButton) {
nextButton.disabled = currentSectionIndex === sections.length - 1;
nextButton.style.opacity = currentSectionIndex === sections.length - 1 ? 0.5 : 1;
// Change text for last step
if (currentSectionIndex === sections.length - 2) {
nextButton.innerHTML = 'Finish <i class="fas fa-check"></i>';
} else {
nextButton.innerHTML = 'Next <i class="fas fa-arrow-right"></i>';
}
}
}
// Helper function to validate current section before proceeding
function validateCurrentSection() {
// Implement validation logic here based on the current section
// Return true if valid, false if not
return true;
}
// Add to initAgentFormCommon function if it exists
if (typeof window.initAgentFormCommon === 'function') {
const originalInit = window.initAgentFormCommon;
window.initAgentFormCommon = function(options) {
// Call the original initialization function
originalInit(options);
// Now initialize the wizard navigation
setActiveSection(0);
};
}
});

View File

@@ -3,6 +3,8 @@
<head>
<title>Create New Agent</title>
{{template "views/partials/header"}}
<script src="/public/js/wizard.js"></script>
<link rel="stylesheet" href="/public/css/wizard.css">
<script src="/public/js/agent-form.js"></script>
</head>
<body>

View File

@@ -1,118 +1,55 @@
<div class="mb-4">
<div class="agent-form-container">
<!-- Wizard Sidebar -->
<div class="wizard-sidebar">
<ul class="wizard-nav">
<li class="wizard-nav-item active" data-target="basic-section">
<i class="fas fa-info-circle"></i> Basic Information
</li>
<li class="wizard-nav-item" data-target="connectors-section">
<i class="fas fa-plug"></i> Connectors
</li>
<li class="wizard-nav-item" data-target="actions-section">
<i class="fas fa-bolt"></i> Actions
</li>
<li class="wizard-nav-item" data-target="mcp-section">
<i class="fas fa-server"></i> MCP Servers
</li>
<li class="wizard-nav-item" data-target="memory-section">
<i class="fas fa-memory"></i> Memory Settings
</li>
<li class="wizard-nav-item" data-target="model-section">
<i class="fas fa-robot"></i> Model Settings
</li>
<li class="wizard-nav-item" data-target="prompts-section">
<i class="fas fa-comment-alt"></i> Prompts & Goals
</li>
<li class="wizard-nav-item" data-target="advanced-section">
<i class="fas fa-cogs"></i> Advanced Settings
</li>
</ul>
</div>
<!-- Form Content Area -->
<div class="form-content-area">
<!-- Basic Information Section -->
<div class="form-section active" id="basic-section">
<h3 class="section-title">Basic Information</h3>
<div class="mb-4">
<label for="name">Name</label>
{{ if .Name }}
<input type="text" name="name" id="name" placeholder="Name" value="{{.Name}}" readonly >
{{ else }}
<input type="text" name="name" id="name" placeholder="Name">
{{ end }}
</div>
</div>
<div id="connectorsSection">
<!-- Connectors will be added here dynamically -->
</div>
<div class="mb-4">
<label for="identity_guidance">Identity Guidance</label>
<textarea name="identity_guidance" id="identity_guidance" placeholder="Identity Guidance"></textarea>
</div>
<div class="button-container">
<button type="button" id="addConnectorButton" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Connector
</button>
</div>
<div class="mb-4" id="action_box">
<!-- Actions will be added here dynamically -->
</div>
<div class="button-container">
<button id="action_button" type="button" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Action
</button>
</div>
<div id="mcpSection">
<!-- MCP servers will be added here dynamically -->
</div>
<div class="button-container">
<button type="button" id="addMCPButton" class="action-btn">
<i class="fas fa-plus-circle"></i> Add MCP Server
</button>
</div>
<div class="mb-4" id="dynamic_box">
<!-- Dynamic prompts will be added here dynamically -->
</div>
<div class="button-container">
<button id="dynamic_button" type="button" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Dynamic Prompt
</button>
</div>
<div class="mb-4">
<label for="hud" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="hud" id="hud">
<span class="checkmark"></span>
</span>
HUD
</label>
</div>
<div class="mb-4">
<label for="enable_kb" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="enable_kb" id="enable_kb">
<span class="checkmark"></span>
</span>
Enable Knowledge Base
</label>
</div>
<div class="mb-4">
<label for="enable_reasoning" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="enable_reasoning" id="enable_reasoning">
<span class="checkmark"></span>
</span>
Enable Reasoning
</label>
</div>
<div class="mb-4">
<label for="kb_results">Knowledge Base Results</label>
<input type="number" name="kb_results" id="kb_results" placeholder="3">
</div>
<div class="mb-4">
<label for="standalone_job" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="standalone_job" id="standalone_job">
<span class="checkmark"></span>
</span>
Standalone Job
</label>
</div>
<div class="mb-4">
<label for="initiate_conversations" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="initiate_conversations" id="initiate_conversations">
<span class="checkmark"></span>
</span>
Initiate Conversations
</label>
</div>
<div class="mb-4">
<label for="can_stop_itself" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="can_stop_itself" id="can_stop_itself">
<span class="checkmark"></span>
</span>
Can Stop Itself
</label>
</div>
<div class="mb-4">
<div class="mb-4">
<label for="random_identity" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="random_identity" id="random_identity">
@@ -120,9 +57,84 @@
</span>
Random Identity
</label>
</div>
</div>
<div class="mb-4">
<div class="mb-4">
<label for="hud" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="hud" id="hud">
<span class="checkmark"></span>
</span>
HUD
</label>
</div>
</div>
<!-- Connectors Section -->
<div class="form-section" id="connectors-section">
<h3 class="section-title">Connectors</h3>
<div id="connectorsSection">
<!-- Connectors will be added here dynamically -->
</div>
<div class="button-container">
<button type="button" id="addConnectorButton" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Connector
</button>
</div>
</div>
<!-- Actions Section -->
<div class="form-section" id="actions-section">
<h3 class="section-title">Actions</h3>
<div class="mb-4" id="action_box">
<!-- Actions will be added here dynamically -->
</div>
<div class="button-container">
<button id="action_button" type="button" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Action
</button>
</div>
</div>
<!-- MCP Servers Section -->
<div class="form-section" id="mcp-section">
<h3 class="section-title">MCP Servers</h3>
<div id="mcpSection">
<!-- MCP servers will be added here dynamically -->
</div>
<div class="button-container">
<button type="button" id="addMCPButton" class="action-btn">
<i class="fas fa-plus-circle"></i> Add MCP Server
</button>
</div>
</div>
<!-- Memory Settings Section -->
<div class="form-section" id="memory-section">
<h3 class="section-title">Memory Settings</h3>
<div class="mb-4">
<label for="enable_kb" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="enable_kb" id="enable_kb">
<span class="checkmark"></span>
</span>
Enable Knowledge Base
</label>
</div>
<div class="mb-4">
<label for="kb_results">Knowledge Base Results</label>
<input type="number" name="kb_results" id="kb_results" placeholder="3">
</div>
<div class="mb-4">
<label for="long_term_memory" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="long_term_memory" id="long_term_memory">
@@ -130,9 +142,9 @@
</span>
Long Term Memory
</label>
</div>
</div>
<div class="mb-4">
<div class="mb-4">
<label for="summary_long_term_memory" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="summary_long_term_memory" id="summary_long_term_memory">
@@ -140,34 +152,121 @@
</span>
Long Term Memory (Summarize!)
</label>
</div>
</div>
</div>
<div class="mb-4">
<label for="identity_guidance">Identity Guidance</label>
<textarea name="identity_guidance" id="identity_guidance" placeholder="Identity Guidance"></textarea>
</div>
<!-- Model Settings Section -->
<div class="form-section" id="model-section">
<h3 class="section-title">Model Settings</h3>
<div class="mb-4">
<label for="periodic_runs">Periodic Runs</label>
<input type="text" name="periodic_runs" id="periodic_runs" placeholder="Periodic Runs">
</div>
<div class="mb-4">
<div class="mb-4">
<label for="model">Model </label>
<input type="text" name="model" id="model" placeholder="Model name">
</div>
</div>
<div class="mb-4">
<div class="mb-4">
<label for="multimodal_model">Multimodal Model </label>
<input type="text" name="multimodal_model" id="multimodal_model" placeholder="Model name">
</div>
</div>
<div class="mb-4">
<label for="permanent_goal">Permanent Goal</label>
<textarea name="permanent_goal" id="permanent_goal" placeholder="Permanent goal"></textarea>
</div>
<div class="mb-4">
<label for="enable_reasoning" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="enable_reasoning" id="enable_reasoning">
<span class="checkmark"></span>
</span>
Enable Reasoning
</label>
</div>
</div>
<div class="mb-4">
<!-- Prompts & Goals Section -->
<div class="form-section" id="prompts-section">
<h3 class="section-title">Prompts & Goals</h3>
<div class="mb-4" id="dynamic_box">
<!-- Dynamic prompts will be added here dynamically -->
</div>
<div class="button-container">
<button id="dynamic_button" type="button" class="action-btn">
<i class="fas fa-plus-circle"></i> Add Dynamic Prompt
</button>
</div>
<div class="mb-4">
<label for="system_prompt">System Prompt</label>
<textarea name="system_prompt" id="system_prompt" placeholder="System prompt"></textarea>
</div>
<div class="mb-4">
<label for="permanent_goal">Permanent Goal</label>
<textarea name="permanent_goal" id="permanent_goal" placeholder="Permanent goal"></textarea>
</div>
</div>
<!-- Advanced Settings Section -->
<div class="form-section" id="advanced-section">
<h3 class="section-title">Advanced Settings</h3>
<div class="mb-4">
<label for="standalone_job" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="standalone_job" id="standalone_job">
<span class="checkmark"></span>
</span>
Standalone Job
</label>
</div>
<div class="mb-4">
<label for="initiate_conversations" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="initiate_conversations" id="initiate_conversations">
<span class="checkmark"></span>
</span>
Initiate Conversations
</label>
</div>
<div class="mb-4">
<label for="can_stop_itself" class="checkbox-label">
<span class="checkbox-custom">
<input type="checkbox" name="can_stop_itself" id="can_stop_itself">
<span class="checkmark"></span>
</span>
Can Stop Itself
</label>
</div>
<div class="mb-4">
<label for="periodic_runs">Periodic Runs</label>
<input type="text" name="periodic_runs" id="periodic_runs" placeholder="Periodic Runs">
</div>
</div>
</div>
</div>
<!-- Add navigation controls at the bottom -->
<div class="wizard-controls">
<div class="wizard-controls-left">
<button type="button" id="prevSection" class="nav-btn">
<i class="fas fa-arrow-left"></i> Previous
</button>
</div>
<div class="wizard-controls-center">
<div class="progress-dots" id="progressDots">
<!-- Dots will be added dynamically via JS -->
</div>
<div class="progress-indicator">
<span id="currentStepLabel">Basic Information</span>
</div>
</div>
<div class="wizard-controls-right">
<button type="button" id="nextSection" class="nav-btn">
Next <i class="fas fa-arrow-right"></i>
</button>
</div>
</div>

View File

@@ -3,6 +3,8 @@
<head>
<title>Agent settings {{.Name}}</title>
{{template "views/partials/header"}}
<script src="/public/js/wizard.js"></script>
<link rel="stylesheet" href="/public/css/wizard.css">
<script src="/public/js/agent-form.js"></script>
</head>
<body>
@@ -19,6 +21,21 @@
</header>
<div class="max-w-4xl mx-auto">
<!-- Agent Configuration Form Section -->
<div class="section-box">
<h2>Edit Agent Configuration</h2>
<form id="edit-agent-form">
<input type="hidden" name="name" id="name" value="{{.Name}}">
{{template "views/partials/agent-form" .}}
<button type="submit" id="update-button" class="action-btn" data-original-text="<i class='fas fa-save'></i> Update Agent">
<i class="fas fa-save"></i> Update Agent
</button>
</form>
</div>
<div class="section-box">
<h2>Agent Control</h2>
<div class="button-container">
@@ -35,20 +52,6 @@
</div>
</div>
<!-- Agent Configuration Form Section -->
<div class="section-box">
<h2>Edit Agent Configuration</h2>
<form id="edit-agent-form">
<input type="hidden" name="name" id="name" value="{{.Name}}">
{{template "views/partials/agent-form" .}}
<button type="submit" id="update-button" class="action-btn" data-original-text="<i class='fas fa-save'></i> Update Agent">
<i class="fas fa-save"></i> Update Agent
</button>
</form>
</div>
<div class="section-box">
<h2>Export Data</h2>
<p class="mb-4">Export your agent configuration for backup or transfer.</p>