@@ -97,9 +97,9 @@ func statusJSONMessage(c *fiber.Ctx, message string) error {
|
|||||||
|
|
||||||
func (a *App) Pause(pool *state.AgentPool) func(c *fiber.Ctx) error {
|
func (a *App) Pause(pool *state.AgentPool) func(c *fiber.Ctx) error {
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
xlog.Info("Pausing agent", c.Params("name"))
|
|
||||||
agent := pool.GetAgent(c.Params("name"))
|
agent := pool.GetAgent(c.Params("name"))
|
||||||
if agent != nil {
|
if agent != nil {
|
||||||
|
xlog.Info("Pausing agent", "name", c.Params("name"))
|
||||||
agent.Pause()
|
agent.Pause()
|
||||||
}
|
}
|
||||||
return statusJSONMessage(c, "ok")
|
return statusJSONMessage(c, "ok")
|
||||||
@@ -110,6 +110,7 @@ func (a *App) Start(pool *state.AgentPool) func(c *fiber.Ctx) error {
|
|||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
agent := pool.GetAgent(c.Params("name"))
|
agent := pool.GetAgent(c.Params("name"))
|
||||||
if agent != nil {
|
if agent != nil {
|
||||||
|
xlog.Info("Starting agent", "name", c.Params("name"))
|
||||||
agent.Resume()
|
agent.Resume()
|
||||||
}
|
}
|
||||||
return statusJSONMessage(c, "ok")
|
return statusJSONMessage(c, "ok")
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func (app *App) registerRoutes(pool *state.AgentPool, webapp *fiber.App) {
|
|||||||
"Agents": pool.List(),
|
"Agents": pool.List(),
|
||||||
"AgentCount": len(pool.List()),
|
"AgentCount": len(pool.List()),
|
||||||
"Actions": len(services.AvailableActions),
|
"Actions": len(services.AvailableActions),
|
||||||
|
"Connectors": len(services.AvailableConnectors),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -93,9 +94,17 @@ func (app *App) registerRoutes(pool *state.AgentPool, webapp *fiber.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
webapp.Get("/settings/:name", func(c *fiber.Ctx) error {
|
webapp.Get("/settings/:name", func(c *fiber.Ctx) error {
|
||||||
|
status := false
|
||||||
|
for _, a := range pool.List() {
|
||||||
|
if a == c.Params("name") {
|
||||||
|
status = !pool.GetAgent(a).Paused()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c.Render("views/settings", fiber.Map{
|
return c.Render("views/settings", fiber.Map{
|
||||||
// "Character": agent.Character,
|
// "Character": agent.Character,
|
||||||
"Name": c.Params("name"),
|
"Name": c.Params("name"),
|
||||||
|
"Status": status,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
webapp.Post("/settings/import", app.ImportAgent(pool))
|
webapp.Post("/settings/import", app.ImportAgent(pool))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<div class="container mx-auto">
|
<div class="container mx-auto">
|
||||||
<header class="text-center mb-8">
|
<header class="text-center mb-8">
|
||||||
<h1 class="text-4xl md:text-6xl font-bold">Smart Agent List</h1>
|
<h1 class="text-4xl md:text-6xl font-bold">Agent List</h1>
|
||||||
<p class="mt-4 text-gray-400">Manage and interact with your AI agents</p>
|
<p class="mt-4 text-gray-400">Manage and interact with your AI agents</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -55,7 +55,6 @@
|
|||||||
<button id="import-button" type="submit" class="action-btn">
|
<button id="import-button" type="submit" class="action-btn">
|
||||||
<i class="fas fa-cloud-upload-alt"></i> Import Agent
|
<i class="fas fa-cloud-upload-alt"></i> Import Agent
|
||||||
</button>
|
</button>
|
||||||
<progress id='progress' value='0' max='100' class="ml-4"></progress>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,16 +85,15 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-3 gap-2 w-full">
|
<div class="grid grid-cols-2 gap-2 w-full">
|
||||||
<button class="action-btn start-btn col-span-1"
|
<button class="action-btn toggle-btn col-span-1"
|
||||||
hx-put="/start/{{.}}" hx-swap="none" hx-ext="json-enc"
|
data-agent="{{.}}"
|
||||||
data-action="start" data-agent="{{.}}">
|
data-active="{{ if eq (index $status .) true }}true{{ else }}false{{ end }}">
|
||||||
<i class="fas fa-play"></i>
|
{{ if eq (index $status .) true }}
|
||||||
</button>
|
<i class="fas fa-pause"></i> Pause
|
||||||
<button class="action-btn pause-btn col-span-1"
|
{{ else }}
|
||||||
hx-put="/pause/{{.}}" hx-swap="none" hx-ext="json-enc"
|
<i class="fas fa-play"></i> Start
|
||||||
data-action="pause" data-agent="{{.}}">
|
{{ end }}
|
||||||
<i class="fas fa-pause"></i>
|
|
||||||
</button>
|
</button>
|
||||||
<a href="/settings/{{.}}" class="action-btn col-span-1 flex items-center justify-center"
|
<a href="/settings/{{.}}" class="action-btn col-span-1 flex items-center justify-center"
|
||||||
style="background: linear-gradient(135deg, #2a2a2a, #3a3a3a);">
|
style="background: linear-gradient(135deg, #2a2a2a, #3a3a3a);">
|
||||||
@@ -179,17 +177,23 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listeners for Start and Pause buttons
|
// Handle toggle buttons - using pure JavaScript
|
||||||
document.querySelectorAll('.action-btn[data-action]').forEach(button => {
|
document.querySelectorAll('.toggle-btn').forEach(button => {
|
||||||
button.addEventListener('htmx:beforeRequest', function() {
|
button.addEventListener('click', function() {
|
||||||
this.style.animation = 'pulse 0.5s';
|
|
||||||
});
|
|
||||||
|
|
||||||
button.addEventListener('htmx:afterRequest', function(event) {
|
|
||||||
const xhr = event.detail.xhr;
|
|
||||||
const action = this.getAttribute('data-action');
|
|
||||||
const agent = this.getAttribute('data-agent');
|
const agent = this.getAttribute('data-agent');
|
||||||
|
const isActive = this.getAttribute('data-active') === 'true';
|
||||||
|
const endpoint = isActive ? `/pause/${agent}` : `/start/${agent}`;
|
||||||
|
|
||||||
|
// Add animation
|
||||||
|
this.style.animation = 'pulse 0.5s';
|
||||||
|
|
||||||
|
// Create a new XMLHttpRequest
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('PUT', endpoint);
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
xhr.onload = () => {
|
||||||
|
// Clear animation
|
||||||
this.style.animation = '';
|
this.style.animation = '';
|
||||||
|
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
@@ -197,11 +201,23 @@
|
|||||||
const response = JSON.parse(xhr.responseText);
|
const response = JSON.parse(xhr.responseText);
|
||||||
|
|
||||||
if (response.status === "ok") {
|
if (response.status === "ok") {
|
||||||
// Show success toast
|
// Toggle the button state
|
||||||
showToast(`Agent "${agent}" ${action === 'start' ? 'started' : 'paused'} successfully`, 'success');
|
const newState = !isActive;
|
||||||
|
this.setAttribute('data-active', newState ? 'true' : 'false');
|
||||||
|
|
||||||
// Update the status cell if needed
|
// Update button text and icon
|
||||||
updateAgentStatus(agent, action === 'start' ? true : false);
|
if (newState) {
|
||||||
|
this.innerHTML = '<i class="fas fa-pause"></i> Pause';
|
||||||
|
} else {
|
||||||
|
this.innerHTML = '<i class="fas fa-play"></i> Start';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show success toast
|
||||||
|
const action = isActive ? 'pause' : 'start';
|
||||||
|
showToast(`Agent "${agent}" ${action}ed successfully`, 'success');
|
||||||
|
|
||||||
|
// Update the status badge
|
||||||
|
updateAgentStatus(agent, newState);
|
||||||
} else if (response.error) {
|
} else if (response.error) {
|
||||||
// Show error toast
|
// Show error toast
|
||||||
showToast(`Error: ${response.error}`, 'error');
|
showToast(`Error: ${response.error}`, 'error');
|
||||||
@@ -209,11 +225,23 @@
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Handle parsing error
|
// Handle parsing error
|
||||||
showToast("Invalid response format", 'error');
|
showToast("Invalid response format", 'error');
|
||||||
|
console.error("Error parsing response:", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle HTTP error
|
// Handle HTTP error
|
||||||
showToast(`Server error: ${xhr.status}`, 'error');
|
showToast(`Server error: ${xhr.status}`, 'error');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = () => {
|
||||||
|
// Clear animation
|
||||||
|
this.style.animation = '';
|
||||||
|
showToast("Network error occurred", 'error');
|
||||||
|
console.error("Network error occurred");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
xhr.send(JSON.stringify({}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
<img src="/public/logo_1.png" width="250" alt="Company Logo">
|
<img src="/public/logo_1.png" width="250" alt="Company Logo">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="dashboard-title">SMART ASSISTANT DASHBOARD</h1>
|
<h1 class="dashboard-title">LocalAgent</h1>
|
||||||
|
|
||||||
<!-- Simple stats display -->
|
<!-- Simple stats display -->
|
||||||
<div class="dashboard-stats">
|
<div class="dashboard-stats">
|
||||||
@@ -148,6 +148,10 @@
|
|||||||
<div class="stat-count">{{.Actions}}</div>
|
<div class="stat-count">{{.Actions}}</div>
|
||||||
<div class="stat-label">Available Actions</div>
|
<div class="stat-label">Available Actions</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-count">{{.Connectors}}</div>
|
||||||
|
<div class="stat-label">Available Connectors</div>
|
||||||
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<div class="stat-count">{{ .AgentCount }}</div>
|
<div class="stat-count">{{ .AgentCount }}</div>
|
||||||
<div class="stat-label">Agents</div>
|
<div class="stat-label">Agents</div>
|
||||||
|
|||||||
@@ -22,20 +22,14 @@
|
|||||||
<h2>Agent Control</h2>
|
<h2>Agent Control</h2>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<button
|
<button
|
||||||
class="action-btn start-btn"
|
class="action-btn toggle-btn"
|
||||||
hx-put="/start/{{.Name}}"
|
data-agent="{{.Name}}"
|
||||||
hx-swap="none"
|
data-active="{{.Status}}">
|
||||||
data-action="start"
|
{{if .Status}}
|
||||||
data-agent="{{.Name}}">
|
|
||||||
<i class="fas fa-play"></i> Start Agent
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="action-btn pause-btn"
|
|
||||||
hx-put="/pause/{{.Name}}"
|
|
||||||
hx-swap="none"
|
|
||||||
data-action="pause"
|
|
||||||
data-agent="{{.Name}}">
|
|
||||||
<i class="fas fa-pause"></i> Pause Agent
|
<i class="fas fa-pause"></i> Pause Agent
|
||||||
|
{{else}}
|
||||||
|
<i class="fas fa-play"></i> Start Agent
|
||||||
|
{{end}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -73,19 +67,86 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Add event listeners for action buttons (Start, Pause)
|
// Add event listener for delete button
|
||||||
document.querySelectorAll('[data-action]').forEach(button => {
|
document.querySelectorAll('[data-action="delete"]').forEach(button => {
|
||||||
button.addEventListener('htmx:afterRequest', function(event) {
|
button.addEventListener('htmx:afterRequest', function(event) {
|
||||||
handleActionResponse(event, this);
|
handleActionResponse(event, this);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle toggle button
|
||||||
|
const toggleButton = document.querySelector('.toggle-btn');
|
||||||
|
if (toggleButton) {
|
||||||
|
toggleButton.addEventListener('click', function() {
|
||||||
|
const agent = this.getAttribute('data-agent');
|
||||||
|
const isActive = this.getAttribute('data-active') === "true";
|
||||||
|
const endpoint = isActive ? `/pause/${agent}` : `/start/${agent}`;
|
||||||
|
|
||||||
|
// Add animation
|
||||||
|
this.style.animation = 'pulse 0.5s';
|
||||||
|
|
||||||
|
// Create a new XMLHttpRequest
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('PUT', endpoint);
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
xhr.onload = () => {
|
||||||
|
// Clear animation
|
||||||
|
this.style.animation = '';
|
||||||
|
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
try {
|
||||||
|
const response = JSON.parse(xhr.responseText);
|
||||||
|
|
||||||
|
if (response.status === "ok") {
|
||||||
|
// Toggle the button state
|
||||||
|
const newState = !isActive;
|
||||||
|
this.setAttribute('data-active', newState.toString());
|
||||||
|
|
||||||
|
// Update button text and icon
|
||||||
|
if (newState) {
|
||||||
|
this.innerHTML = '<i class="fas fa-pause"></i> Pause Agent';
|
||||||
|
} else {
|
||||||
|
this.innerHTML = '<i class="fas fa-play"></i> Start Agent';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show success toast
|
||||||
|
const action = isActive ? 'pause' : 'start';
|
||||||
|
showToast(`Agent "${agent}" ${action}ed successfully`, 'success');
|
||||||
|
|
||||||
|
} else if (response.error) {
|
||||||
|
// Show error toast
|
||||||
|
showToast(`Error: ${response.error}`, 'error');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Handle parsing error
|
||||||
|
showToast("Invalid response format", 'error');
|
||||||
|
console.error("Error parsing response:", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle HTTP error
|
||||||
|
showToast(`Server error: ${xhr.status}`, 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = () => {
|
||||||
|
// Clear animation
|
||||||
|
this.style.animation = '';
|
||||||
|
showToast("Network error occurred", 'error');
|
||||||
|
console.error("Network error occurred");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
xhr.send(JSON.stringify({}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Set current date for timestamp
|
// Set current date for timestamp
|
||||||
const now = new Date();
|
const now = new Date("2025-03-04T20:52:02Z");
|
||||||
document.getElementById('current-date').textContent = now.toISOString().split('T')[0];
|
document.getElementById('current-date').textContent = now.toISOString().split('T')[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to handle API responses for all actions
|
// Function to handle API responses for delete action
|
||||||
function handleActionResponse(event, button) {
|
function handleActionResponse(event, button) {
|
||||||
const xhr = event.detail.xhr;
|
const xhr = event.detail.xhr;
|
||||||
const action = button.getAttribute('data-action');
|
const action = button.getAttribute('data-action');
|
||||||
@@ -100,12 +161,6 @@
|
|||||||
let message = "";
|
let message = "";
|
||||||
|
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case 'start':
|
|
||||||
message = `Agent "${agent}" started successfully`;
|
|
||||||
break;
|
|
||||||
case 'pause':
|
|
||||||
message = `Agent "${agent}" paused successfully`;
|
|
||||||
break;
|
|
||||||
case 'delete':
|
case 'delete':
|
||||||
message = `Agent "${agent}" deleted successfully`;
|
message = `Agent "${agent}" deleted successfully`;
|
||||||
// Redirect to agent list page after short delay for delete
|
// Redirect to agent list page after short delay for delete
|
||||||
|
|||||||
Reference in New Issue
Block a user