feat(ui): Add React based UI for the vibes at /app

This adds a completely separate frontend based on React because I
found that code gen works better with React once the application gets
bigger. In particular it was getting very hard to move past add
connectors and actions.

The idea is to replace the standard UI with this once it has been
tested. But for now it is available at /app in addition to the
original at /

Signed-off-by: Richard Palethorpe <io@richiejp.com>
This commit is contained in:
Richard Palethorpe
2025-03-24 14:36:18 +00:00
parent 438a65caf6
commit 71e66c651c
61 changed files with 6452 additions and 2 deletions

198
webui/react-ui/src/utils/api.js vendored Normal file
View File

@@ -0,0 +1,198 @@
/**
* API utility for communicating with the Go backend
*/
import { API_CONFIG } from './config';
// Helper function for handling API responses
const handleResponse = async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.error || `API error: ${response.status}`);
}
// Check if response is JSON
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
}
return response.text();
};
// Helper function to build a full URL
const buildUrl = (endpoint) => {
return `${API_CONFIG.baseUrl}${endpoint.startsWith('/') ? endpoint.substring(1) : endpoint}`;
};
// Agent-related API calls
export const agentApi = {
// Get list of all agents
getAgents: async () => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.agents), {
headers: API_CONFIG.headers
});
return handleResponse(response);
},
// Get a specific agent's configuration
getAgentConfig: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.agentConfig(name)), {
headers: API_CONFIG.headers
});
return handleResponse(response);
},
// Create a new agent
createAgent: async (config) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.createAgent), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(config),
});
return handleResponse(response);
},
// Update an existing agent's configuration
updateAgentConfig: async (name, config) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.agentConfig(name)), {
method: 'PUT',
headers: API_CONFIG.headers,
body: JSON.stringify(config),
});
return handleResponse(response);
},
// Delete an agent
deleteAgent: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.deleteAgent(name)), {
method: 'DELETE',
headers: API_CONFIG.headers,
});
return handleResponse(response);
},
// Pause an agent
pauseAgent: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.pauseAgent(name)), {
method: 'PUT',
headers: API_CONFIG.headers,
body: JSON.stringify({}),
});
return handleResponse(response);
},
// Start an agent
startAgent: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.startAgent(name)), {
method: 'PUT',
headers: API_CONFIG.headers,
body: JSON.stringify({}),
});
return handleResponse(response);
},
// Export agent configuration
exportAgentConfig: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.exportAgent(name)), {
headers: API_CONFIG.headers
});
return handleResponse(response);
},
// Import agent configuration
importAgentConfig: async (configData) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.importAgent), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(configData),
});
return handleResponse(response);
},
// Generate group profiles
generateGroupProfiles: async (data) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.generateGroupProfiles), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(data),
});
return handleResponse(response);
},
// Create a group of agents
createGroup: async (data) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.createGroup), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(data),
});
return handleResponse(response);
},
};
// Chat-related API calls
export const chatApi = {
// Send a chat message to an agent
sendMessage: async (name, message) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.chat(name)), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify({ message }),
});
return handleResponse(response);
},
// Send a notification to an agent
sendNotification: async (name, message) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.notify(name)), {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ message }),
});
return handleResponse(response);
},
// Get responses from an agent
getResponses: async (data) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.responses), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(data),
});
return handleResponse(response);
},
};
// Action-related API calls
export const actionApi = {
// List available actions
listActions: async () => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.listActions), {
headers: API_CONFIG.headers
});
return handleResponse(response);
},
// Execute an action for an agent
executeAction: async (name, actionData) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.executeAction(name)), {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(actionData),
});
return handleResponse(response);
},
};
// Status-related API calls
export const statusApi = {
// Get agent status history
getStatusHistory: async (name) => {
const response = await fetch(buildUrl(API_CONFIG.endpoints.status(name)), {
headers: API_CONFIG.headers
});
return handleResponse(response);
},
};

49
webui/react-ui/src/utils/config.js vendored Normal file
View File

@@ -0,0 +1,49 @@
/**
* Application configuration
*/
// Get the base URL from Vite's environment variables or default to '/app/'
export const BASE_URL = import.meta.env.BASE_URL || '/app/';
// API endpoints configuration
export const API_CONFIG = {
// Base URL for API requests
baseUrl: '/', // API endpoints are at the root, not under /app/
// Default headers for API requests
headers: {
'Content-Type': 'application/json',
},
// Endpoints
endpoints: {
// Agent endpoints
agents: '/api/agents',
agentConfig: (name) => `/api/agent/${name}/config`,
createAgent: '/create',
deleteAgent: (name) => `/delete/${name}`,
pauseAgent: (name) => `/pause/${name}`,
startAgent: (name) => `/start/${name}`,
exportAgent: (name) => `/settings/export/${name}`,
importAgent: '/settings/import',
// Group endpoints
generateGroupProfiles: '/api/agent/group/generateProfiles',
createGroup: '/api/agent/group/create',
// Chat endpoints
chat: (name) => `/chat/${name}`,
notify: (name) => `/notify/${name}`,
responses: '/v1/responses',
// SSE endpoint
sse: (name) => `/sse/${name}`,
// Action endpoints
listActions: '/actions',
executeAction: (name) => `/action/${name}/run`,
// Status endpoint
status: (name) => `/status/${name}`,
}
};