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