diff --git a/webui/react-ui/src/App.css b/webui/react-ui/src/App.css
index 98f6b46..622c220 100644
--- a/webui/react-ui/src/App.css
+++ b/webui/react-ui/src/App.css
@@ -1933,3 +1933,124 @@ select.form-control {
background-color: var(--light-bg);
color: var(--primary);
}
+
+.import-agent-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+.import-agent-content {
+ margin-top: 20px;
+}
+
+.file-dropzone {
+ border: 2px dashed var(--border);
+ border-radius: 8px;
+ padding: 40px;
+ text-align: center;
+ margin-bottom: 20px;
+ transition: all 0.3s ease;
+ background: rgba(30, 30, 30, 0.7);
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+}
+
+.file-dropzone:hover {
+ border-color: var(--primary);
+ background: rgba(30, 30, 30, 0.8);
+}
+
+.dropzone-content {
+ color: var(--text);
+}
+
+.dropzone-content i {
+ font-size: 48px;
+ color: var(--primary);
+ margin-bottom: 20px;
+}
+
+.dropzone-content h2 {
+ margin-bottom: 10px;
+ color: var(--primary);
+ text-shadow: var(--neon-glow);
+}
+
+.dropzone-content p {
+ margin: 10px 0;
+ color: var(--text);
+}
+
+.file-button {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 24px;
+ background: var(--primary);
+ color: var(--dark-bg);
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+}
+
+.file-button:hover {
+ background: rgba(0, 255, 149, 0.8);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.file-button i {
+ font-size: 16px;
+}
+
+.selected-file-info {
+ margin-top: 20px;
+ padding: 20px;
+ background: rgba(30, 30, 30, 0.7);
+ border-radius: 8px;
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
+}
+
+.selected-file-info p {
+ margin-bottom: 15px;
+ color: var(--text);
+}
+
+.import-button {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 24px;
+ background: var(--primary);
+ color: var(--dark-bg);
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: 16px;
+}
+
+.import-button:hover:not(:disabled) {
+ background: rgba(0, 255, 149, 0.8);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.import-button:disabled {
+ background: rgba(0, 255, 149, 0.3);
+ cursor: not-allowed;
+}
+
+.import-button i {
+ font-size: 16px;
+}
+
+.import-button .fa-spinner {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
diff --git a/webui/react-ui/src/pages/AgentsList.jsx b/webui/react-ui/src/pages/AgentsList.jsx
index 5189282..6472c71 100644
--- a/webui/react-ui/src/pages/AgentsList.jsx
+++ b/webui/react-ui/src/pages/AgentsList.jsx
@@ -112,9 +112,14 @@ function AgentsList() {
{agents.length > 0 ? (
diff --git a/webui/react-ui/src/pages/Home.jsx b/webui/react-ui/src/pages/Home.jsx
index 81440b0..3eaf87a 100644
--- a/webui/react-ui/src/pages/Home.jsx
+++ b/webui/react-ui/src/pages/Home.jsx
@@ -99,9 +99,18 @@ function Home() {
Create Group
-
Create agent groups for collaborative intelligence.
+
Create a group of agents with shared configurations and behaviors.
+
+ {/* Card for Import Agent */}
+
+
+
Import Agent
+
Import an existing agent configuration from a file.
+
+
+
{stats.agents.length > 0 && (
diff --git a/webui/react-ui/src/pages/ImportAgent.jsx b/webui/react-ui/src/pages/ImportAgent.jsx
new file mode 100644
index 0000000..ea87b18
--- /dev/null
+++ b/webui/react-ui/src/pages/ImportAgent.jsx
@@ -0,0 +1,102 @@
+import { useState } from 'react';
+import { useNavigate, useOutletContext } from 'react-router-dom';
+import { agentApi } from '../utils/api';
+
+function ImportAgent() {
+ const navigate = useNavigate();
+ const { showToast } = useOutletContext();
+ const [file, setFile] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const handleFileChange = (e) => {
+ const selectedFile = e.target.files[0];
+ if (selectedFile) {
+ setFile(selectedFile);
+ }
+ };
+
+ const handleImport = async () => {
+ if (!file) {
+ showToast('Please select a file to import', 'error');
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const formData = new FormData();
+ formData.append('file', file);
+
+ await agentApi.importAgentConfig(formData);
+ showToast('Agent imported successfully', 'success');
+ navigate('/agents');
+ } catch (err) {
+ showToast(`Error importing agent: ${err.message}`, 'error');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
{
+ e.preventDefault();
+ const droppedFile = e.dataTransfer.files[0];
+ if (droppedFile) {
+ setFile(droppedFile);
+ }
+ }}
+ onDragOver={(e) => e.preventDefault()}>
+
+
+
Drop your agent file here
+
or
+
+
+
+
+
+ {file && (
+
+
Selected file: {file.name}
+
+
+ )}
+
+
+
+ );
+}
+
+export default ImportAgent;
diff --git a/webui/react-ui/src/router.jsx b/webui/react-ui/src/router.jsx
index c0f5a74..f7d5c34 100644
--- a/webui/react-ui/src/router.jsx
+++ b/webui/react-ui/src/router.jsx
@@ -8,6 +8,7 @@ import Chat from './pages/Chat';
import ActionsPlayground from './pages/ActionsPlayground';
import GroupCreate from './pages/GroupCreate';
import AgentStatus from './pages/AgentStatus';
+import ImportAgent from './pages/ImportAgent';
// Get the base URL from Vite's environment variables or default to '/app/'
const BASE_URL = import.meta.env.BASE_URL || '/app';
@@ -46,6 +47,10 @@ export const router = createBrowserRouter([
path: 'group-create',
element:
},
+ {
+ path: 'import',
+ element:
+ },
{
path: 'status/:name',
element:
diff --git a/webui/react-ui/src/utils/api.js b/webui/react-ui/src/utils/api.js
index 36fd7eb..b4f0444 100644
--- a/webui/react-ui/src/utils/api.js
+++ b/webui/react-ui/src/utils/api.js
@@ -142,11 +142,11 @@ export const agentApi = {
},
// Import agent configuration
- importAgentConfig: async (configData) => {
+ importAgent: async (formData) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.importAgent), {
method: 'POST',
headers: API_CONFIG.headers,
- body: JSON.stringify(configData),
+ body: formData,
});
return handleResponse(response);
},