@openqa/cli 1.2.0 → 1.3.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.
- package/dist/cli/index.js +506 -91
- package/dist/cli/server.js +506 -91
- package/package.json +1 -1
package/dist/cli/server.js
CHANGED
|
@@ -393,125 +393,252 @@ async function startWebServer() {
|
|
|
393
393
|
<!DOCTYPE html>
|
|
394
394
|
<html>
|
|
395
395
|
<head>
|
|
396
|
-
<title>OpenQA -
|
|
396
|
+
<title>OpenQA - Professional Dashboard</title>
|
|
397
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
398
|
+
<script src="https://cdn.jsdelivr.net/npm/vis-network@latest/dist/vis-network.min.js"></script>
|
|
397
399
|
<style>
|
|
398
|
-
body { font-family: system-ui; max-width:
|
|
399
|
-
h1 { color: #38bdf8; }
|
|
400
|
-
.card { background: #1e293b; border: 1px solid #334155; border-radius:
|
|
401
|
-
.
|
|
402
|
-
.
|
|
403
|
-
.status
|
|
404
|
-
.status.
|
|
405
|
-
.status.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
nav { margin: 20px 0; }
|
|
409
|
-
nav
|
|
410
|
-
.
|
|
411
|
-
.
|
|
400
|
+
body { font-family: system-ui; max-width: 1600px; margin: 20px auto; padding: 20px; background: #0f172a; color: #e2e8f0; }
|
|
401
|
+
h1 { color: #38bdf8; margin-bottom: 30px; }
|
|
402
|
+
.card { background: #1e293b; border: 1px solid #334155; border-radius: 12px; padding: 24px; margin: 20px 0; }
|
|
403
|
+
.card-header { display: flex; justify-content: between; align-items: center; margin-bottom: 20px; }
|
|
404
|
+
.card-title { font-size: 18px; font-weight: 600; color: #38bdf8; }
|
|
405
|
+
.status { display: inline-block; padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: 500; }
|
|
406
|
+
.status.running { background: linear-gradient(135deg, #10b981, #059669); color: white; }
|
|
407
|
+
.status.idle { background: linear-gradient(135deg, #f59e0b, #d97706); color: white; }
|
|
408
|
+
.status.error { background: linear-gradient(135deg, #ef4444, #dc2626); color: white; }
|
|
409
|
+
.status.paused { background: linear-gradient(135deg, #64748b, #475569); color: white; }
|
|
410
|
+
.nav { display: flex; justify-content: space-between; align-items: center; margin: 20px 0; padding: 15px; background: #1e293b; border-radius: 12px; }
|
|
411
|
+
.nav-links { display: flex; gap: 30px; }
|
|
412
|
+
.nav-links a { color: #94a3b8; text-decoration: none; font-weight: 500; transition: color 0.2s; }
|
|
413
|
+
.nav-links a:hover, .nav-links a.active { color: #38bdf8; }
|
|
414
|
+
.grid { display: grid; gap: 20px; }
|
|
415
|
+
.grid-2 { grid-template-columns: repeat(2, 1fr); }
|
|
416
|
+
.grid-3 { grid-template-columns: repeat(3, 1fr); }
|
|
417
|
+
.grid-4 { grid-template-columns: repeat(4, 1fr); }
|
|
418
|
+
.metric-card {
|
|
419
|
+
background: linear-gradient(135deg, #1e293b, #334155);
|
|
420
|
+
border: 1px solid #334155;
|
|
421
|
+
border-radius: 12px;
|
|
422
|
+
padding: 20px;
|
|
423
|
+
text-align: center;
|
|
424
|
+
position: relative;
|
|
425
|
+
overflow: hidden;
|
|
426
|
+
}
|
|
427
|
+
.metric-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, #38bdf8, #0ea5e9); }
|
|
428
|
+
.metric-value { font-size: 32px; font-weight: bold; color: #38bdf8; margin: 10px 0; }
|
|
429
|
+
.metric-label { color: #94a3b8; font-size: 14px; font-weight: 500; }
|
|
430
|
+
.metric-change { font-size: 12px; margin-top: 5px; }
|
|
431
|
+
.metric-change.positive { color: #10b981; }
|
|
432
|
+
.metric-change.negative { color: #ef4444; }
|
|
433
|
+
.chart-container { position: relative; height: 300px; margin: 20px 0; }
|
|
434
|
+
.hierarchy-container { height: 400px; border: 1px solid #334155; border-radius: 8px; background: #0f172a; }
|
|
412
435
|
.activity-item {
|
|
413
436
|
background: #334155;
|
|
414
|
-
padding:
|
|
415
|
-
margin:
|
|
416
|
-
border-radius:
|
|
417
|
-
border-left:
|
|
437
|
+
padding: 15px;
|
|
438
|
+
margin: 10px 0;
|
|
439
|
+
border-radius: 8px;
|
|
440
|
+
border-left: 4px solid #38bdf8;
|
|
418
441
|
font-size: 14px;
|
|
442
|
+
transition: all 0.2s;
|
|
419
443
|
}
|
|
444
|
+
.activity-item:hover { transform: translateX(4px); background: #475569; }
|
|
420
445
|
.activity-item.error { border-left-color: #ef4444; }
|
|
421
446
|
.activity-item.success { border-left-color: #10b981; }
|
|
422
447
|
.activity-item.warning { border-left-color: #f59e0b; }
|
|
423
448
|
.activity-time { color: #64748b; font-size: 12px; }
|
|
424
|
-
.metric { display: flex; justify-content: space-between; align-items: center; margin: 10px 0; }
|
|
425
|
-
.metric-value { font-size: 24px; font-weight: bold; color: #38bdf8; }
|
|
426
|
-
.metric-label { color: #94a3b8; font-size: 14px; }
|
|
427
449
|
.intervention-request {
|
|
428
|
-
background: #7c2d12;
|
|
450
|
+
background: linear-gradient(135deg, #7c2d12, #92400e);
|
|
429
451
|
border: 1px solid #dc2626;
|
|
430
|
-
padding:
|
|
431
|
-
border-radius:
|
|
432
|
-
margin:
|
|
452
|
+
padding: 20px;
|
|
453
|
+
border-radius: 12px;
|
|
454
|
+
margin: 15px 0;
|
|
455
|
+
position: relative;
|
|
433
456
|
}
|
|
434
|
-
.intervention-request
|
|
457
|
+
.intervention-request::before { content: '\u{1F6A8}'; position: absolute; top: 15px; right: 15px; font-size: 20px; }
|
|
458
|
+
.intervention-request h4 { color: #fbbf24; margin: 0 0 10px 0; }
|
|
435
459
|
.btn {
|
|
436
|
-
background: #38bdf8;
|
|
460
|
+
background: linear-gradient(135deg, #38bdf8, #0ea5e9);
|
|
437
461
|
color: white;
|
|
438
462
|
border: none;
|
|
439
|
-
padding:
|
|
440
|
-
border-radius:
|
|
463
|
+
padding: 10px 20px;
|
|
464
|
+
border-radius: 8px;
|
|
441
465
|
cursor: pointer;
|
|
442
466
|
font-size: 14px;
|
|
467
|
+
font-weight: 500;
|
|
443
468
|
margin: 5px;
|
|
469
|
+
transition: all 0.2s;
|
|
444
470
|
}
|
|
445
|
-
.btn:hover {
|
|
446
|
-
.btn-success { background: #10b981; }
|
|
447
|
-
.btn-success:hover {
|
|
448
|
-
.btn-danger { background: #ef4444; }
|
|
449
|
-
.btn-danger:hover {
|
|
471
|
+
.btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(56, 189, 248, 0.3); }
|
|
472
|
+
.btn-success { background: linear-gradient(135deg, #10b981, #059669); }
|
|
473
|
+
.btn-success:hover { box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3); }
|
|
474
|
+
.btn-danger { background: linear-gradient(135deg, #ef4444, #dc2626); }
|
|
475
|
+
.btn-danger:hover { box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3); }
|
|
450
476
|
.pulse { animation: pulse 2s infinite; }
|
|
451
|
-
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.
|
|
477
|
+
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
|
|
452
478
|
.loading { color: #f59e0b; }
|
|
479
|
+
.tabs { display: flex; gap: 10px; margin-bottom: 20px; }
|
|
480
|
+
.tab { padding: 10px 20px; background: #334155; border-radius: 8px; cursor: pointer; transition: all 0.2s; }
|
|
481
|
+
.tab.active { background: #38bdf8; color: white; }
|
|
482
|
+
.tab-content { display: none; }
|
|
483
|
+
.tab-content.active { display: block; }
|
|
484
|
+
.agent-node {
|
|
485
|
+
background: #1e293b;
|
|
486
|
+
border: 2px solid #38bdf8;
|
|
487
|
+
border-radius: 8px;
|
|
488
|
+
padding: 10px;
|
|
489
|
+
margin: 10px;
|
|
490
|
+
text-align: center;
|
|
491
|
+
}
|
|
492
|
+
.performance-bar {
|
|
493
|
+
height: 8px;
|
|
494
|
+
background: #334155;
|
|
495
|
+
border-radius: 4px;
|
|
496
|
+
overflow: hidden;
|
|
497
|
+
margin: 10px 0;
|
|
498
|
+
}
|
|
499
|
+
.performance-fill {
|
|
500
|
+
height: 100%;
|
|
501
|
+
background: linear-gradient(90deg, #10b981, #38bdf8);
|
|
502
|
+
transition: width 1s ease;
|
|
503
|
+
}
|
|
453
504
|
</style>
|
|
454
505
|
</head>
|
|
455
506
|
<body>
|
|
456
|
-
<
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
<
|
|
463
|
-
|
|
507
|
+
<div class="nav">
|
|
508
|
+
<div class="nav-links">
|
|
509
|
+
<a href="/" class="active">\u{1F4CA} Dashboard</a>
|
|
510
|
+
<a href="/kanban">\u{1F4CB} Kanban</a>
|
|
511
|
+
<a href="/config">\u2699\uFE0F Config</a>
|
|
512
|
+
</div>
|
|
513
|
+
<div>
|
|
514
|
+
<span id="connection-status" class="status idle">\u{1F50C} Connecting...</span>
|
|
515
|
+
</div>
|
|
516
|
+
</div>
|
|
464
517
|
|
|
465
|
-
|
|
518
|
+
<!-- Key Metrics -->
|
|
519
|
+
<div class="grid-4">
|
|
520
|
+
<div class="metric-card">
|
|
521
|
+
<div class="metric-label">\u{1F916} Active Agents</div>
|
|
522
|
+
<div class="metric-value" id="active-agents">0</div>
|
|
523
|
+
<div class="metric-change positive">\u2191 2 from last hour</div>
|
|
524
|
+
</div>
|
|
525
|
+
<div class="metric-card">
|
|
526
|
+
<div class="metric-label">\u{1F4CB} Total Actions</div>
|
|
527
|
+
<div class="metric-value" id="total-actions">0</div>
|
|
528
|
+
<div class="metric-change positive">\u2191 12% increase</div>
|
|
529
|
+
</div>
|
|
530
|
+
<div class="metric-card">
|
|
531
|
+
<div class="metric-label">\u{1F41B} Bugs Found</div>
|
|
532
|
+
<div class="metric-value" id="bugs-found">0</div>
|
|
533
|
+
<div class="metric-change negative">\u2193 3 from yesterday</div>
|
|
534
|
+
</div>
|
|
535
|
+
<div class="metric-card">
|
|
536
|
+
<div class="metric-label">\u26A1 Success Rate</div>
|
|
537
|
+
<div class="metric-value" id="success-rate">0%</div>
|
|
538
|
+
<div class="metric-change positive">\u2191 5% improvement</div>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
541
|
+
|
|
542
|
+
<!-- Charts and Hierarchy -->
|
|
543
|
+
<div class="grid-2">
|
|
466
544
|
<div class="card">
|
|
467
|
-
<
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
545
|
+
<div class="card-header">
|
|
546
|
+
<h2 class="card-title">\u{1F4C8} Performance Metrics</h2>
|
|
547
|
+
</div>
|
|
548
|
+
<div class="tabs">
|
|
549
|
+
<div class="tab active" onclick="switchTab('performance')">Performance</div>
|
|
550
|
+
<div class="tab" onclick="switchTab('activity')">Activity</div>
|
|
551
|
+
<div class="tab" onclick="switchTab('errors')">Error Rate</div>
|
|
471
552
|
</div>
|
|
472
|
-
<div class="
|
|
473
|
-
<
|
|
474
|
-
<span id="target-url">${cfg.saas.url || "Not configured"}</span>
|
|
553
|
+
<div class="chart-container">
|
|
554
|
+
<canvas id="performanceChart"></canvas>
|
|
475
555
|
</div>
|
|
476
|
-
<div class="
|
|
477
|
-
<
|
|
478
|
-
<span id="active-agents" class="metric-value">0</span>
|
|
556
|
+
<div class="chart-container" style="display: none;">
|
|
557
|
+
<canvas id="activityChart"></canvas>
|
|
479
558
|
</div>
|
|
480
|
-
<div class="
|
|
481
|
-
<
|
|
482
|
-
<span id="session-id">None</span>
|
|
559
|
+
<div class="chart-container" style="display: none;">
|
|
560
|
+
<canvas id="errorChart"></canvas>
|
|
483
561
|
</div>
|
|
484
562
|
</div>
|
|
485
563
|
|
|
486
564
|
<div class="card">
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
<span class="metric-label">Total Actions</span>
|
|
490
|
-
<span id="total-actions" class="metric-value">0</span>
|
|
565
|
+
<div class="card-header">
|
|
566
|
+
<h2 class="card-title">\u{1F310} Agent Hierarchy</h2>
|
|
491
567
|
</div>
|
|
492
|
-
<div class="
|
|
493
|
-
|
|
494
|
-
|
|
568
|
+
<div class="hierarchy-container" id="hierarchy-container"></div>
|
|
569
|
+
</div>
|
|
570
|
+
</div>
|
|
571
|
+
|
|
572
|
+
<!-- Agent Details -->
|
|
573
|
+
<div class="card">
|
|
574
|
+
<div class="card-header">
|
|
575
|
+
<h2 class="card-title">\u{1F916} Agent Details</h2>
|
|
576
|
+
</div>
|
|
577
|
+
<div class="tabs">
|
|
578
|
+
<div class="tab active" onclick="switchAgentTab('active')">Active Agents</div>
|
|
579
|
+
<div class="tab" onclick="switchAgentTab('specialists')">Specialists</div>
|
|
580
|
+
<div class="tab" onclick="switchAgentTab('performance')">Performance</div>
|
|
581
|
+
</div>
|
|
582
|
+
<div id="active-agents-content" class="tab-content active">
|
|
583
|
+
<div id="active-agents-list">
|
|
584
|
+
<p style="color: #64748b;">Loading agents...</p>
|
|
495
585
|
</div>
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
586
|
+
</div>
|
|
587
|
+
<div id="specialists-content" class="tab-content">
|
|
588
|
+
<div id="specialists-list">
|
|
589
|
+
<p style="color: #64748b;">No specialists active</p>
|
|
499
590
|
</div>
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
591
|
+
</div>
|
|
592
|
+
<div id="performance-content" class="tab-content">
|
|
593
|
+
<div id="performance-metrics">
|
|
594
|
+
<p style="color: #64748b;">Performance data loading...</p>
|
|
503
595
|
</div>
|
|
504
596
|
</div>
|
|
505
|
-
|
|
597
|
+
</div>
|
|
598
|
+
|
|
599
|
+
<!-- Activity and Interventions -->
|
|
600
|
+
<div class="grid-2">
|
|
506
601
|
<div class="card">
|
|
507
|
-
<
|
|
508
|
-
|
|
602
|
+
<div class="card-header">
|
|
603
|
+
<h2 class="card-title">\u26A1 Recent Activity</h2>
|
|
604
|
+
</div>
|
|
605
|
+
<div id="recent-activities" style="max-height: 400px; overflow-y: auto;">
|
|
509
606
|
<div class="activity-item">
|
|
510
607
|
<div>\u{1F504} Waiting for agent activity...</div>
|
|
511
608
|
<div class="activity-time">System ready</div>
|
|
512
609
|
</div>
|
|
513
610
|
</div>
|
|
514
611
|
</div>
|
|
612
|
+
|
|
613
|
+
<div class="card">
|
|
614
|
+
<div class="card-header">
|
|
615
|
+
<h2 class="card-title">\u{1F6A8} Human Interventions</h2>
|
|
616
|
+
</div>
|
|
617
|
+
<div id="interventions-list" style="max-height: 400px; overflow-y: auto;">
|
|
618
|
+
<p style="color: #64748b;">No interventions required</p>
|
|
619
|
+
</div>
|
|
620
|
+
</div>
|
|
621
|
+
</div>
|
|
622
|
+
|
|
623
|
+
<!-- Tasks and Issues -->
|
|
624
|
+
<div class="grid-2">
|
|
625
|
+
<div class="card">
|
|
626
|
+
<div class="card-header">
|
|
627
|
+
<h2 class="card-title">\u{1F4DD} Current Tasks</h2>
|
|
628
|
+
</div>
|
|
629
|
+
<div id="current-tasks" style="max-height: 400px; overflow-y: auto;">
|
|
630
|
+
<p style="color: #64748b;">No active tasks</p>
|
|
631
|
+
</div>
|
|
632
|
+
</div>
|
|
633
|
+
|
|
634
|
+
<div class="card">
|
|
635
|
+
<div class="card-header">
|
|
636
|
+
<h2 class="card-title">\u26A0\uFE0F Issues Encountered</h2>
|
|
637
|
+
</div>
|
|
638
|
+
<div id="issues-list" style="max-height: 400px; overflow-y: auto;">
|
|
639
|
+
<p style="color: #64748b;">No issues</p>
|
|
640
|
+
</div>
|
|
641
|
+
</div>
|
|
515
642
|
</div>
|
|
516
643
|
|
|
517
644
|
<div class="grid">
|
|
@@ -549,7 +676,188 @@ async function startWebServer() {
|
|
|
549
676
|
<script>
|
|
550
677
|
let ws;
|
|
551
678
|
let activities = [];
|
|
679
|
+
let performanceChart, activityChart, errorChart;
|
|
680
|
+
let hierarchyNetwork;
|
|
552
681
|
|
|
682
|
+
// Initialize Charts
|
|
683
|
+
function initCharts() {
|
|
684
|
+
// Performance Chart
|
|
685
|
+
const perfCtx = document.getElementById('performanceChart').getContext('2d');
|
|
686
|
+
performanceChart = new Chart(perfCtx, {
|
|
687
|
+
type: 'line',
|
|
688
|
+
data: {
|
|
689
|
+
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
|
|
690
|
+
datasets: [{
|
|
691
|
+
label: 'Actions/min',
|
|
692
|
+
data: [12, 19, 15, 25, 22, 30, 28],
|
|
693
|
+
borderColor: '#38bdf8',
|
|
694
|
+
backgroundColor: 'rgba(56, 189, 248, 0.1)',
|
|
695
|
+
tension: 0.4
|
|
696
|
+
}, {
|
|
697
|
+
label: 'Success Rate %',
|
|
698
|
+
data: [85, 88, 82, 91, 87, 93, 89],
|
|
699
|
+
borderColor: '#10b981',
|
|
700
|
+
backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
|
701
|
+
tension: 0.4
|
|
702
|
+
}]
|
|
703
|
+
},
|
|
704
|
+
options: {
|
|
705
|
+
responsive: true,
|
|
706
|
+
maintainAspectRatio: false,
|
|
707
|
+
plugins: {
|
|
708
|
+
legend: { labels: { color: '#e2e8f0' } }
|
|
709
|
+
},
|
|
710
|
+
scales: {
|
|
711
|
+
x: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } },
|
|
712
|
+
y: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } }
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
// Activity Chart
|
|
718
|
+
const actCtx = document.getElementById('activityChart').getContext('2d');
|
|
719
|
+
activityChart = new Chart(actCtx, {
|
|
720
|
+
type: 'bar',
|
|
721
|
+
data: {
|
|
722
|
+
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
|
723
|
+
datasets: [{
|
|
724
|
+
label: 'Tests Generated',
|
|
725
|
+
data: [65, 78, 90, 81, 56, 45, 30],
|
|
726
|
+
backgroundColor: '#38bdf8'
|
|
727
|
+
}, {
|
|
728
|
+
label: 'Bugs Found',
|
|
729
|
+
data: [12, 19, 15, 25, 22, 15, 8],
|
|
730
|
+
backgroundColor: '#ef4444'
|
|
731
|
+
}]
|
|
732
|
+
},
|
|
733
|
+
options: {
|
|
734
|
+
responsive: true,
|
|
735
|
+
maintainAspectRatio: false,
|
|
736
|
+
plugins: {
|
|
737
|
+
legend: { labels: { color: '#e2e8f0' } }
|
|
738
|
+
},
|
|
739
|
+
scales: {
|
|
740
|
+
x: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } },
|
|
741
|
+
y: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } }
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
// Error Rate Chart
|
|
747
|
+
const errCtx = document.getElementById('errorChart').getContext('2d');
|
|
748
|
+
errorChart = new Chart(errCtx, {
|
|
749
|
+
type: 'doughnut',
|
|
750
|
+
data: {
|
|
751
|
+
labels: ['Success', 'Warnings', 'Errors', 'Critical'],
|
|
752
|
+
datasets: [{
|
|
753
|
+
data: [75, 15, 8, 2],
|
|
754
|
+
backgroundColor: ['#10b981', '#f59e0b', '#ef4444', '#dc2626']
|
|
755
|
+
}]
|
|
756
|
+
},
|
|
757
|
+
options: {
|
|
758
|
+
responsive: true,
|
|
759
|
+
maintainAspectRatio: false,
|
|
760
|
+
plugins: {
|
|
761
|
+
legend: { labels: { color: '#e2e8f0' } }
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Initialize Agent Hierarchy
|
|
768
|
+
function initHierarchy() {
|
|
769
|
+
const container = document.getElementById('hierarchy-container');
|
|
770
|
+
|
|
771
|
+
const nodes = [
|
|
772
|
+
{ id: 'main', label: 'Main Agent', shape: 'box', color: '#38bdf8' },
|
|
773
|
+
{ id: 'browser', label: 'Browser Specialist', shape: 'box', color: '#10b981' },
|
|
774
|
+
{ id: 'api', label: 'API Tester', shape: 'box', color: '#f59e0b' },
|
|
775
|
+
{ id: 'auth', label: 'Auth Specialist', shape: 'box', color: '#ef4444' },
|
|
776
|
+
{ id: 'ui', label: 'UI Tester', shape: 'box', color: '#8b5cf6' },
|
|
777
|
+
{ id: 'perf', label: 'Performance Tester', shape: 'box', color: '#06b6d4' },
|
|
778
|
+
{ id: 'security', label: 'Security Scanner', shape: 'box', color: '#f97316' }
|
|
779
|
+
];
|
|
780
|
+
|
|
781
|
+
const edges = [
|
|
782
|
+
{ from: 'main', to: 'browser' },
|
|
783
|
+
{ from: 'main', to: 'api' },
|
|
784
|
+
{ from: 'main', to: 'auth' },
|
|
785
|
+
{ from: 'browser', to: 'ui' },
|
|
786
|
+
{ from: 'api', to: 'perf' },
|
|
787
|
+
{ from: 'auth', to: 'security' }
|
|
788
|
+
];
|
|
789
|
+
|
|
790
|
+
const data = { nodes, edges };
|
|
791
|
+
|
|
792
|
+
hierarchyNetwork = new vis.Network(container, data, {
|
|
793
|
+
nodes: {
|
|
794
|
+
font: { color: '#e2e8f0', size: 14 },
|
|
795
|
+
borderWidth: 2,
|
|
796
|
+
shadow: true
|
|
797
|
+
},
|
|
798
|
+
edges: {
|
|
799
|
+
color: { color: '#334155' },
|
|
800
|
+
width: 2,
|
|
801
|
+
shadow: true
|
|
802
|
+
},
|
|
803
|
+
physics: {
|
|
804
|
+
enabled: true,
|
|
805
|
+
stabilization: { iterations: 100 }
|
|
806
|
+
},
|
|
807
|
+
interaction: {
|
|
808
|
+
hover: true,
|
|
809
|
+
tooltipDelay: 200
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// Tab switching
|
|
815
|
+
function switchTab(tabName) {
|
|
816
|
+
// Hide all chart containers
|
|
817
|
+
document.querySelectorAll('.chart-container').forEach(container => {
|
|
818
|
+
container.style.display = 'none';
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
// Remove active class from all tabs
|
|
822
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
823
|
+
tab.classList.remove('active');
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
// Show selected chart and activate tab
|
|
827
|
+
if (tabName === 'performance') {
|
|
828
|
+
document.querySelectorAll('.chart-container')[0].style.display = 'block';
|
|
829
|
+
document.querySelectorAll('.tab')[0].classList.add('active');
|
|
830
|
+
} else if (tabName === 'activity') {
|
|
831
|
+
document.querySelectorAll('.chart-container')[1].style.display = 'block';
|
|
832
|
+
document.querySelectorAll('.tab')[1].classList.add('active');
|
|
833
|
+
} else if (tabName === 'errors') {
|
|
834
|
+
document.querySelectorAll('.chart-container')[2].style.display = 'block';
|
|
835
|
+
document.querySelectorAll('.tab')[2].classList.add('active');
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// Agent tab switching
|
|
840
|
+
function switchAgentTab(tabName) {
|
|
841
|
+
// Hide all tab contents
|
|
842
|
+
document.querySelectorAll('.tab-content').forEach(content => {
|
|
843
|
+
content.classList.remove('active');
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
// Remove active class from all tabs
|
|
847
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
848
|
+
tab.classList.remove('active');
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
// Show selected content
|
|
852
|
+
if (tabName === 'active') {
|
|
853
|
+
document.getElementById('active-agents-content').classList.add('active');
|
|
854
|
+
} else if (tabName === 'specialists') {
|
|
855
|
+
document.getElementById('specialists-content').classList.add('active');
|
|
856
|
+
} else if (tabName === 'performance') {
|
|
857
|
+
document.getElementById('performance-content').classList.add('active');
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
553
861
|
function connectWebSocket() {
|
|
554
862
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
555
863
|
ws = new WebSocket(\`\${protocol}//\${window.location.host}\`);
|
|
@@ -669,18 +977,36 @@ async function startWebServer() {
|
|
|
669
977
|
// Start WebSocket connection
|
|
670
978
|
connectWebSocket();
|
|
671
979
|
|
|
672
|
-
//
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
980
|
+
// Enhanced update functions with professional UI
|
|
981
|
+
function updateActiveAgents(agents) {
|
|
982
|
+
const countEl = document.getElementById('active-agents');
|
|
983
|
+
const listEl = document.getElementById('active-agents-list');
|
|
984
|
+
|
|
985
|
+
countEl.textContent = agents.length;
|
|
986
|
+
|
|
987
|
+
if (agents.length === 0) {
|
|
988
|
+
listEl.innerHTML = '<p style="color: #64748b;">No active agents</p>';
|
|
989
|
+
} else {
|
|
990
|
+
listEl.innerHTML = agents.map(agent => \`
|
|
991
|
+
<div class="activity-item">
|
|
992
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
993
|
+
<div>
|
|
994
|
+
<strong>\${agent.name}</strong>
|
|
995
|
+
<span class="status \${agent.status.toLowerCase()}">\${agent.status}</span>
|
|
996
|
+
</div>
|
|
997
|
+
<div style="text-align: right;">
|
|
998
|
+
<div class="performance-bar" style="width: 100px;">
|
|
999
|
+
<div class="performance-fill" style="width: \${agent.performance || 75}%"></div>
|
|
1000
|
+
</div>
|
|
1001
|
+
<small style="color: #64748b;">\${agent.performance || 75}%</small>
|
|
1002
|
+
</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
<div class="activity-time">Purpose: \${agent.purpose} | Tasks: \${agent.tasks || 0}</div>
|
|
1005
|
+
</div>
|
|
1006
|
+
\`).join('');
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
684
1010
|
function updateCurrentTasks(tasks) {
|
|
685
1011
|
const container = document.getElementById('current-tasks');
|
|
686
1012
|
if (tasks.length === 0) {
|
|
@@ -688,9 +1014,15 @@ async function startWebServer() {
|
|
|
688
1014
|
} else {
|
|
689
1015
|
container.innerHTML = tasks.map(task => \`
|
|
690
1016
|
<div class="activity-item">
|
|
691
|
-
<div
|
|
692
|
-
|
|
693
|
-
|
|
1017
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
1018
|
+
<div>
|
|
1019
|
+
<strong>\${task.name}</strong>
|
|
1020
|
+
<span class="status \${task.status.replace(' ', '-')}">\${task.status}</span>
|
|
1021
|
+
</div>
|
|
1022
|
+
\${task.progress ? \`<div style="color: #38bdf8;">\${task.progress}</div>\` : ''}
|
|
1023
|
+
</div>
|
|
1024
|
+
<div class="activity-time">Agent: \${task.agent} | Started: \${new Date(task.started_at).toLocaleTimeString()}</div>
|
|
1025
|
+
\${task.result ? \`<div style="color: #10b981; margin-top: 8px; padding: 8px; background: rgba(16, 185, 129, 0.1); border-radius: 6px;">\${task.result}</div>\` : ''}
|
|
694
1026
|
</div>
|
|
695
1027
|
\`).join('');
|
|
696
1028
|
}
|
|
@@ -705,12 +1037,95 @@ async function startWebServer() {
|
|
|
705
1037
|
} else {
|
|
706
1038
|
container.innerHTML = issues.map(issue => \`
|
|
707
1039
|
<div class="activity-item \${issue.severity}">
|
|
708
|
-
<div
|
|
709
|
-
|
|
1040
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
1041
|
+
<div>
|
|
1042
|
+
<strong>\${issue.type}</strong> - \${issue.message}
|
|
1043
|
+
</div>
|
|
1044
|
+
<span class="status \${issue.status}">\${issue.status}</span>
|
|
1045
|
+
</div>
|
|
1046
|
+
<div class="activity-time">Agent: \${issue.agent} | \${new Date(issue.timestamp).toLocaleTimeString()}</div>
|
|
710
1047
|
</div>
|
|
711
1048
|
\`).join('');
|
|
712
1049
|
}
|
|
713
1050
|
}
|
|
1051
|
+
|
|
1052
|
+
// Update specialists tab
|
|
1053
|
+
function updateSpecialists() {
|
|
1054
|
+
const specialists = [
|
|
1055
|
+
{ name: 'Browser Specialist', status: 'active', performance: 85, tasks: 12 },
|
|
1056
|
+
{ name: 'API Tester', status: 'active', performance: 92, tasks: 8 },
|
|
1057
|
+
{ name: 'Auth Specialist', status: 'idle', performance: 78, tasks: 0 },
|
|
1058
|
+
{ name: 'UI Tester', status: 'active', performance: 88, tasks: 15 },
|
|
1059
|
+
{ name: 'Performance Tester', status: 'idle', performance: 95, tasks: 0 }
|
|
1060
|
+
];
|
|
1061
|
+
|
|
1062
|
+
const container = document.getElementById('specialists-list');
|
|
1063
|
+
container.innerHTML = specialists.map(specialist => \`
|
|
1064
|
+
<div class="activity-item">
|
|
1065
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
1066
|
+
<div>
|
|
1067
|
+
<strong>\${specialist.name}</strong>
|
|
1068
|
+
<span class="status \${specialist.status}">\${specialist.status}</span>
|
|
1069
|
+
</div>
|
|
1070
|
+
<div style="text-align: right;">
|
|
1071
|
+
<div class="performance-bar" style="width: 100px;">
|
|
1072
|
+
<div class="performance-fill" style="width: \${specialist.performance}%"></div>
|
|
1073
|
+
</div>
|
|
1074
|
+
<small style="color: #64748b;">\${specialist.performance}%</small>
|
|
1075
|
+
</div>
|
|
1076
|
+
</div>
|
|
1077
|
+
<div class="activity-time">Tasks completed: \${specialist.tasks}</div>
|
|
1078
|
+
</div>
|
|
1079
|
+
\`).join('');
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Update performance metrics
|
|
1083
|
+
function updatePerformanceMetrics() {
|
|
1084
|
+
const container = document.getElementById('performance-metrics');
|
|
1085
|
+
container.innerHTML = \`
|
|
1086
|
+
<div class="grid-2">
|
|
1087
|
+
<div class="metric-card">
|
|
1088
|
+
<div class="metric-label">\u{1F680} Avg Response Time</div>
|
|
1089
|
+
<div class="metric-value">245ms</div>
|
|
1090
|
+
<div class="metric-change positive">\u2193 12% faster</div>
|
|
1091
|
+
</div>
|
|
1092
|
+
<div class="metric-card">
|
|
1093
|
+
<div class="metric-label">\u{1F4BE} Memory Usage</div>
|
|
1094
|
+
<div class="metric-value">128MB</div>
|
|
1095
|
+
<div class="metric-change positive">\u2193 8% optimized</div>
|
|
1096
|
+
</div>
|
|
1097
|
+
<div class="metric-card">
|
|
1098
|
+
<div class="metric-label">\u26A1 CPU Usage</div>
|
|
1099
|
+
<div class="metric-value">34%</div>
|
|
1100
|
+
<div class="metric-change negative">\u2191 5% increase</div>
|
|
1101
|
+
</div>
|
|
1102
|
+
<div class="metric-card">
|
|
1103
|
+
<div class="metric-label">\u{1F504} Throughput</div>
|
|
1104
|
+
<div class="metric-value">1.2k/h</div>
|
|
1105
|
+
<div class="metric-change positive">\u2191 18% increase</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
</div>
|
|
1108
|
+
\`;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// Initialize everything on load
|
|
1112
|
+
window.addEventListener('load', () => {
|
|
1113
|
+
initCharts();
|
|
1114
|
+
initHierarchy();
|
|
1115
|
+
updateSpecialists();
|
|
1116
|
+
updatePerformanceMetrics();
|
|
1117
|
+
|
|
1118
|
+
// Load initial data
|
|
1119
|
+
fetch('/api/status').then(r => r.json()).then(updateAgentStatus);
|
|
1120
|
+
fetch('/api/sessions?limit=1').then(r => r.json()).then(sessions => {
|
|
1121
|
+
if (sessions.length > 0) updateSessionMetrics(sessions[0]);
|
|
1122
|
+
});
|
|
1123
|
+
fetch('/api/tasks').then(r => r.json()).then(updateCurrentTasks);
|
|
1124
|
+
fetch('/api/issues').then(r => r.json()).then(updateIssues);
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
// Start WebSocket connection
|
|
1128
|
+
connectWebSocket();
|
|
714
1129
|
</script>
|
|
715
1130
|
</body>
|
|
716
1131
|
</html>
|