enhance_swarm 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/CLAUDE.md +164 -0
- data/.claude/MCP.md +117 -0
- data/.claude/PERSONAS.md +114 -0
- data/.claude/RULES.md +221 -0
- data/.enhance_swarm/logs/general_output.log +0 -404
- data/.enhance_swarm.yml +33 -0
- data/CHANGELOG.md +71 -0
- data/README.md +128 -3
- data/lib/enhance_swarm/agent_spawner.rb +205 -12
- data/lib/enhance_swarm/cli.rb +129 -1
- data/lib/enhance_swarm/task_coordinator.rb +363 -86
- data/lib/enhance_swarm/version.rb +1 -1
- metadata +13 -97
- data/PRODUCTION_TEST_LOG.md +0 -502
- data/debug_agent_spawner.rb +0 -99
- data/debug_cli_spawn.rb +0 -95
- data/debug_fixes.rb +0 -209
- data/debug_script_execution.rb +0 -124
- data/debug_session_issue.rb +0 -87
- data/debug_spawn.rb +0 -113
- data/debug_spawn_step_by_step.rb +0 -190
- data/debug_worktree.rb +0 -77
- data/enhance_swarm-0.1.1.gem +0 -0
- data/enhance_swarm-1.0.0.gem +0 -0
- data/final_validation_test.rb +0 -199
- data/setup.sh +0 -86
- data/test_blog_app/.enhance_swarm/archives/session_1751187575_e119ea73_20250629_105935.json +0 -16
- data/test_blog_app/.enhance_swarm/archives/session_1751187637_7fda97dd_20250629_110037.json +0 -32
- data/test_blog_app/.enhance_swarm/archives/session_1751190527_4c99147e_20250629_114847.json +0 -32
- data/test_blog_app/.enhance_swarm/archives/session_1751190541_8dc83406_20250629_114901.json +0 -16
- data/test_blog_app/.ruby-version +0 -1
- data/test_blog_app/Gemfile +0 -18
- data/test_blog_app/Gemfile.lock +0 -206
- data/test_blog_app/README.md +0 -24
- data/test_blog_app/Rakefile +0 -6
- data/test_blog_app/app/assets/images/.keep +0 -0
- data/test_blog_app/app/assets/stylesheets/application.css +0 -10
- data/test_blog_app/app/controllers/application_controller.rb +0 -4
- data/test_blog_app/app/controllers/concerns/.keep +0 -0
- data/test_blog_app/app/helpers/application_helper.rb +0 -2
- data/test_blog_app/app/models/application_record.rb +0 -3
- data/test_blog_app/app/models/concerns/.keep +0 -0
- data/test_blog_app/app/views/layouts/application.html.erb +0 -27
- data/test_blog_app/app/views/pwa/manifest.json.erb +0 -22
- data/test_blog_app/app/views/pwa/service-worker.js +0 -26
- data/test_blog_app/bin/dev +0 -2
- data/test_blog_app/bin/rails +0 -4
- data/test_blog_app/bin/rake +0 -4
- data/test_blog_app/bin/setup +0 -34
- data/test_blog_app/config/application.rb +0 -42
- data/test_blog_app/config/boot.rb +0 -3
- data/test_blog_app/config/credentials.yml.enc +0 -1
- data/test_blog_app/config/database.yml +0 -32
- data/test_blog_app/config/environment.rb +0 -5
- data/test_blog_app/config/environments/development.rb +0 -51
- data/test_blog_app/config/environments/production.rb +0 -67
- data/test_blog_app/config/environments/test.rb +0 -42
- data/test_blog_app/config/initializers/assets.rb +0 -7
- data/test_blog_app/config/initializers/content_security_policy.rb +0 -25
- data/test_blog_app/config/initializers/filter_parameter_logging.rb +0 -8
- data/test_blog_app/config/initializers/inflections.rb +0 -16
- data/test_blog_app/config/locales/en.yml +0 -31
- data/test_blog_app/config/master.key +0 -1
- data/test_blog_app/config/puma.rb +0 -38
- data/test_blog_app/config/routes.rb +0 -14
- data/test_blog_app/config.ru +0 -6
- data/test_blog_app/db/seeds.rb +0 -9
- data/test_blog_app/lib/tasks/.keep +0 -0
- data/test_blog_app/log/.keep +0 -0
- data/test_blog_app/public/400.html +0 -114
- data/test_blog_app/public/404.html +0 -114
- data/test_blog_app/public/406-unsupported-browser.html +0 -114
- data/test_blog_app/public/422.html +0 -114
- data/test_blog_app/public/500.html +0 -114
- data/test_blog_app/public/icon.png +0 -0
- data/test_blog_app/public/icon.svg +0 -3
- data/test_blog_app/public/robots.txt +0 -1
- data/test_blog_app/script/.keep +0 -0
- data/test_blog_app/storage/.keep +0 -0
- data/test_blog_app/test/controllers/.keep +0 -0
- data/test_blog_app/test/fixtures/files/.keep +0 -0
- data/test_blog_app/test/helpers/.keep +0 -0
- data/test_blog_app/test/integration/.keep +0 -0
- data/test_blog_app/test/models/.keep +0 -0
- data/test_blog_app/test/test_helper.rb +0 -15
- data/test_blog_app/test_enhance_swarm_e2e.rb +0 -244
- data/test_blog_app/test_realistic_workflow.rb +0 -292
- data/test_blog_app/tmp/.keep +0 -0
- data/test_blog_app/tmp/pids/.keep +0 -0
- data/test_blog_app/tmp/storage/.keep +0 -0
- data/test_blog_app/vendor/.keep +0 -0
- data/test_builtin_functionality.rb +0 -121
- data/test_complete_system.rb +0 -267
- data/test_core_components.rb +0 -156
- data/test_real_claude_integration.rb +0 -285
- data/test_security.rb +0 -150
- data/test_smart_defaults.rb +0 -155
- data/test_task_integration.rb +0 -173
- data/test_web_ui.rb +0 -245
- data/web/assets/css/main.css +0 -645
- data/web/assets/js/kanban.js +0 -499
- data/web/assets/js/main.js +0 -525
- data/web/templates/dashboard.html.erb +0 -226
- data/web/templates/kanban.html.erb +0 -193
data/web/assets/js/main.js
DELETED
@@ -1,525 +0,0 @@
|
|
1
|
-
// EnhanceSwarm Web UI JavaScript
|
2
|
-
|
3
|
-
// Global state
|
4
|
-
window.EnhanceSwarm = {
|
5
|
-
status: {},
|
6
|
-
tasks: {},
|
7
|
-
agents: [],
|
8
|
-
config: {},
|
9
|
-
refreshInterval: null
|
10
|
-
};
|
11
|
-
|
12
|
-
// API helper functions
|
13
|
-
async function apiRequest(endpoint, options = {}) {
|
14
|
-
try {
|
15
|
-
const response = await fetch(endpoint, {
|
16
|
-
headers: {
|
17
|
-
'Content-Type': 'application/json',
|
18
|
-
...options.headers
|
19
|
-
},
|
20
|
-
...options
|
21
|
-
});
|
22
|
-
|
23
|
-
if (!response.ok) {
|
24
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
25
|
-
}
|
26
|
-
|
27
|
-
return await response.json();
|
28
|
-
} catch (error) {
|
29
|
-
console.error('API request failed:', error);
|
30
|
-
showNotification('API request failed: ' + error.message, 'error');
|
31
|
-
throw error;
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
// Dashboard functions
|
36
|
-
async function initializeDashboard() {
|
37
|
-
try {
|
38
|
-
await Promise.all([
|
39
|
-
loadStatus(),
|
40
|
-
loadConfig(),
|
41
|
-
loadProjectInfo()
|
42
|
-
]);
|
43
|
-
|
44
|
-
updateDashboard();
|
45
|
-
} catch (error) {
|
46
|
-
console.error('Failed to initialize dashboard:', error);
|
47
|
-
showNotification('Failed to load dashboard data', 'error');
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
async function loadStatus() {
|
52
|
-
try {
|
53
|
-
const status = await apiRequest('/api/status');
|
54
|
-
window.EnhanceSwarm.status = status;
|
55
|
-
return status;
|
56
|
-
} catch (error) {
|
57
|
-
console.error('Failed to load status:', error);
|
58
|
-
return {};
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
async function loadTasks() {
|
63
|
-
try {
|
64
|
-
const tasks = await apiRequest('/api/tasks');
|
65
|
-
window.EnhanceSwarm.tasks = tasks;
|
66
|
-
return tasks;
|
67
|
-
} catch (error) {
|
68
|
-
console.error('Failed to load tasks:', error);
|
69
|
-
return { tasks: [], folders: [] };
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
async function loadConfig() {
|
74
|
-
try {
|
75
|
-
const config = await apiRequest('/api/config');
|
76
|
-
window.EnhanceSwarm.config = config;
|
77
|
-
return config;
|
78
|
-
} catch (error) {
|
79
|
-
console.error('Failed to load config:', error);
|
80
|
-
return {};
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
async function loadProjectInfo() {
|
85
|
-
try {
|
86
|
-
const projectInfo = await apiRequest('/api/project/analyze');
|
87
|
-
window.EnhanceSwarm.projectInfo = projectInfo;
|
88
|
-
return projectInfo;
|
89
|
-
} catch (error) {
|
90
|
-
console.error('Failed to load project info:', error);
|
91
|
-
return {};
|
92
|
-
}
|
93
|
-
}
|
94
|
-
|
95
|
-
function updateDashboard() {
|
96
|
-
updateStatusOverview();
|
97
|
-
updateActiveAgents();
|
98
|
-
updateRecentTasks();
|
99
|
-
updateSystemHealth();
|
100
|
-
updateProjectInfo();
|
101
|
-
}
|
102
|
-
|
103
|
-
function updateStatusOverview() {
|
104
|
-
const status = window.EnhanceSwarm.status;
|
105
|
-
|
106
|
-
// Session status
|
107
|
-
const sessionStatus = document.getElementById('session-status');
|
108
|
-
if (sessionStatus) {
|
109
|
-
const icon = sessionStatus.querySelector('i');
|
110
|
-
const value = sessionStatus.querySelector('.status-value');
|
111
|
-
|
112
|
-
if (status.session_exists) {
|
113
|
-
icon.className = 'fas fa-circle';
|
114
|
-
icon.style.color = '#27ae60';
|
115
|
-
value.textContent = 'Active';
|
116
|
-
} else {
|
117
|
-
icon.className = 'fas fa-circle';
|
118
|
-
icon.style.color = '#7f8c8d';
|
119
|
-
value.textContent = 'Inactive';
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
|
-
// Agents status
|
124
|
-
const agentsStatus = document.getElementById('agents-status');
|
125
|
-
if (agentsStatus) {
|
126
|
-
const value = agentsStatus.querySelector('.status-value');
|
127
|
-
value.textContent = status.active_agents || 0;
|
128
|
-
}
|
129
|
-
|
130
|
-
// Tasks status
|
131
|
-
const tasksStatus = document.getElementById('tasks-status');
|
132
|
-
if (tasksStatus) {
|
133
|
-
const value = tasksStatus.querySelector('.status-value');
|
134
|
-
const tasks = window.EnhanceSwarm.tasks;
|
135
|
-
value.textContent = tasks.tasks ? tasks.tasks.length : 0;
|
136
|
-
}
|
137
|
-
}
|
138
|
-
|
139
|
-
function updateActiveAgents() {
|
140
|
-
const container = document.getElementById('active-agents-list');
|
141
|
-
if (!container) return;
|
142
|
-
|
143
|
-
const status = window.EnhanceSwarm.status;
|
144
|
-
|
145
|
-
if (!status.agents || status.agents.length === 0) {
|
146
|
-
container.innerHTML = '<div class="text-center text-secondary">No active agents</div>';
|
147
|
-
return;
|
148
|
-
}
|
149
|
-
|
150
|
-
const activeAgents = status.agents.filter(agent => agent.status === 'running');
|
151
|
-
|
152
|
-
if (activeAgents.length === 0) {
|
153
|
-
container.innerHTML = '<div class="text-center text-secondary">No active agents</div>';
|
154
|
-
return;
|
155
|
-
}
|
156
|
-
|
157
|
-
container.innerHTML = activeAgents.map(agent => `
|
158
|
-
<div class="agent-item">
|
159
|
-
<div class="agent-icon">
|
160
|
-
<i class="fas fa-robot" style="color: #27ae60;"></i>
|
161
|
-
</div>
|
162
|
-
<div class="agent-info">
|
163
|
-
<div class="agent-role">${agent.role.toUpperCase()}</div>
|
164
|
-
<div class="agent-details">PID: ${agent.pid} | Runtime: ${calculateRuntime(agent.start_time)}</div>
|
165
|
-
</div>
|
166
|
-
</div>
|
167
|
-
`).join('');
|
168
|
-
}
|
169
|
-
|
170
|
-
function updateRecentTasks() {
|
171
|
-
const container = document.getElementById('recent-tasks-list');
|
172
|
-
if (!container) return;
|
173
|
-
|
174
|
-
const tasks = window.EnhanceSwarm.tasks;
|
175
|
-
|
176
|
-
if (!tasks.tasks || tasks.tasks.length === 0) {
|
177
|
-
container.innerHTML = '<div class="text-center text-secondary">No tasks found</div>';
|
178
|
-
return;
|
179
|
-
}
|
180
|
-
|
181
|
-
const recentTasks = tasks.tasks.slice(0, 5);
|
182
|
-
|
183
|
-
container.innerHTML = recentTasks.map(task => `
|
184
|
-
<div class="task-item">
|
185
|
-
<div class="task-title">${task.title || 'Untitled Task'}</div>
|
186
|
-
<div class="task-status">${task.status || 'unknown'}</div>
|
187
|
-
</div>
|
188
|
-
`).join('');
|
189
|
-
}
|
190
|
-
|
191
|
-
function updateSystemHealth() {
|
192
|
-
const container = document.getElementById('system-health');
|
193
|
-
if (!container) return;
|
194
|
-
|
195
|
-
const config = window.EnhanceSwarm.config;
|
196
|
-
const status = window.EnhanceSwarm.status;
|
197
|
-
|
198
|
-
const healthItems = [
|
199
|
-
{
|
200
|
-
name: 'Configuration',
|
201
|
-
status: Object.keys(config).length > 0 ? 'healthy' : 'warning',
|
202
|
-
message: Object.keys(config).length > 0 ? 'Loaded' : 'No config found'
|
203
|
-
},
|
204
|
-
{
|
205
|
-
name: 'Task Management',
|
206
|
-
status: window.EnhanceSwarm.tasks.swarm_tasks_available ? 'healthy' : 'warning',
|
207
|
-
message: window.EnhanceSwarm.tasks.swarm_tasks_available ? 'Available' : 'Limited functionality'
|
208
|
-
},
|
209
|
-
{
|
210
|
-
name: 'Agent System',
|
211
|
-
status: status.session_exists ? 'healthy' : 'inactive',
|
212
|
-
message: status.session_exists ? 'Session active' : 'No active session'
|
213
|
-
}
|
214
|
-
];
|
215
|
-
|
216
|
-
container.innerHTML = healthItems.map(item => `
|
217
|
-
<div class="health-item">
|
218
|
-
<div class="health-icon">
|
219
|
-
<i class="fas fa-${item.status === 'healthy' ? 'check-circle' : item.status === 'warning' ? 'exclamation-triangle' : 'times-circle'}"
|
220
|
-
style="color: ${item.status === 'healthy' ? '#27ae60' : item.status === 'warning' ? '#f39c12' : '#e74c3c'};"></i>
|
221
|
-
</div>
|
222
|
-
<div class="health-info">
|
223
|
-
<div class="health-name">${item.name}</div>
|
224
|
-
<div class="health-message">${item.message}</div>
|
225
|
-
</div>
|
226
|
-
</div>
|
227
|
-
`).join('');
|
228
|
-
}
|
229
|
-
|
230
|
-
function updateProjectInfo() {
|
231
|
-
const container = document.getElementById('project-info');
|
232
|
-
if (!container) return;
|
233
|
-
|
234
|
-
const projectInfo = window.EnhanceSwarm.projectInfo;
|
235
|
-
|
236
|
-
if (!projectInfo || !projectInfo.analysis) {
|
237
|
-
container.innerHTML = '<div class="text-center text-secondary">No project analysis available</div>';
|
238
|
-
return;
|
239
|
-
}
|
240
|
-
|
241
|
-
const analysis = projectInfo.analysis;
|
242
|
-
|
243
|
-
container.innerHTML = `
|
244
|
-
<div class="project-detail">
|
245
|
-
<strong>Type:</strong> ${analysis.project_type || 'Unknown'}
|
246
|
-
</div>
|
247
|
-
<div class="project-detail">
|
248
|
-
<strong>Stack:</strong> ${analysis.technology_stack ? analysis.technology_stack.join(', ') : 'Not detected'}
|
249
|
-
</div>
|
250
|
-
<div class="project-detail">
|
251
|
-
<strong>Testing:</strong> ${analysis.testing_framework ? analysis.testing_framework.join(', ') : 'None detected'}
|
252
|
-
</div>
|
253
|
-
<div class="project-detail">
|
254
|
-
<strong>Documentation:</strong> ${analysis.documentation && analysis.documentation.has_docs ? 'Available' : 'None found'}
|
255
|
-
</div>
|
256
|
-
`;
|
257
|
-
}
|
258
|
-
|
259
|
-
// Agent management
|
260
|
-
async function spawnAgent() {
|
261
|
-
openModal('spawn-agent-modal');
|
262
|
-
}
|
263
|
-
|
264
|
-
async function submitSpawnAgent(formData) {
|
265
|
-
try {
|
266
|
-
const result = await apiRequest('/api/agents/spawn', {
|
267
|
-
method: 'POST',
|
268
|
-
body: JSON.stringify(formData)
|
269
|
-
});
|
270
|
-
|
271
|
-
if (result.success) {
|
272
|
-
showNotification(`${formData.role.charAt(0).toUpperCase() + formData.role.slice(1)} agent spawned successfully (PID: ${result.pid})`, 'success');
|
273
|
-
closeModal('spawn-agent-modal');
|
274
|
-
await refreshData();
|
275
|
-
} else {
|
276
|
-
throw new Error(result.message);
|
277
|
-
}
|
278
|
-
} catch (error) {
|
279
|
-
showNotification('Failed to spawn agent: ' + error.message, 'error');
|
280
|
-
}
|
281
|
-
}
|
282
|
-
|
283
|
-
// Quick actions
|
284
|
-
async function enhanceProject() {
|
285
|
-
showNotification('Starting project enhancement...', 'info');
|
286
|
-
// This would trigger the enhance protocol
|
287
|
-
// For now, just show a message
|
288
|
-
setTimeout(() => {
|
289
|
-
showNotification('Enhancement protocol would be triggered here', 'info');
|
290
|
-
}, 1000);
|
291
|
-
}
|
292
|
-
|
293
|
-
async function analyzeProject() {
|
294
|
-
showNotification('Analyzing project...', 'info');
|
295
|
-
try {
|
296
|
-
await loadProjectInfo();
|
297
|
-
updateProjectInfo();
|
298
|
-
showNotification('Project analysis completed', 'success');
|
299
|
-
} catch (error) {
|
300
|
-
showNotification('Project analysis failed: ' + error.message, 'error');
|
301
|
-
}
|
302
|
-
}
|
303
|
-
|
304
|
-
function viewMonitoring() {
|
305
|
-
window.location.href = '/agents';
|
306
|
-
}
|
307
|
-
|
308
|
-
function setupTasks() {
|
309
|
-
window.location.href = '/kanban';
|
310
|
-
}
|
311
|
-
|
312
|
-
// Utility functions
|
313
|
-
function calculateRuntime(startTime) {
|
314
|
-
if (!startTime) return 'Unknown';
|
315
|
-
|
316
|
-
try {
|
317
|
-
const start = new Date(startTime);
|
318
|
-
const now = new Date();
|
319
|
-
const diff = Math.floor((now - start) / 1000);
|
320
|
-
|
321
|
-
if (diff < 60) return `${diff}s`;
|
322
|
-
if (diff < 3600) return `${Math.floor(diff / 60)}m`;
|
323
|
-
return `${Math.floor(diff / 3600)}h`;
|
324
|
-
} catch (error) {
|
325
|
-
return 'Unknown';
|
326
|
-
}
|
327
|
-
}
|
328
|
-
|
329
|
-
function formatDate(dateString) {
|
330
|
-
if (!dateString) return 'Unknown';
|
331
|
-
|
332
|
-
try {
|
333
|
-
const date = new Date(dateString);
|
334
|
-
return date.toLocaleString();
|
335
|
-
} catch (error) {
|
336
|
-
return 'Unknown';
|
337
|
-
}
|
338
|
-
}
|
339
|
-
|
340
|
-
// Modal management
|
341
|
-
function openModal(modalId) {
|
342
|
-
const modal = document.getElementById(modalId);
|
343
|
-
if (modal) {
|
344
|
-
modal.classList.add('show');
|
345
|
-
document.body.style.overflow = 'hidden';
|
346
|
-
}
|
347
|
-
}
|
348
|
-
|
349
|
-
function closeModal(modalId) {
|
350
|
-
const modal = document.getElementById(modalId);
|
351
|
-
if (modal) {
|
352
|
-
modal.classList.remove('show');
|
353
|
-
document.body.style.overflow = '';
|
354
|
-
}
|
355
|
-
}
|
356
|
-
|
357
|
-
// Click outside modal to close
|
358
|
-
document.addEventListener('click', function(event) {
|
359
|
-
if (event.target.classList.contains('modal')) {
|
360
|
-
closeModal(event.target.id);
|
361
|
-
}
|
362
|
-
});
|
363
|
-
|
364
|
-
// Escape key to close modal
|
365
|
-
document.addEventListener('keydown', function(event) {
|
366
|
-
if (event.key === 'Escape') {
|
367
|
-
const openModal = document.querySelector('.modal.show');
|
368
|
-
if (openModal) {
|
369
|
-
closeModal(openModal.id);
|
370
|
-
}
|
371
|
-
}
|
372
|
-
});
|
373
|
-
|
374
|
-
// Form handling
|
375
|
-
document.addEventListener('submit', function(event) {
|
376
|
-
if (event.target.id === 'spawn-agent-form') {
|
377
|
-
event.preventDefault();
|
378
|
-
|
379
|
-
const formData = new FormData(event.target);
|
380
|
-
const data = {
|
381
|
-
role: formData.get('role'),
|
382
|
-
task: formData.get('task'),
|
383
|
-
worktree: formData.get('worktree') === 'on'
|
384
|
-
};
|
385
|
-
|
386
|
-
submitSpawnAgent(data);
|
387
|
-
}
|
388
|
-
});
|
389
|
-
|
390
|
-
// Notifications
|
391
|
-
function showNotification(message, type = 'info') {
|
392
|
-
// Create notification element
|
393
|
-
const notification = document.createElement('div');
|
394
|
-
notification.className = `notification notification-${type}`;
|
395
|
-
notification.innerHTML = `
|
396
|
-
<div class="notification-content">
|
397
|
-
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
|
398
|
-
<span>${message}</span>
|
399
|
-
</div>
|
400
|
-
<button class="notification-close" onclick="this.parentElement.remove()">
|
401
|
-
<i class="fas fa-times"></i>
|
402
|
-
</button>
|
403
|
-
`;
|
404
|
-
|
405
|
-
// Add to page
|
406
|
-
let container = document.getElementById('notification-container');
|
407
|
-
if (!container) {
|
408
|
-
container = document.createElement('div');
|
409
|
-
container.id = 'notification-container';
|
410
|
-
container.style.cssText = `
|
411
|
-
position: fixed;
|
412
|
-
top: 20px;
|
413
|
-
right: 20px;
|
414
|
-
z-index: 10000;
|
415
|
-
max-width: 400px;
|
416
|
-
`;
|
417
|
-
document.body.appendChild(container);
|
418
|
-
}
|
419
|
-
|
420
|
-
container.appendChild(notification);
|
421
|
-
|
422
|
-
// Auto remove after 5 seconds
|
423
|
-
setTimeout(() => {
|
424
|
-
if (notification.parentElement) {
|
425
|
-
notification.remove();
|
426
|
-
}
|
427
|
-
}, 5000);
|
428
|
-
}
|
429
|
-
|
430
|
-
// Auto refresh
|
431
|
-
function startAutoRefresh() {
|
432
|
-
// Refresh every 30 seconds
|
433
|
-
window.EnhanceSwarm.refreshInterval = setInterval(async () => {
|
434
|
-
try {
|
435
|
-
await Promise.all([
|
436
|
-
loadStatus(),
|
437
|
-
loadTasks()
|
438
|
-
]);
|
439
|
-
updateDashboard();
|
440
|
-
} catch (error) {
|
441
|
-
console.error('Auto refresh failed:', error);
|
442
|
-
}
|
443
|
-
}, 30000);
|
444
|
-
}
|
445
|
-
|
446
|
-
function stopAutoRefresh() {
|
447
|
-
if (window.EnhanceSwarm.refreshInterval) {
|
448
|
-
clearInterval(window.EnhanceSwarm.refreshInterval);
|
449
|
-
window.EnhanceSwarm.refreshInterval = null;
|
450
|
-
}
|
451
|
-
}
|
452
|
-
|
453
|
-
async function refreshData() {
|
454
|
-
try {
|
455
|
-
await Promise.all([
|
456
|
-
loadStatus(),
|
457
|
-
loadTasks(),
|
458
|
-
loadConfig()
|
459
|
-
]);
|
460
|
-
updateDashboard();
|
461
|
-
showNotification('Data refreshed', 'success');
|
462
|
-
} catch (error) {
|
463
|
-
showNotification('Failed to refresh data', 'error');
|
464
|
-
}
|
465
|
-
}
|
466
|
-
|
467
|
-
// Add notification styles to head
|
468
|
-
const notificationStyles = `
|
469
|
-
.notification {
|
470
|
-
background: white;
|
471
|
-
border-radius: 8px;
|
472
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
473
|
-
margin-bottom: 10px;
|
474
|
-
padding: 16px;
|
475
|
-
display: flex;
|
476
|
-
justify-content: space-between;
|
477
|
-
align-items: center;
|
478
|
-
animation: slideInRight 0.3s ease;
|
479
|
-
}
|
480
|
-
|
481
|
-
.notification-success { border-left: 4px solid #27ae60; }
|
482
|
-
.notification-error { border-left: 4px solid #e74c3c; }
|
483
|
-
.notification-info { border-left: 4px solid #3498db; }
|
484
|
-
|
485
|
-
.notification-content {
|
486
|
-
display: flex;
|
487
|
-
align-items: center;
|
488
|
-
}
|
489
|
-
|
490
|
-
.notification-content i {
|
491
|
-
margin-right: 8px;
|
492
|
-
font-size: 18px;
|
493
|
-
}
|
494
|
-
|
495
|
-
.notification-success .notification-content i { color: #27ae60; }
|
496
|
-
.notification-error .notification-content i { color: #e74c3c; }
|
497
|
-
.notification-info .notification-content i { color: #3498db; }
|
498
|
-
|
499
|
-
.notification-close {
|
500
|
-
background: none;
|
501
|
-
border: none;
|
502
|
-
cursor: pointer;
|
503
|
-
color: #7f8c8d;
|
504
|
-
padding: 4px;
|
505
|
-
}
|
506
|
-
|
507
|
-
.notification-close:hover {
|
508
|
-
color: #2c3e50;
|
509
|
-
}
|
510
|
-
|
511
|
-
@keyframes slideInRight {
|
512
|
-
from {
|
513
|
-
transform: translateX(100%);
|
514
|
-
opacity: 0;
|
515
|
-
}
|
516
|
-
to {
|
517
|
-
transform: translateX(0);
|
518
|
-
opacity: 1;
|
519
|
-
}
|
520
|
-
}
|
521
|
-
`;
|
522
|
-
|
523
|
-
const styleSheet = document.createElement('style');
|
524
|
-
styleSheet.textContent = notificationStyles;
|
525
|
-
document.head.appendChild(styleSheet);
|