From fbe6ecddc22817bdd2c335f9525b9db5139126e8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 15 Feb 2026 07:50:08 +0000
Subject: [PATCH 1/3] Initial plan
From 5eebe015d0a9bed912cfae0cc3b9ae3811d4bd9b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 15 Feb 2026 07:57:23 +0000
Subject: [PATCH 2/3] Add dashboard structure with main page, CSS, JavaScript,
and policies page
Co-authored-by: Stacey77 <54900383+Stacey77@users.noreply.github.com>
---
dashboard/assets/logo.svg | 40 +++
dashboard/css/dashboard.css | 557 ++++++++++++++++++++++++++++++++++
dashboard/css/main.css | 452 +++++++++++++++++++++++++++
dashboard/css/responsive.css | 245 +++++++++++++++
dashboard/data/mock-data.json | 281 +++++++++++++++++
dashboard/index.html | 469 ++++++++++++++++++++++++++++
dashboard/js/agents.js | 207 +++++++++++++
dashboard/js/api.js | 252 +++++++++++++++
dashboard/js/charts.js | 320 +++++++++++++++++++
dashboard/js/dashboard.js | 272 +++++++++++++++++
dashboard/js/websocket.js | 244 +++++++++++++++
dashboard/policies.html | 382 +++++++++++++++++++++++
12 files changed, 3721 insertions(+)
create mode 100644 dashboard/assets/logo.svg
create mode 100644 dashboard/css/dashboard.css
create mode 100644 dashboard/css/main.css
create mode 100644 dashboard/css/responsive.css
create mode 100644 dashboard/data/mock-data.json
create mode 100644 dashboard/index.html
create mode 100644 dashboard/js/agents.js
create mode 100644 dashboard/js/api.js
create mode 100644 dashboard/js/charts.js
create mode 100644 dashboard/js/dashboard.js
create mode 100644 dashboard/js/websocket.js
create mode 100644 dashboard/policies.html
diff --git a/dashboard/assets/logo.svg b/dashboard/assets/logo.svg
new file mode 100644
index 0000000..1066b68
--- /dev/null
+++ b/dashboard/assets/logo.svg
@@ -0,0 +1,40 @@
+
diff --git a/dashboard/css/dashboard.css b/dashboard/css/dashboard.css
new file mode 100644
index 0000000..b93a5e5
--- /dev/null
+++ b/dashboard/css/dashboard.css
@@ -0,0 +1,557 @@
+/* Dashboard Specific Styles */
+
+/* Overview Section */
+.overview-section {
+ margin-bottom: 30px;
+}
+
+.stat-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 20px;
+}
+
+.stat-card {
+ background: linear-gradient(135deg, rgba(91, 75, 138, 0.3) 0%, rgba(46, 37, 71, 0.6) 100%);
+ border: 1px solid rgba(123, 104, 166, 0.3);
+ border-radius: 12px;
+ padding: 24px;
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ transition: all 0.3s ease;
+}
+
+.stat-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 8px 24px rgba(123, 104, 166, 0.3);
+ border-color: var(--secondary-purple);
+}
+
+.stat-icon {
+ width: 60px;
+ height: 60px;
+ background: linear-gradient(135deg, var(--accent-orange) 0%, #ff8555 100%);
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 28px;
+ color: var(--text-light);
+ flex-shrink: 0;
+}
+
+.stat-content {
+ flex: 1;
+}
+
+.stat-content h3 {
+ font-size: 14px;
+ color: var(--text-gray);
+ margin-bottom: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.stat-value {
+ font-size: 32px;
+ font-weight: 700;
+ color: var(--text-light);
+ margin-bottom: 4px;
+}
+
+.stat-label {
+ font-size: 13px;
+ color: var(--text-gray);
+}
+
+/* Agent Status Section */
+.agent-status-section {
+ margin-bottom: 30px;
+}
+
+.agent-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 20px;
+}
+
+.agent-card {
+ background: linear-gradient(145deg, rgba(91, 75, 138, 0.15) 0%, rgba(46, 37, 71, 0.4) 100%);
+ border: 1px solid rgba(123, 104, 166, 0.3);
+ border-radius: 12px;
+ padding: 20px;
+ transition: all 0.3s ease;
+}
+
+.agent-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(123, 104, 166, 0.25);
+ border-color: var(--secondary-purple);
+}
+
+.agent-header {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 1px solid rgba(123, 104, 166, 0.2);
+}
+
+.agent-icon {
+ width: 48px;
+ height: 48px;
+ background: linear-gradient(135deg, var(--primary-purple) 0%, var(--secondary-purple) 100%);
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 22px;
+ color: var(--text-light);
+}
+
+.agent-info {
+ flex: 1;
+}
+
+.agent-info h3 {
+ font-size: 18px;
+ margin-bottom: 4px;
+ color: var(--text-light);
+}
+
+.agent-status {
+ display: inline-block;
+ padding: 2px 10px;
+ border-radius: 10px;
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.agent-status.active {
+ background: rgba(76, 175, 80, 0.2);
+ color: var(--status-success);
+}
+
+.agent-status.inactive {
+ background: rgba(239, 83, 80, 0.2);
+ color: var(--status-error);
+}
+
+.agent-metrics {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.metric {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ background: rgba(91, 75, 138, 0.1);
+ border-radius: 8px;
+}
+
+.metric-label {
+ font-size: 13px;
+ color: var(--text-gray);
+}
+
+.metric-value {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--text-light);
+}
+
+/* Two Column Layout */
+.two-column-layout {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
+ gap: 20px;
+ margin-bottom: 30px;
+}
+
+/* Blast Radius Section */
+.blast-radius-section {
+ margin-bottom: 30px;
+}
+
+.blast-radius-header {
+ margin-bottom: 20px;
+}
+
+.risk-indicator {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 15px 30px;
+ background: linear-gradient(135deg, rgba(255, 107, 53, 0.2) 0%, rgba(255, 107, 53, 0.1) 100%);
+ border: 2px solid var(--accent-orange);
+ border-radius: 12px;
+}
+
+.risk-indicator.high {
+ border-color: var(--status-error);
+ background: linear-gradient(135deg, rgba(239, 83, 80, 0.2) 0%, rgba(239, 83, 80, 0.1) 100%);
+}
+
+.risk-label {
+ font-size: 12px;
+ text-transform: uppercase;
+ color: var(--text-gray);
+ margin-bottom: 4px;
+}
+
+.risk-value {
+ font-size: 20px;
+ font-weight: 700;
+ color: var(--accent-orange);
+}
+
+.blast-radius-viz {
+ margin: 20px 0;
+ min-height: 250px;
+}
+
+.blast-radius-stats {
+ display: flex;
+ justify-content: space-around;
+ margin: 20px 0;
+ padding: 20px 0;
+ border-top: 1px solid rgba(123, 104, 166, 0.2);
+ border-bottom: 1px solid rgba(123, 104, 166, 0.2);
+}
+
+.blast-radius-stats .stat {
+ text-align: center;
+}
+
+.blast-radius-stats .stat i {
+ font-size: 24px;
+ color: var(--accent-orange);
+ margin-bottom: 8px;
+ display: block;
+}
+
+.stat-num {
+ display: block;
+ font-size: 28px;
+ font-weight: 700;
+ color: var(--text-light);
+ margin-bottom: 4px;
+}
+
+.stat-text {
+ display: block;
+ font-size: 12px;
+ color: var(--text-gray);
+ text-transform: uppercase;
+}
+
+.approval-workflow {
+ display: flex;
+ gap: 10px;
+ margin-top: 20px;
+}
+
+.approval-workflow .btn {
+ flex: 1;
+}
+
+/* Region Map Section */
+.region-map-section {
+ margin-bottom: 30px;
+}
+
+.region-map {
+ position: relative;
+ width: 100%;
+ height: 300px;
+ background: linear-gradient(135deg, rgba(91, 75, 138, 0.1) 0%, rgba(46, 37, 71, 0.3) 100%);
+ border-radius: 12px;
+ margin-bottom: 20px;
+ overflow: hidden;
+}
+
+.region {
+ position: absolute;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+}
+
+.region:hover {
+ transform: scale(1.1);
+ z-index: 10;
+}
+
+.region-marker {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ color: var(--text-light);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ animation: regionPulse 2s infinite;
+}
+
+.region-marker.healthy {
+ background: var(--status-success);
+}
+
+.region-marker.warning {
+ background: var(--status-warning);
+}
+
+.region-marker.error {
+ background: var(--status-error);
+}
+
+@keyframes regionPulse {
+ 0%, 100% {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ }
+ 50% {
+ box-shadow: 0 4px 24px rgba(123, 104, 166, 0.6);
+ }
+}
+
+.region-label {
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ margin-top: 8px;
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ white-space: nowrap;
+ color: var(--text-gray);
+}
+
+.region-stats {
+ display: flex;
+ justify-content: center;
+ gap: 30px;
+}
+
+.region-stat {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ color: var(--text-gray);
+}
+
+/* Policy Section */
+.policy-section {
+ margin-bottom: 30px;
+}
+
+.policy-header {
+ display: flex;
+ gap: 15px;
+ margin-bottom: 20px;
+}
+
+.policy-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.policy-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px;
+ background: rgba(91, 75, 138, 0.1);
+ border: 1px solid rgba(123, 104, 166, 0.2);
+ border-radius: 8px;
+ transition: all 0.3s ease;
+}
+
+.policy-item:hover {
+ background: rgba(91, 75, 138, 0.15);
+ border-color: var(--secondary-purple);
+}
+
+.policy-info h4 {
+ font-size: 16px;
+ margin-bottom: 4px;
+ color: var(--text-light);
+}
+
+.policy-info p {
+ font-size: 13px;
+ color: var(--text-gray);
+}
+
+.policy-status {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.policy-count {
+ font-size: 13px;
+ color: var(--text-gray);
+}
+
+/* Cost Section */
+.cost-section {
+ margin-bottom: 30px;
+}
+
+.metrics-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 20px;
+}
+
+.metric-card {
+ padding: 20px;
+}
+
+.metric-card h3 {
+ font-size: 16px;
+ margin-bottom: 15px;
+ color: var(--text-light);
+}
+
+.metric-card canvas {
+ max-height: 150px;
+}
+
+.metric-footer {
+ margin-top: 15px;
+ padding-top: 15px;
+ border-top: 1px solid rgba(123, 104, 166, 0.2);
+ text-align: center;
+}
+
+.trend-up {
+ color: var(--status-success);
+ font-weight: 600;
+ font-size: 14px;
+}
+
+.trend-down {
+ color: var(--status-error);
+ font-weight: 600;
+ font-size: 14px;
+}
+
+.trend-neutral {
+ color: var(--text-gray);
+ font-weight: 600;
+ font-size: 14px;
+}
+
+/* Activity Section */
+.activity-section {
+ margin-bottom: 30px;
+}
+
+.activity-filters {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
+}
+
+.filter-btn {
+ padding: 8px 16px;
+ background: rgba(91, 75, 138, 0.1);
+ border: 1px solid rgba(123, 104, 166, 0.2);
+ border-radius: 20px;
+ color: var(--text-gray);
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.filter-btn:hover {
+ background: rgba(91, 75, 138, 0.2);
+ color: var(--text-light);
+}
+
+.filter-btn.active {
+ background: linear-gradient(135deg, var(--primary-purple) 0%, var(--secondary-purple) 100%);
+ color: var(--text-light);
+ border-color: var(--secondary-purple);
+}
+
+.activity-feed {
+ max-height: 500px;
+ overflow-y: auto;
+}
+
+.activity-item {
+ display: flex;
+ gap: 15px;
+ padding: 16px;
+ border-bottom: 1px solid rgba(123, 104, 166, 0.1);
+ transition: background 0.2s ease;
+}
+
+.activity-item:last-child {
+ border-bottom: none;
+}
+
+.activity-item:hover {
+ background: rgba(91, 75, 138, 0.05);
+}
+
+.activity-icon {
+ width: 40px;
+ height: 40px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ flex-shrink: 0;
+}
+
+.activity-icon.policy {
+ background: rgba(91, 75, 138, 0.3);
+ color: var(--secondary-purple);
+}
+
+.activity-icon.deployment {
+ background: rgba(255, 107, 53, 0.2);
+ color: var(--accent-orange);
+}
+
+.activity-icon.compliance {
+ background: rgba(76, 175, 80, 0.2);
+ color: var(--status-success);
+}
+
+.activity-content {
+ flex: 1;
+}
+
+.activity-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--text-light);
+ margin-bottom: 4px;
+}
+
+.activity-description {
+ font-size: 13px;
+ color: var(--text-gray);
+ margin-bottom: 8px;
+}
+
+.activity-time {
+ font-size: 12px;
+ color: var(--text-gray);
+}
diff --git a/dashboard/css/main.css b/dashboard/css/main.css
new file mode 100644
index 0000000..2c06f9d
--- /dev/null
+++ b/dashboard/css/main.css
@@ -0,0 +1,452 @@
+/* Main Stylesheet - Purple Theme */
+:root {
+ /* Color Palette */
+ --primary-purple: #5B4B8A;
+ --secondary-purple: #7B68A6;
+ --dark-purple: #2E2547;
+ --accent-orange: #FF6B35;
+ --accent-green: #4CAF50;
+ --text-light: #FFFFFF;
+ --text-gray: #B8B8B8;
+ --text-dark: #1A1A1A;
+
+ /* Status Colors */
+ --status-success: #4CAF50;
+ --status-warning: #FFA726;
+ --status-error: #EF5350;
+ --status-info: #42A5F5;
+
+ /* Shadows */
+ --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
+ --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.2);
+ --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.3);
+ --shadow-xl: 0 12px 24px rgba(0, 0, 0, 0.4);
+
+ /* Transitions */
+ --transition-fast: 0.2s ease;
+ --transition-normal: 0.3s ease;
+ --transition-slow: 0.5s ease;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+ background: var(--dark-purple);
+ color: var(--text-light);
+ line-height: 1.6;
+ display: flex;
+ min-height: 100vh;
+}
+
+/* Sidebar Navigation */
+.sidebar {
+ width: 260px;
+ background: linear-gradient(180deg, #3a2e5a 0%, var(--dark-purple) 100%);
+ border-right: 1px solid rgba(123, 104, 166, 0.2);
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ height: 100vh;
+ overflow-y: auto;
+ z-index: 1000;
+}
+
+.logo-container {
+ padding: 30px 20px;
+ text-align: center;
+ border-bottom: 1px solid rgba(123, 104, 166, 0.2);
+}
+
+.logo {
+ width: 60px;
+ height: 60px;
+ margin-bottom: 10px;
+}
+
+.logo-container h2 {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--text-light);
+ margin: 0;
+}
+
+.nav-menu {
+ list-style: none;
+ padding: 20px 0;
+ flex: 1;
+}
+
+.nav-item {
+ margin: 5px 0;
+}
+
+.nav-item a {
+ display: flex;
+ align-items: center;
+ padding: 12px 20px;
+ color: var(--text-gray);
+ text-decoration: none;
+ transition: all var(--transition-fast);
+ border-left: 3px solid transparent;
+}
+
+.nav-item a:hover {
+ background: rgba(123, 104, 166, 0.1);
+ color: var(--text-light);
+ border-left-color: var(--secondary-purple);
+}
+
+.nav-item.active a {
+ background: rgba(123, 104, 166, 0.2);
+ color: var(--text-light);
+ border-left-color: var(--accent-orange);
+}
+
+.nav-item i {
+ width: 24px;
+ margin-right: 12px;
+ font-size: 18px;
+}
+
+.connection-status {
+ padding: 20px;
+ border-top: 1px solid rgba(123, 104, 166, 0.2);
+}
+
+.status-indicator {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ color: var(--text-gray);
+}
+
+.status-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--status-success);
+ animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.5; }
+}
+
+/* Main Content */
+.main-content {
+ margin-left: 260px;
+ flex: 1;
+ padding: 30px;
+ overflow-y: auto;
+}
+
+.page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30px;
+}
+
+.page-header h1 {
+ font-size: 32px;
+ font-weight: 700;
+ background: linear-gradient(135deg, var(--text-light) 0%, var(--secondary-purple) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.header-actions {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.user-menu {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 16px;
+ background: rgba(123, 104, 166, 0.2);
+ border-radius: 20px;
+ cursor: pointer;
+ transition: background var(--transition-fast);
+}
+
+.user-menu:hover {
+ background: rgba(123, 104, 166, 0.3);
+}
+
+.user-menu i {
+ font-size: 20px;
+}
+
+/* Buttons */
+.btn {
+ padding: 10px 20px;
+ border: none;
+ border-radius: 8px;
+ font-size: 14px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.btn-primary {
+ background: linear-gradient(135deg, var(--primary-purple) 0%, var(--secondary-purple) 100%);
+ color: var(--text-light);
+ box-shadow: var(--shadow-sm);
+}
+
+.btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-md);
+}
+
+.btn-secondary {
+ background: rgba(123, 104, 166, 0.2);
+ color: var(--text-light);
+}
+
+.btn-secondary:hover {
+ background: rgba(123, 104, 166, 0.3);
+}
+
+.btn-success {
+ background: var(--status-success);
+ color: var(--text-light);
+}
+
+.btn-success:hover {
+ background: #45a049;
+}
+
+.btn-danger {
+ background: var(--status-error);
+ color: var(--text-light);
+}
+
+.btn-danger:hover {
+ background: #e53935;
+}
+
+.btn-icon {
+ background: transparent;
+ border: 1px solid rgba(123, 104, 166, 0.3);
+ color: var(--text-gray);
+ padding: 8px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+}
+
+.btn-icon:hover {
+ background: rgba(123, 104, 166, 0.2);
+ color: var(--text-light);
+ border-color: var(--secondary-purple);
+}
+
+/* Cards */
+.card {
+ background: linear-gradient(145deg, rgba(91, 75, 138, 0.1) 0%, rgba(46, 37, 71, 0.5) 100%);
+ border: 1px solid rgba(123, 104, 166, 0.2);
+ border-radius: 12px;
+ padding: 24px;
+ box-shadow: var(--shadow-md);
+ transition: all var(--transition-normal);
+}
+
+.card:hover {
+ box-shadow: var(--shadow-lg);
+ border-color: rgba(123, 104, 166, 0.4);
+}
+
+/* Section Titles */
+.section-title {
+ font-size: 20px;
+ font-weight: 700;
+ margin-bottom: 20px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: var(--text-light);
+}
+
+.section-title i {
+ color: var(--accent-orange);
+}
+
+/* Badges */
+.badge {
+ display: inline-block;
+ padding: 4px 12px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.badge.success {
+ background: rgba(76, 175, 80, 0.2);
+ color: var(--status-success);
+ border: 1px solid var(--status-success);
+}
+
+.badge.warning {
+ background: rgba(255, 167, 38, 0.2);
+ color: var(--status-warning);
+ border: 1px solid var(--status-warning);
+}
+
+.badge.error {
+ background: rgba(239, 83, 80, 0.2);
+ color: var(--status-error);
+ border: 1px solid var(--status-error);
+}
+
+.badge.info {
+ background: rgba(66, 165, 245, 0.2);
+ color: var(--status-info);
+ border: 1px solid var(--status-info);
+}
+
+/* Status Badges */
+.status-badge {
+ padding: 6px 16px;
+ border-radius: 20px;
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ display: inline-block;
+}
+
+.status-badge.operational {
+ background: rgba(76, 175, 80, 0.2);
+ color: var(--status-success);
+ border: 2px solid var(--status-success);
+}
+
+.status-badge.degraded {
+ background: rgba(255, 167, 38, 0.2);
+ color: var(--status-warning);
+ border: 2px solid var(--status-warning);
+}
+
+.status-badge.down {
+ background: rgba(239, 83, 80, 0.2);
+ color: var(--status-error);
+ border: 2px solid var(--status-error);
+}
+
+/* Form Elements */
+input[type="text"],
+input[type="email"],
+input[type="password"],
+select,
+textarea {
+ width: 100%;
+ padding: 12px 16px;
+ background: rgba(91, 75, 138, 0.1);
+ border: 1px solid rgba(123, 104, 166, 0.3);
+ border-radius: 8px;
+ color: var(--text-light);
+ font-size: 14px;
+ transition: all var(--transition-fast);
+}
+
+input:focus,
+select:focus,
+textarea:focus {
+ outline: none;
+ border-color: var(--secondary-purple);
+ background: rgba(91, 75, 138, 0.2);
+}
+
+input::placeholder {
+ color: var(--text-gray);
+}
+
+/* Search Box */
+.search-box {
+ position: relative;
+ flex: 1;
+ max-width: 400px;
+}
+
+.search-box i {
+ position: absolute;
+ left: 16px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--text-gray);
+}
+
+.search-box input {
+ padding-left: 45px;
+}
+
+/* Utility Classes */
+.text-center {
+ text-align: center;
+}
+
+.text-right {
+ text-align: right;
+}
+
+.mt-1 { margin-top: 10px; }
+.mt-2 { margin-top: 20px; }
+.mt-3 { margin-top: 30px; }
+
+.mb-1 { margin-bottom: 10px; }
+.mb-2 { margin-bottom: 20px; }
+.mb-3 { margin-bottom: 30px; }
+
+.success { color: var(--status-success); }
+.warning { color: var(--status-warning); }
+.error { color: var(--status-error); }
+.info { color: var(--status-info); }
+
+/* Loading Spinner */
+.spinner {
+ border: 3px solid rgba(123, 104, 166, 0.3);
+ border-top: 3px solid var(--secondary-purple);
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+/* Scrollbar Styling */
+::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+}
+
+::-webkit-scrollbar-track {
+ background: rgba(91, 75, 138, 0.1);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--secondary-purple);
+ border-radius: 5px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--primary-purple);
+}
diff --git a/dashboard/css/responsive.css b/dashboard/css/responsive.css
new file mode 100644
index 0000000..c2a4c9c
--- /dev/null
+++ b/dashboard/css/responsive.css
@@ -0,0 +1,245 @@
+/* Responsive Styles */
+
+/* Tablet and below */
+@media (max-width: 1024px) {
+ .stat-cards {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .agent-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .two-column-layout {
+ grid-template-columns: 1fr;
+ }
+
+ .metrics-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+/* Mobile */
+@media (max-width: 768px) {
+ body {
+ flex-direction: column;
+ }
+
+ .sidebar {
+ width: 100%;
+ height: auto;
+ position: relative;
+ border-right: none;
+ border-bottom: 1px solid rgba(123, 104, 166, 0.2);
+ }
+
+ .logo-container {
+ padding: 20px;
+ }
+
+ .logo-container h2 {
+ font-size: 14px;
+ }
+
+ .nav-menu {
+ display: flex;
+ overflow-x: auto;
+ padding: 10px 0;
+ }
+
+ .nav-item {
+ margin: 0 5px;
+ }
+
+ .nav-item a {
+ flex-direction: column;
+ padding: 10px 15px;
+ border-left: none;
+ border-bottom: 3px solid transparent;
+ white-space: nowrap;
+ }
+
+ .nav-item.active a,
+ .nav-item a:hover {
+ border-left: none;
+ border-bottom-color: var(--accent-orange);
+ }
+
+ .nav-item i {
+ margin-right: 0;
+ margin-bottom: 4px;
+ }
+
+ .connection-status {
+ display: none;
+ }
+
+ .main-content {
+ margin-left: 0;
+ padding: 20px 15px;
+ }
+
+ .page-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ .page-header h1 {
+ font-size: 24px;
+ }
+
+ .header-actions {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .stat-cards {
+ grid-template-columns: 1fr;
+ }
+
+ .stat-card {
+ padding: 20px;
+ }
+
+ .stat-icon {
+ width: 50px;
+ height: 50px;
+ font-size: 24px;
+ }
+
+ .stat-value {
+ font-size: 28px;
+ }
+
+ .agent-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .two-column-layout {
+ grid-template-columns: 1fr;
+ }
+
+ .policy-header {
+ flex-direction: column;
+ }
+
+ .search-box {
+ max-width: 100%;
+ }
+
+ .metrics-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .activity-filters {
+ overflow-x: auto;
+ }
+
+ .filter-btn {
+ white-space: nowrap;
+ }
+
+ .blast-radius-stats {
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .approval-workflow {
+ flex-direction: column;
+ }
+
+ .region-stats {
+ flex-direction: column;
+ gap: 10px;
+ }
+}
+
+/* Small Mobile */
+@media (max-width: 480px) {
+ .page-header h1 {
+ font-size: 20px;
+ }
+
+ .stat-value {
+ font-size: 24px;
+ }
+
+ .stat-content h3 {
+ font-size: 12px;
+ }
+
+ .agent-header {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .agent-controls {
+ align-self: flex-end;
+ }
+
+ .policy-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ }
+
+ .policy-status {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .region-map {
+ height: 200px;
+ }
+
+ .region-marker {
+ width: 30px;
+ height: 30px;
+ font-size: 16px;
+ }
+
+ .region-label {
+ font-size: 9px;
+ }
+}
+
+/* Print Styles */
+@media print {
+ .sidebar,
+ .header-actions,
+ .agent-controls,
+ .approval-workflow,
+ .activity-filters {
+ display: none;
+ }
+
+ .main-content {
+ margin-left: 0;
+ }
+
+ .card {
+ break-inside: avoid;
+ }
+}
+
+/* High DPI / Retina Displays */
+@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
+ .logo {
+ image-rendering: -webkit-optimize-contrast;
+ }
+}
+
+/* Dark Mode Support (for future enhancement) */
+@media (prefers-color-scheme: dark) {
+ /* Already in dark mode by default */
+}
+
+/* Reduced Motion */
+@media (prefers-reduced-motion: reduce) {
+ * {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
diff --git a/dashboard/data/mock-data.json b/dashboard/data/mock-data.json
new file mode 100644
index 0000000..843b284
--- /dev/null
+++ b/dashboard/data/mock-data.json
@@ -0,0 +1,281 @@
+{
+ "platform": {
+ "status": "operational",
+ "activeAgents": 4,
+ "queueSize": 12,
+ "systemHealth": 98
+ },
+ "agents": [
+ {
+ "id": "policy",
+ "name": "Policy Agent",
+ "status": "active",
+ "metrics": {
+ "policiesEnforced": 247,
+ "violations": 3,
+ "lastCheck": "2 min ago"
+ }
+ },
+ {
+ "id": "intent",
+ "name": "Intent Agent",
+ "status": "active",
+ "metrics": {
+ "activeIntents": 8,
+ "scriptsGenerated": 156,
+ "queueSize": 5
+ }
+ },
+ {
+ "id": "deployment",
+ "name": "Deployment Agent",
+ "status": "active",
+ "metrics": {
+ "activeDeployments": 12,
+ "regions": 5,
+ "successRate": "99.2%"
+ }
+ },
+ {
+ "id": "compliance",
+ "name": "Compliance Agent",
+ "status": "active",
+ "metrics": {
+ "complianceScore": "96%",
+ "auditEvents": 1234,
+ "markers": 45
+ }
+ }
+ ],
+ "activities": [
+ {
+ "type": "policy",
+ "title": "Policy Violation Detected",
+ "description": "Cost threshold exceeded in us-east-1 region",
+ "time": "2 minutes ago"
+ },
+ {
+ "type": "deployment",
+ "title": "Deployment Completed",
+ "description": "Successfully deployed version 2.1.4 to production",
+ "time": "15 minutes ago"
+ },
+ {
+ "type": "compliance",
+ "title": "Compliance Check Passed",
+ "description": "All resources meet compliance requirements",
+ "time": "1 hour ago"
+ },
+ {
+ "type": "policy",
+ "title": "Policy Updated",
+ "description": "Resource quota policy modified by admin",
+ "time": "2 hours ago"
+ },
+ {
+ "type": "deployment",
+ "title": "Deployment Initiated",
+ "description": "Starting deployment to eu-central-1",
+ "time": "3 hours ago"
+ },
+ {
+ "type": "compliance",
+ "title": "Audit Event Recorded",
+ "description": "Configuration change logged for security group sg-12345",
+ "time": "4 hours ago"
+ }
+ ],
+ "policies": [
+ {
+ "id": "pol-1",
+ "name": "Resource Quota Enforcement",
+ "description": "Ensures CPU and memory limits are not exceeded",
+ "status": "active",
+ "enforced": 247,
+ "rules": [
+ "cpu_limit < 80%",
+ "memory_limit < 90%"
+ ]
+ },
+ {
+ "id": "pol-2",
+ "name": "Security Group Validation",
+ "description": "Validates security group rules against best practices",
+ "status": "active",
+ "enforced": 89,
+ "rules": [
+ "no_public_ssh_access",
+ "encrypted_traffic_only"
+ ]
+ },
+ {
+ "id": "pol-3",
+ "name": "Cost Threshold Alert",
+ "description": "Alerts when spending exceeds budget thresholds",
+ "status": "warning",
+ "violations": 3,
+ "checks": 156,
+ "rules": [
+ "daily_cost < $500",
+ "monthly_cost < $15000"
+ ]
+ },
+ {
+ "id": "pol-4",
+ "name": "Data Encryption Policy",
+ "description": "Ensures all data at rest is encrypted",
+ "status": "active",
+ "enforced": 312,
+ "rules": [
+ "s3_encryption_enabled",
+ "ebs_encryption_enabled",
+ "rds_encryption_enabled"
+ ]
+ }
+ ],
+ "metrics": {
+ "bandwidth": {
+ "labels": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+ "data": [65, 59, 80, 81, 56, 55, 40]
+ },
+ "compute": {
+ "labels": ["00:00", "04:00", "08:00", "12:00", "16:00", "20:00"],
+ "data": [75, 82, 88, 91, 85, 78]
+ },
+ "storage": {
+ "used": 67,
+ "free": 33
+ },
+ "costTrend": {
+ "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
+ "data": [1200, 1150, 1100, 1050, 1080, 1020]
+ }
+ },
+ "regions": [
+ {
+ "id": "us-east",
+ "name": "US East",
+ "status": "healthy",
+ "instances": 45,
+ "cpuUsage": 67,
+ "latency": 12
+ },
+ {
+ "id": "us-west",
+ "name": "US West",
+ "status": "healthy",
+ "instances": 38,
+ "cpuUsage": 72,
+ "latency": 15
+ },
+ {
+ "id": "eu-central",
+ "name": "EU Central",
+ "status": "healthy",
+ "instances": 52,
+ "cpuUsage": 58,
+ "latency": 25
+ },
+ {
+ "id": "asia-pacific",
+ "name": "Asia Pacific",
+ "status": "warning",
+ "instances": 29,
+ "cpuUsage": 89,
+ "latency": 45
+ },
+ {
+ "id": "south-america",
+ "name": "South America",
+ "status": "healthy",
+ "instances": 18,
+ "cpuUsage": 45,
+ "latency": 35
+ }
+ ],
+ "blastRadius": {
+ "riskLevel": "medium",
+ "affectedResources": 24,
+ "impactedUsers": 156,
+ "estimatedDowntime": "2-5 minutes",
+ "categories": ["Compute", "Storage", "Network", "Security"],
+ "values": [12, 5, 4, 3],
+ "details": {
+ "compute": ["ec2-instance-1", "ec2-instance-2", "lambda-function-1"],
+ "storage": ["s3-bucket-prod", "ebs-volume-1"],
+ "network": ["load-balancer-1", "vpc-endpoint-1"],
+ "security": ["security-group-1", "iam-role-1"]
+ }
+ },
+ "scripts": [
+ {
+ "id": "script-1",
+ "name": "Auto-Scale Infrastructure",
+ "category": "Automation",
+ "description": "Automatically scales compute resources based on demand",
+ "language": "Python",
+ "cloudProvider": "AWS",
+ "downloads": 1234
+ },
+ {
+ "id": "script-2",
+ "name": "Cost Optimizer",
+ "category": "Optimization",
+ "description": "Identifies and terminates unused resources",
+ "language": "JavaScript",
+ "cloudProvider": "Multi-Cloud",
+ "downloads": 892
+ },
+ {
+ "id": "script-3",
+ "name": "Security Audit",
+ "category": "Security",
+ "description": "Runs comprehensive security checks across infrastructure",
+ "language": "Go",
+ "cloudProvider": "Azure",
+ "downloads": 567
+ }
+ ],
+ "compliance": {
+ "score": 96,
+ "frameworks": [
+ {
+ "name": "SOC 2",
+ "compliance": 98,
+ "controls": 156,
+ "passed": 153,
+ "failed": 3
+ },
+ {
+ "name": "HIPAA",
+ "compliance": 95,
+ "controls": 89,
+ "passed": 85,
+ "failed": 4
+ },
+ {
+ "name": "PCI DSS",
+ "compliance": 94,
+ "controls": 67,
+ "passed": 63,
+ "failed": 4
+ }
+ ],
+ "markers": [
+ {
+ "id": "marker-1",
+ "resource": "s3://production-data",
+ "requirement": "Encryption at rest",
+ "status": "compliant",
+ "lastChecked": "2024-02-15T07:30:00Z"
+ },
+ {
+ "id": "marker-2",
+ "resource": "rds://prod-db",
+ "requirement": "Automated backups",
+ "status": "compliant",
+ "lastChecked": "2024-02-15T07:25:00Z"
+ }
+ ]
+ }
+}
diff --git a/dashboard/index.html b/dashboard/index.html
new file mode 100644
index 0000000..5d7db8b
--- /dev/null
+++ b/dashboard/index.html
@@ -0,0 +1,469 @@
+
+
+
+
+
+ Multi-Agent Infrastructure Control Platform - Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Active Agents
+
4
+
of 4 agents online
+
+
+
+
+
+
+
+
Processing Queue
+
12
+
items pending
+
+
+
+
+
+
+
+
System Health
+
98%
+
excellent condition
+
+
+
+
+
+
+
+
+ Agent Status
+
+
+
+
+
+
+ Policies Enforced
+ 247
+
+
+ Violations
+ 3
+
+
+ Last Check
+ 2 min ago
+
+
+
+
+
+
+
+
+ Active Intents
+ 8
+
+
+ Scripts Generated
+ 156
+
+
+ Queue Size
+ 5
+
+
+
+
+
+
+
+
+ Active Deployments
+ 12
+
+
+ Regions
+ 5
+
+
+ Success Rate
+ 99.2%
+
+
+
+
+
+
+
+
+ Compliance Score
+ 96%
+
+
+ Audit Events
+ 1,234
+
+
+ Markers
+ 45
+
+
+
+
+
+
+
+
+
+
+
+ Blast Radius Prediction
+
+
+
+
+
+
+
+
+
+ 24
+ Affected Resources
+
+
+
+ 156
+ Impacted Users
+
+
+
+
+
+
+
+
+
+
+
+
+ Multi-Region Infrastructure
+
+
+
+
+
+
+ 4 Healthy
+
+
+
+ 1 Warning
+
+
+
+ 0 Down
+
+
+
+
+
+
+
+
+
+ Policy Enforcement
+
+
+
+
+
+
+
Resource Quota Enforcement
+
Ensures CPU and memory limits are not exceeded
+
+
+ Active
+ 247 enforced
+
+
+
+
+
Security Group Validation
+
Validates security group rules against best practices
+
+
+ Active
+ 89 enforced
+
+
+
+
+
Cost Threshold Alert
+
Alerts when spending exceeds budget thresholds
+
+
+ 3 violations
+ 156 checks
+
+
+
+
+
+
+
+
+
+ Cost Optimization
+
+
+
+
Bandwidth Savings
+
+
+
+
+
Compute Efficiency
+
+
+
+
+
Storage Rebalancing
+
+
+
+
+
Cost Trends
+
+
+
+
+
+
+
+
+
+ Recent Activities
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dashboard/js/agents.js b/dashboard/js/agents.js
new file mode 100644
index 0000000..3d9cb20
--- /dev/null
+++ b/dashboard/js/agents.js
@@ -0,0 +1,207 @@
+// Agent Management Module
+class AgentManager {
+ constructor() {
+ this.agents = [];
+ this.updateInterval = null;
+ }
+
+ async initialize() {
+ await this.loadAgents();
+ this.setupEventListeners();
+ this.startAutoUpdate();
+ }
+
+ async loadAgents() {
+ try {
+ const data = await api.getDefaultMockData();
+ this.agents = data.agents;
+ this.updateAgentCards();
+ } catch (error) {
+ console.error('Failed to load agents:', error);
+ }
+ }
+
+ updateAgentCards() {
+ this.agents.forEach(agent => {
+ const card = document.querySelector(`.agent-card[data-agent="${agent.id}"]`);
+ if (!card) return;
+
+ // Update status
+ const statusElement = card.querySelector('.agent-status');
+ if (statusElement) {
+ statusElement.textContent = agent.status.charAt(0).toUpperCase() + agent.status.slice(1);
+ statusElement.className = `agent-status ${agent.status}`;
+ }
+
+ // Update metrics
+ const metrics = card.querySelectorAll('.metric-value');
+ const metricValues = Object.values(agent.metrics);
+
+ metrics.forEach((metric, index) => {
+ if (metricValues[index] !== undefined) {
+ metric.textContent = metricValues[index];
+ }
+ });
+ });
+ }
+
+ setupEventListeners() {
+ // Agent control buttons
+ document.querySelectorAll('.agent-card .btn-icon').forEach(button => {
+ button.addEventListener('click', (e) => {
+ const card = e.target.closest('.agent-card');
+ const agentId = card.dataset.agent;
+ this.toggleAgent(agentId);
+ });
+ });
+
+ // Listen to WebSocket updates
+ wsManager.on('agentStatus', (data) => {
+ this.handleAgentStatusUpdate(data);
+ });
+ }
+
+ async toggleAgent(agentId) {
+ const agent = this.agents.find(a => a.id === agentId);
+ if (!agent) return;
+
+ try {
+ if (agent.status === 'active') {
+ await api.stopAgent(agentId);
+ agent.status = 'inactive';
+ this.showNotification(`${agent.name} stopped`, 'info');
+ } else {
+ await api.startAgent(agentId);
+ agent.status = 'active';
+ this.showNotification(`${agent.name} started`, 'success');
+ }
+
+ this.updateAgentCards();
+ this.updateActiveAgentsCount();
+ } catch (error) {
+ console.error(`Failed to toggle agent ${agentId}:`, error);
+ this.showNotification('Failed to update agent', 'error');
+ }
+ }
+
+ handleAgentStatusUpdate(data) {
+ const agent = this.agents.find(a => a.id === data.agentId);
+ if (!agent) return;
+
+ agent.status = data.status;
+ this.updateAgentCards();
+ this.updateActiveAgentsCount();
+ }
+
+ updateActiveAgentsCount() {
+ const activeCount = this.agents.filter(a => a.status === 'active').length;
+ const element = document.getElementById('activeAgents');
+ if (element) {
+ element.textContent = activeCount;
+ }
+ }
+
+ startAutoUpdate() {
+ // Update agent metrics every 5 seconds
+ this.updateInterval = setInterval(async () => {
+ await this.loadAgents();
+ }, 5000);
+ }
+
+ stopAutoUpdate() {
+ if (this.updateInterval) {
+ clearInterval(this.updateInterval);
+ this.updateInterval = null;
+ }
+ }
+
+ showNotification(message, type = 'info') {
+ // Create notification element
+ const notification = document.createElement('div');
+ notification.className = `notification notification-${type}`;
+ notification.innerHTML = `
+
+ ${message}
+ `;
+
+ notification.style.cssText = `
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ padding: 15px 20px;
+ background: ${this.getNotificationColor(type)};
+ color: white;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ z-index: 10000;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ animation: slideIn 0.3s ease;
+ `;
+
+ document.body.appendChild(notification);
+
+ // Remove after 3 seconds
+ setTimeout(() => {
+ notification.style.animation = 'slideOut 0.3s ease';
+ setTimeout(() => {
+ document.body.removeChild(notification);
+ }, 300);
+ }, 3000);
+ }
+
+ getNotificationIcon(type) {
+ const icons = {
+ success: 'check-circle',
+ error: 'exclamation-circle',
+ warning: 'exclamation-triangle',
+ info: 'info-circle'
+ };
+ return icons[type] || 'info-circle';
+ }
+
+ getNotificationColor(type) {
+ const colors = {
+ success: 'rgba(76, 175, 80, 0.95)',
+ error: 'rgba(239, 83, 80, 0.95)',
+ warning: 'rgba(255, 167, 38, 0.95)',
+ info: 'rgba(66, 165, 245, 0.95)'
+ };
+ return colors[type] || colors.info;
+ }
+
+ destroy() {
+ this.stopAutoUpdate();
+ }
+}
+
+// Add notification animations
+const style = document.createElement('style');
+style.textContent = `
+ @keyframes slideIn {
+ from {
+ transform: translateX(400px);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ }
+
+ @keyframes slideOut {
+ from {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ to {
+ transform: translateX(400px);
+ opacity: 0;
+ }
+ }
+`;
+document.head.appendChild(style);
+
+// Export agent manager instance
+const agentManager = new AgentManager();
diff --git a/dashboard/js/api.js b/dashboard/js/api.js
new file mode 100644
index 0000000..06524f9
--- /dev/null
+++ b/dashboard/js/api.js
@@ -0,0 +1,252 @@
+// API Integration Layer
+class API {
+ constructor() {
+ this.baseUrl = '/api'; // Change to actual API endpoint
+ this.mockMode = true; // Set to false when real API is available
+ }
+
+ // Generic request method
+ async request(endpoint, options = {}) {
+ if (this.mockMode) {
+ return this.mockRequest(endpoint, options);
+ }
+
+ try {
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers,
+ },
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return await response.json();
+ } catch (error) {
+ console.error('API request failed:', error);
+ throw error;
+ }
+ }
+
+ // Mock request handler for development
+ async mockRequest(endpoint, options = {}) {
+ // Simulate network delay
+ await new Promise(resolve => setTimeout(resolve, 300));
+
+ // Load mock data
+ const mockData = await this.loadMockData();
+
+ // Route mock requests
+ if (endpoint.includes('/agents')) {
+ return mockData.agents;
+ } else if (endpoint.includes('/activities')) {
+ return mockData.activities;
+ } else if (endpoint.includes('/policies')) {
+ return mockData.policies;
+ } else if (endpoint.includes('/metrics')) {
+ return mockData.metrics;
+ } else if (endpoint.includes('/regions')) {
+ return mockData.regions;
+ } else if (endpoint.includes('/blast-radius')) {
+ return mockData.blastRadius;
+ }
+
+ return mockData;
+ }
+
+ // Load mock data from JSON file
+ async loadMockData() {
+ try {
+ const response = await fetch('data/mock-data.json');
+ return await response.json();
+ } catch (error) {
+ console.error('Failed to load mock data:', error);
+ return this.getDefaultMockData();
+ }
+ }
+
+ // Default mock data if JSON file is not available
+ getDefaultMockData() {
+ return {
+ platform: {
+ status: 'operational',
+ activeAgents: 4,
+ queueSize: 12,
+ systemHealth: 98
+ },
+ agents: [
+ {
+ id: 'policy',
+ name: 'Policy Agent',
+ status: 'active',
+ metrics: {
+ policiesEnforced: 247,
+ violations: 3,
+ lastCheck: '2 min ago'
+ }
+ },
+ {
+ id: 'intent',
+ name: 'Intent Agent',
+ status: 'active',
+ metrics: {
+ activeIntents: 8,
+ scriptsGenerated: 156,
+ queueSize: 5
+ }
+ },
+ {
+ id: 'deployment',
+ name: 'Deployment Agent',
+ status: 'active',
+ metrics: {
+ activeDeployments: 12,
+ regions: 5,
+ successRate: '99.2%'
+ }
+ },
+ {
+ id: 'compliance',
+ name: 'Compliance Agent',
+ status: 'active',
+ metrics: {
+ complianceScore: '96%',
+ auditEvents: 1234,
+ markers: 45
+ }
+ }
+ ],
+ activities: [
+ {
+ type: 'policy',
+ title: 'Policy Violation Detected',
+ description: 'Cost threshold exceeded in us-east-1',
+ time: '2 minutes ago'
+ },
+ {
+ type: 'deployment',
+ title: 'Deployment Completed',
+ description: 'Successfully deployed version 2.1.4 to production',
+ time: '15 minutes ago'
+ },
+ {
+ type: 'compliance',
+ title: 'Compliance Check Passed',
+ description: 'All resources meet compliance requirements',
+ time: '1 hour ago'
+ }
+ ],
+ policies: [
+ {
+ id: 'pol-1',
+ name: 'Resource Quota Enforcement',
+ description: 'Ensures CPU and memory limits are not exceeded',
+ status: 'active',
+ enforced: 247
+ },
+ {
+ id: 'pol-2',
+ name: 'Security Group Validation',
+ description: 'Validates security group rules against best practices',
+ status: 'active',
+ enforced: 89
+ },
+ {
+ id: 'pol-3',
+ name: 'Cost Threshold Alert',
+ description: 'Alerts when spending exceeds budget thresholds',
+ status: 'warning',
+ violations: 3,
+ checks: 156
+ }
+ ],
+ metrics: {
+ bandwidth: {
+ labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+ data: [65, 59, 80, 81, 56, 55, 40]
+ },
+ compute: {
+ labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
+ data: [75, 82, 88, 91, 85, 78]
+ },
+ storage: {
+ used: 67,
+ free: 33
+ },
+ costTrend: {
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
+ data: [1200, 1150, 1100, 1050, 1080, 1020]
+ }
+ },
+ regions: [
+ { id: 'us-east', name: 'US East', status: 'healthy' },
+ { id: 'us-west', name: 'US West', status: 'healthy' },
+ { id: 'eu-central', name: 'EU Central', status: 'healthy' },
+ { id: 'asia-pacific', name: 'Asia Pacific', status: 'warning' },
+ { id: 'south-america', name: 'South America', status: 'healthy' }
+ ],
+ blastRadius: {
+ riskLevel: 'medium',
+ affectedResources: 24,
+ impactedUsers: 156,
+ categories: ['Compute', 'Storage', 'Network', 'Security'],
+ values: [12, 5, 4, 3]
+ }
+ };
+ }
+
+ // API Methods
+ async getPlatformStatus() {
+ return this.request('/platform/status');
+ }
+
+ async getAgents() {
+ return this.request('/agents');
+ }
+
+ async getAgentStatus(agentId) {
+ return this.request(`/agents/${agentId}`);
+ }
+
+ async startAgent(agentId) {
+ return this.request(`/agents/${agentId}/start`, { method: 'POST' });
+ }
+
+ async stopAgent(agentId) {
+ return this.request(`/agents/${agentId}/stop`, { method: 'POST' });
+ }
+
+ async getActivities(filter = 'all') {
+ return this.request(`/activities?filter=${filter}`);
+ }
+
+ async getPolicies() {
+ return this.request('/policies');
+ }
+
+ async getMetrics() {
+ return this.request('/metrics');
+ }
+
+ async getRegions() {
+ return this.request('/regions');
+ }
+
+ async getBlastRadius() {
+ return this.request('/blast-radius');
+ }
+
+ async simulatePolicy(policyId) {
+ return this.request(`/policies/${policyId}/simulate`, { method: 'POST' });
+ }
+
+ async exportComplianceReport(format = 'pdf') {
+ return this.request(`/compliance/export?format=${format}`);
+ }
+}
+
+// Export API instance
+const api = new API();
diff --git a/dashboard/js/charts.js b/dashboard/js/charts.js
new file mode 100644
index 0000000..ecdbbdc
--- /dev/null
+++ b/dashboard/js/charts.js
@@ -0,0 +1,320 @@
+// Chart.js Configurations
+class ChartManager {
+ constructor() {
+ this.charts = {};
+ this.defaultOptions = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ labels: {
+ color: '#B8B8B8',
+ font: {
+ family: 'Inter, sans-serif'
+ }
+ }
+ }
+ },
+ scales: {
+ y: {
+ ticks: {
+ color: '#B8B8B8'
+ },
+ grid: {
+ color: 'rgba(123, 104, 166, 0.1)'
+ }
+ },
+ x: {
+ ticks: {
+ color: '#B8B8B8'
+ },
+ grid: {
+ color: 'rgba(123, 104, 166, 0.1)'
+ }
+ }
+ }
+ };
+ }
+
+ initializeCharts(metricsData) {
+ this.createBlastRadiusChart();
+ this.createBandwidthChart(metricsData.bandwidth);
+ this.createComputeChart(metricsData.compute);
+ this.createStorageChart(metricsData.storage);
+ this.createCostTrendChart(metricsData.costTrend);
+ }
+
+ createBlastRadiusChart() {
+ const ctx = document.getElementById('blastRadiusChart');
+ if (!ctx) return;
+
+ this.charts.blastRadius = new Chart(ctx, {
+ type: 'doughnut',
+ data: {
+ labels: ['Compute', 'Storage', 'Network', 'Security'],
+ datasets: [{
+ data: [12, 5, 4, 3],
+ backgroundColor: [
+ 'rgba(91, 75, 138, 0.8)',
+ 'rgba(123, 104, 166, 0.8)',
+ 'rgba(255, 107, 53, 0.8)',
+ 'rgba(76, 175, 80, 0.8)'
+ ],
+ borderColor: [
+ 'rgb(91, 75, 138)',
+ 'rgb(123, 104, 166)',
+ 'rgb(255, 107, 53)',
+ 'rgb(76, 175, 80)'
+ ],
+ borderWidth: 2
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ position: 'bottom',
+ labels: {
+ color: '#B8B8B8',
+ padding: 15,
+ font: {
+ family: 'Inter, sans-serif',
+ size: 12
+ }
+ }
+ },
+ tooltip: {
+ backgroundColor: 'rgba(46, 37, 71, 0.95)',
+ titleColor: '#FFFFFF',
+ bodyColor: '#B8B8B8',
+ borderColor: 'rgba(123, 104, 166, 0.5)',
+ borderWidth: 1,
+ padding: 12,
+ displayColors: true
+ }
+ }
+ }
+ });
+ }
+
+ createBandwidthChart(data) {
+ const ctx = document.getElementById('bandwidthChart');
+ if (!ctx) return;
+
+ this.charts.bandwidth = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: data.labels,
+ datasets: [{
+ label: 'Bandwidth Savings (GB)',
+ data: data.data,
+ borderColor: 'rgb(76, 175, 80)',
+ backgroundColor: 'rgba(76, 175, 80, 0.1)',
+ tension: 0.4,
+ fill: true,
+ pointBackgroundColor: 'rgb(76, 175, 80)',
+ pointBorderColor: '#fff',
+ pointBorderWidth: 2,
+ pointRadius: 4
+ }]
+ },
+ options: {
+ ...this.defaultOptions,
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ backgroundColor: 'rgba(46, 37, 71, 0.95)',
+ titleColor: '#FFFFFF',
+ bodyColor: '#B8B8B8',
+ borderColor: 'rgba(76, 175, 80, 0.5)',
+ borderWidth: 1
+ }
+ }
+ }
+ });
+ }
+
+ createComputeChart(data) {
+ const ctx = document.getElementById('computeChart');
+ if (!ctx) return;
+
+ this.charts.compute = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: data.labels,
+ datasets: [{
+ label: 'Utilization (%)',
+ data: data.data,
+ backgroundColor: 'rgba(91, 75, 138, 0.8)',
+ borderColor: 'rgb(91, 75, 138)',
+ borderWidth: 2,
+ borderRadius: 6
+ }]
+ },
+ options: {
+ ...this.defaultOptions,
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ backgroundColor: 'rgba(46, 37, 71, 0.95)',
+ titleColor: '#FFFFFF',
+ bodyColor: '#B8B8B8'
+ }
+ },
+ scales: {
+ ...this.defaultOptions.scales,
+ y: {
+ ...this.defaultOptions.scales.y,
+ max: 100,
+ ticks: {
+ color: '#B8B8B8',
+ callback: function(value) {
+ return value + '%';
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ createStorageChart(data) {
+ const ctx = document.getElementById('storageChart');
+ if (!ctx) return;
+
+ this.charts.storage = new Chart(ctx, {
+ type: 'doughnut',
+ data: {
+ labels: ['Used', 'Free'],
+ datasets: [{
+ data: [data.used, data.free],
+ backgroundColor: [
+ 'rgba(255, 107, 53, 0.8)',
+ 'rgba(123, 104, 166, 0.3)'
+ ],
+ borderColor: [
+ 'rgb(255, 107, 53)',
+ 'rgb(123, 104, 166)'
+ ],
+ borderWidth: 2
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ position: 'bottom',
+ labels: {
+ color: '#B8B8B8',
+ font: {
+ family: 'Inter, sans-serif',
+ size: 12
+ }
+ }
+ },
+ tooltip: {
+ backgroundColor: 'rgba(46, 37, 71, 0.95)',
+ titleColor: '#FFFFFF',
+ bodyColor: '#B8B8B8',
+ callbacks: {
+ label: function(context) {
+ return context.label + ': ' + context.parsed + '%';
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ createCostTrendChart(data) {
+ const ctx = document.getElementById('costTrendChart');
+ if (!ctx) return;
+
+ this.charts.costTrend = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: data.labels,
+ datasets: [{
+ label: 'Cost ($)',
+ data: data.data,
+ borderColor: 'rgb(255, 107, 53)',
+ backgroundColor: 'rgba(255, 107, 53, 0.1)',
+ tension: 0.4,
+ fill: true,
+ pointBackgroundColor: 'rgb(255, 107, 53)',
+ pointBorderColor: '#fff',
+ pointBorderWidth: 2,
+ pointRadius: 4
+ }]
+ },
+ options: {
+ ...this.defaultOptions,
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ backgroundColor: 'rgba(46, 37, 71, 0.95)',
+ titleColor: '#FFFFFF',
+ bodyColor: '#B8B8B8',
+ callbacks: {
+ label: function(context) {
+ return '$' + context.parsed.y.toLocaleString();
+ }
+ }
+ }
+ },
+ scales: {
+ ...this.defaultOptions.scales,
+ y: {
+ ...this.defaultOptions.scales.y,
+ ticks: {
+ color: '#B8B8B8',
+ callback: function(value) {
+ return '$' + value;
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ updateChart(chartName, newData) {
+ const chart = this.charts[chartName];
+ if (!chart) return;
+
+ if (newData.labels) {
+ chart.data.labels = newData.labels;
+ }
+ if (newData.datasets) {
+ chart.data.datasets = newData.datasets;
+ }
+
+ chart.update();
+ }
+
+ destroyChart(chartName) {
+ const chart = this.charts[chartName];
+ if (chart) {
+ chart.destroy();
+ delete this.charts[chartName];
+ }
+ }
+
+ destroyAllCharts() {
+ Object.keys(this.charts).forEach(chartName => {
+ this.destroyChart(chartName);
+ });
+ }
+}
+
+// Export chart manager instance
+const chartManager = new ChartManager();
diff --git a/dashboard/js/dashboard.js b/dashboard/js/dashboard.js
new file mode 100644
index 0000000..6cce17a
--- /dev/null
+++ b/dashboard/js/dashboard.js
@@ -0,0 +1,272 @@
+// Main Dashboard JavaScript
+class Dashboard {
+ constructor() {
+ this.currentFilter = 'all';
+ this.activities = [];
+ this.refreshInterval = null;
+ }
+
+ async initialize() {
+ await this.loadDashboardData();
+ this.setupEventListeners();
+ this.startAutoRefresh();
+
+ // Initialize sub-modules
+ await agentManager.initialize();
+ }
+
+ async loadDashboardData() {
+ try {
+ const data = await api.getDefaultMockData();
+
+ // Update platform status
+ this.updatePlatformStatus(data.platform);
+
+ // Update activities
+ this.activities = data.activities;
+ this.renderActivities();
+
+ // Initialize charts
+ chartManager.initializeCharts(data.metrics);
+
+ } catch (error) {
+ console.error('Failed to load dashboard data:', error);
+ }
+ }
+
+ updatePlatformStatus(platform) {
+ // Update platform status badge
+ const statusElement = document.getElementById('platformStatus');
+ if (statusElement) {
+ statusElement.textContent = platform.status.charAt(0).toUpperCase() + platform.status.slice(1);
+ statusElement.className = `status-badge ${platform.status}`;
+ }
+
+ // Update stats
+ this.updateStat('activeAgents', platform.activeAgents);
+ this.updateStat('queueSize', platform.queueSize);
+ this.updateStat('systemHealth', platform.systemHealth + '%');
+ }
+
+ updateStat(id, value) {
+ const element = document.getElementById(id);
+ if (element) {
+ element.textContent = value;
+ }
+ }
+
+ renderActivities() {
+ const feedElement = document.getElementById('activityFeed');
+ if (!feedElement) return;
+
+ const filteredActivities = this.currentFilter === 'all'
+ ? this.activities
+ : this.activities.filter(a => a.type === this.currentFilter);
+
+ if (filteredActivities.length === 0) {
+ feedElement.innerHTML = `
+
+
+
No activities to display
+
+ `;
+ return;
+ }
+
+ feedElement.innerHTML = filteredActivities.map(activity => `
+
+
+
+
+
+
${activity.title}
+
${activity.description}
+
+ ${activity.time}
+
+
+
+ `).join('');
+ }
+
+ getActivityIcon(type) {
+ const icons = {
+ policy: 'shield-alt',
+ deployment: 'rocket',
+ compliance: 'clipboard-check',
+ alert: 'exclamation-triangle'
+ };
+ return icons[type] || 'info-circle';
+ }
+
+ setupEventListeners() {
+ // Refresh button
+ const refreshBtn = document.getElementById('refreshBtn');
+ if (refreshBtn) {
+ refreshBtn.addEventListener('click', () => {
+ this.refresh();
+ });
+ }
+
+ // Activity filters
+ document.querySelectorAll('.filter-btn').forEach(button => {
+ button.addEventListener('click', (e) => {
+ // Update active state
+ document.querySelectorAll('.filter-btn').forEach(btn => {
+ btn.classList.remove('active');
+ });
+ e.target.classList.add('active');
+
+ // Update filter and re-render
+ this.currentFilter = e.target.dataset.filter;
+ this.renderActivities();
+ });
+ });
+
+ // Policy search
+ const policySearch = document.getElementById('policySearch');
+ if (policySearch) {
+ policySearch.addEventListener('input', (e) => {
+ this.searchPolicies(e.target.value);
+ });
+ }
+
+ // Simulate policy button
+ const simulatePolicyBtn = document.getElementById('simulatePolicyBtn');
+ if (simulatePolicyBtn) {
+ simulatePolicyBtn.addEventListener('click', () => {
+ this.simulatePolicy();
+ });
+ }
+
+ // Listen to WebSocket events
+ wsManager.on('activity', (activity) => {
+ this.addActivity(activity);
+ });
+
+ wsManager.on('metricUpdate', (data) => {
+ this.handleMetricUpdate(data);
+ });
+ }
+
+ async refresh() {
+ const refreshBtn = document.getElementById('refreshBtn');
+ const icon = refreshBtn.querySelector('i');
+
+ // Add rotation animation
+ icon.style.animation = 'spin 1s linear';
+
+ await this.loadDashboardData();
+
+ // Remove animation after 1 second
+ setTimeout(() => {
+ icon.style.animation = '';
+ }, 1000);
+
+ agentManager.showNotification('Dashboard refreshed', 'success');
+ }
+
+ addActivity(activity) {
+ // Add to beginning of activities array
+ this.activities.unshift(activity);
+
+ // Keep only last 50 activities
+ if (this.activities.length > 50) {
+ this.activities = this.activities.slice(0, 50);
+ }
+
+ // Re-render if current filter matches
+ if (this.currentFilter === 'all' || this.currentFilter === activity.type) {
+ this.renderActivities();
+ }
+ }
+
+ handleMetricUpdate(data) {
+ if (data.type === 'system_health') {
+ this.updateStat('systemHealth', data.value + '%');
+ }
+ }
+
+ searchPolicies(query) {
+ const policyItems = document.querySelectorAll('.policy-item');
+ const searchLower = query.toLowerCase();
+
+ policyItems.forEach(item => {
+ const title = item.querySelector('h4').textContent.toLowerCase();
+ const description = item.querySelector('p').textContent.toLowerCase();
+
+ if (title.includes(searchLower) || description.includes(searchLower)) {
+ item.style.display = 'flex';
+ } else {
+ item.style.display = 'none';
+ }
+ });
+ }
+
+ async simulatePolicy() {
+ agentManager.showNotification('Running policy simulation...', 'info');
+
+ // Simulate delay
+ await new Promise(resolve => setTimeout(resolve, 2000));
+
+ const results = {
+ passed: Math.floor(Math.random() * 50) + 150,
+ failed: Math.floor(Math.random() * 10),
+ warnings: Math.floor(Math.random() * 20)
+ };
+
+ const message = `Simulation complete: ${results.passed} passed, ${results.failed} failed, ${results.warnings} warnings`;
+ agentManager.showNotification(message, results.failed > 0 ? 'warning' : 'success');
+ }
+
+ startAutoRefresh() {
+ // Auto-refresh every 30 seconds
+ this.refreshInterval = setInterval(() => {
+ this.loadDashboardData();
+ }, 30000);
+ }
+
+ stopAutoRefresh() {
+ if (this.refreshInterval) {
+ clearInterval(this.refreshInterval);
+ this.refreshInterval = null;
+ }
+ }
+
+ destroy() {
+ this.stopAutoRefresh();
+ chartManager.destroyAllCharts();
+ agentManager.destroy();
+ }
+}
+
+// Add rotation animation for refresh button
+const rotationStyle = document.createElement('style');
+rotationStyle.textContent = `
+ @keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+ }
+`;
+document.head.appendChild(rotationStyle);
+
+// Initialize dashboard when DOM is ready
+let dashboard;
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => {
+ dashboard = new Dashboard();
+ dashboard.initialize();
+ });
+} else {
+ dashboard = new Dashboard();
+ dashboard.initialize();
+}
+
+// Cleanup on page unload
+window.addEventListener('beforeunload', () => {
+ if (dashboard) {
+ dashboard.destroy();
+ }
+ wsManager.disconnect();
+});
diff --git a/dashboard/js/websocket.js b/dashboard/js/websocket.js
new file mode 100644
index 0000000..9be66d4
--- /dev/null
+++ b/dashboard/js/websocket.js
@@ -0,0 +1,244 @@
+// WebSocket Manager for Real-Time Updates
+class WebSocketManager {
+ constructor() {
+ this.ws = null;
+ this.reconnectAttempts = 0;
+ this.maxReconnectAttempts = 5;
+ this.reconnectDelay = 3000;
+ this.listeners = {};
+ this.simulationMode = true; // Set to false when real WebSocket is available
+ this.simulationInterval = null;
+ }
+
+ connect(url = 'ws://localhost:8080') {
+ if (this.simulationMode) {
+ this.startSimulation();
+ return;
+ }
+
+ try {
+ this.ws = new WebSocket(url);
+
+ this.ws.onopen = () => {
+ console.log('WebSocket connected');
+ this.reconnectAttempts = 0;
+ this.updateConnectionStatus(true);
+ this.emit('connected');
+ };
+
+ this.ws.onmessage = (event) => {
+ try {
+ const data = JSON.parse(event.data);
+ this.handleMessage(data);
+ } catch (error) {
+ console.error('Failed to parse WebSocket message:', error);
+ }
+ };
+
+ this.ws.onerror = (error) => {
+ console.error('WebSocket error:', error);
+ this.emit('error', error);
+ };
+
+ this.ws.onclose = () => {
+ console.log('WebSocket disconnected');
+ this.updateConnectionStatus(false);
+ this.emit('disconnected');
+ this.attemptReconnect();
+ };
+ } catch (error) {
+ console.error('Failed to connect WebSocket:', error);
+ this.updateConnectionStatus(false);
+ }
+ }
+
+ disconnect() {
+ if (this.simulationMode) {
+ this.stopSimulation();
+ } else if (this.ws) {
+ this.ws.close();
+ this.ws = null;
+ }
+ }
+
+ send(message) {
+ if (this.simulationMode) {
+ console.log('Simulation mode: Message not sent', message);
+ return;
+ }
+
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
+ this.ws.send(JSON.stringify(message));
+ } else {
+ console.warn('WebSocket is not connected');
+ }
+ }
+
+ on(event, callback) {
+ if (!this.listeners[event]) {
+ this.listeners[event] = [];
+ }
+ this.listeners[event].push(callback);
+ }
+
+ off(event, callback) {
+ if (!this.listeners[event]) return;
+
+ this.listeners[event] = this.listeners[event].filter(
+ listener => listener !== callback
+ );
+ }
+
+ emit(event, data) {
+ if (!this.listeners[event]) return;
+
+ this.listeners[event].forEach(callback => {
+ try {
+ callback(data);
+ } catch (error) {
+ console.error('Error in event listener:', error);
+ }
+ });
+ }
+
+ handleMessage(data) {
+ const { type, payload } = data;
+
+ switch (type) {
+ case 'agent_status':
+ this.emit('agentStatus', payload);
+ break;
+ case 'activity':
+ this.emit('activity', payload);
+ break;
+ case 'metric_update':
+ this.emit('metricUpdate', payload);
+ break;
+ case 'policy_violation':
+ this.emit('policyViolation', payload);
+ break;
+ case 'deployment_event':
+ this.emit('deploymentEvent', payload);
+ break;
+ case 'compliance_alert':
+ this.emit('complianceAlert', payload);
+ break;
+ default:
+ console.log('Unknown message type:', type);
+ }
+ }
+
+ attemptReconnect() {
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
+ console.error('Max reconnection attempts reached');
+ return;
+ }
+
+ this.reconnectAttempts++;
+ console.log(`Reconnecting... Attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
+
+ setTimeout(() => {
+ this.connect();
+ }, this.reconnectDelay);
+ }
+
+ updateConnectionStatus(connected) {
+ const statusElement = document.getElementById('wsStatus');
+ if (!statusElement) return;
+
+ const statusDot = statusElement.querySelector('.status-dot');
+ const statusText = statusElement.querySelector('.status-text');
+
+ if (connected) {
+ statusDot.style.background = 'var(--status-success)';
+ statusText.textContent = 'Connected';
+ } else {
+ statusDot.style.background = 'var(--status-error)';
+ statusText.textContent = 'Disconnected';
+ }
+ }
+
+ // Simulation mode methods
+ startSimulation() {
+ console.log('Starting WebSocket simulation mode');
+ this.updateConnectionStatus(true);
+ this.emit('connected');
+
+ // Simulate real-time updates every 5 seconds
+ this.simulationInterval = setInterval(() => {
+ this.simulateUpdate();
+ }, 5000);
+ }
+
+ stopSimulation() {
+ if (this.simulationInterval) {
+ clearInterval(this.simulationInterval);
+ this.simulationInterval = null;
+ }
+ this.updateConnectionStatus(false);
+ }
+
+ simulateUpdate() {
+ const updateTypes = [
+ 'agent_status',
+ 'activity',
+ 'metric_update'
+ ];
+
+ const randomType = updateTypes[Math.floor(Math.random() * updateTypes.length)];
+
+ switch (randomType) {
+ case 'agent_status':
+ this.emit('agentStatus', {
+ agentId: ['policy', 'intent', 'deployment', 'compliance'][Math.floor(Math.random() * 4)],
+ status: 'active',
+ timestamp: new Date().toISOString()
+ });
+ break;
+
+ case 'activity':
+ const activities = [
+ {
+ type: 'policy',
+ title: 'Policy Check Completed',
+ description: 'All policies validated successfully',
+ time: 'just now'
+ },
+ {
+ type: 'deployment',
+ title: 'Deployment Initiated',
+ description: 'Starting deployment to us-west-2',
+ time: 'just now'
+ },
+ {
+ type: 'compliance',
+ title: 'Audit Event Recorded',
+ description: 'Configuration change logged',
+ time: 'just now'
+ }
+ ];
+ this.emit('activity', activities[Math.floor(Math.random() * activities.length)]);
+ break;
+
+ case 'metric_update':
+ this.emit('metricUpdate', {
+ type: 'system_health',
+ value: 95 + Math.floor(Math.random() * 5),
+ timestamp: new Date().toISOString()
+ });
+ break;
+ }
+ }
+}
+
+// Export WebSocket manager instance
+const wsManager = new WebSocketManager();
+
+// Auto-connect on page load
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => {
+ wsManager.connect();
+ });
+} else {
+ wsManager.connect();
+}
diff --git a/dashboard/policies.html b/dashboard/policies.html
new file mode 100644
index 0000000..eb1db4e
--- /dev/null
+++ b/dashboard/policies.html
@@ -0,0 +1,382 @@
+
+
+
+
+
+ Policy Management - Multi-Agent Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Active Policies
+
4
+
enforcing compliance
+
+
+
+
+
+
+
+
Policies Enforced
+
648
+
total checks today
+
+
+
+
+
+
+
+
Violations
+
3
+
require attention
+
+
+
+
+
+
+
+
Success Rate
+
99.5%
+
compliance score
+
+
+
+
+
+
+
+
+ All Policies
+
+
+
+
+
+
+
+
+
Ensures CPU and memory limits are not exceeded across all resources
+
+
+ Enforced Today
+ 247
+
+
+ Violations
+ 0
+
+
+ Last Run
+ 2 min ago
+
+
+
+
OPA Rules:
+
package kubernetes.admission
+deny[msg] {
+ input.request.kind.kind == "Pod"
+ container := input.request.object.spec.containers[_]
+ not container.resources.limits.cpu
+ msg := "CPU limit required"
+}
+
+
+
+
+
+
+
Validates security group rules against best practices
+
+
+ Enforced Today
+ 89
+
+
+ Violations
+ 0
+
+
+ Last Run
+ 5 min ago
+
+
+
+
OPA Rules:
+
package aws.security_groups
+deny[msg] {
+ rule := input.rules[_]
+ rule.from_port == 22
+ rule.cidr_blocks[_] == "0.0.0.0/0"
+ msg := "SSH should not be open to public"
+}
+
+
+
+
+
+
+
Alerts when spending exceeds budget thresholds
+
+
+ Checks Today
+ 156
+
+
+ Violations
+ 3
+
+
+ Last Run
+ 10 min ago
+
+
+
+
OPA Rules:
+
package cost.thresholds
+deny[msg] {
+ daily_cost := input.metrics.cost.daily
+ daily_cost > 500
+ msg := sprintf("Daily cost $%v exceeds threshold", [daily_cost])
+}
+
+
+
+
+
+
+
Ensures all data at rest is encrypted
+
+
+ Enforced Today
+ 312
+
+
+ Violations
+ 0
+
+
+ Last Run
+ 1 min ago
+
+
+
+
OPA Rules:
+
package aws.encryption
+deny[msg] {
+ resource := input.resources[_]
+ resource.type == "s3_bucket"
+ not resource.encryption.enabled
+ msg := "S3 bucket must have encryption enabled"
+}
+
+
+
+
+
+
+
+
+
+
From 4aea5952aa78758988fc4a27a26156b183c8390b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 15 Feb 2026 08:01:19 +0000
Subject: [PATCH 3/3] Add remaining dashboard pages (scripts, compliance,
settings) and documentation
Co-authored-by: Stacey77 <54900383+Stacey77@users.noreply.github.com>
---
dashboard/README.md | 316 ++++++++++++++++++
dashboard/compliance.html | 633 ++++++++++++++++++++++++++++++++++++
dashboard/scripts.html | 533 ++++++++++++++++++++++++++++++
dashboard/settings.html | 659 ++++++++++++++++++++++++++++++++++++++
4 files changed, 2141 insertions(+)
create mode 100644 dashboard/README.md
create mode 100644 dashboard/compliance.html
create mode 100644 dashboard/scripts.html
create mode 100644 dashboard/settings.html
diff --git a/dashboard/README.md b/dashboard/README.md
new file mode 100644
index 0000000..facd7a7
--- /dev/null
+++ b/dashboard/README.md
@@ -0,0 +1,316 @@
+# Multi-Agent Agentic Infrastructure Control Platform - Dashboard
+
+A comprehensive HTML dashboard for monitoring and managing the Multi-Agent Agentic Infrastructure Control Platform.
+
+## 🎯 Overview
+
+This interactive dashboard provides real-time monitoring, control, and visualization capabilities for a multi-agent infrastructure management system. Built with pure HTML5, CSS3, and JavaScript - no build process required.
+
+## ✨ Features
+
+### Main Dashboard (`index.html`)
+- **Platform Overview**: Real-time status of the entire platform
+- **Agent Status Panel**: Monitor all 4 agents (Policy, Intent, Deployment, Compliance)
+- **Blast Radius Visualization**: Interactive charts showing deployment impact
+- **Multi-Region Map**: Global infrastructure health visualization
+- **Policy Enforcement**: Active policies and violation tracking
+- **Cost Optimization**: Bandwidth, compute, storage, and cost metrics
+- **Activity Feed**: Real-time updates on system activities
+
+### Policy Management (`policies.html`)
+- View all active policies with OPA rules
+- Policy statistics and enforcement metrics
+- Search and filter policies
+- Policy simulation capabilities
+- Violation tracking
+
+### Script Library (`scripts.html`)
+- Browse 150+ automation scripts
+- Category-based filtering (Automation, Security, Monitoring, etc.)
+- Multi-cloud support (AWS, Azure, GCP)
+- Script ratings and download counts
+- Adapter marketplace
+
+### Compliance Reports (`compliance.html`)
+- Overall compliance score dashboard
+- Framework compliance (SOC 2, HIPAA, PCI DSS)
+- Audit trail viewer with search
+- Compliance markers for key resources
+- Trend analysis charts
+- Export to PDF/CSV
+
+### Settings (`settings.html`)
+- General platform configuration
+- Agent-specific settings
+- API endpoint configuration
+- Cloud provider credentials (AWS, Azure, GCP)
+- Notification preferences (Email, Slack, PagerDuty)
+
+## 🎨 Design
+
+### Color Scheme
+- **Primary Purple**: `#5B4B8A`, `#7B68A6`
+- **Dark Background**: `#2E2547`
+- **Accent Orange**: `#FF6B35`
+- **Success Green**: `#4CAF50`
+- **Status Colors**: Warning (`#FFA726`), Error (`#EF5350`), Info (`#42A5F5`)
+
+### Visual Elements
+- Lion logo with purple/orange gradient
+- Modern card-based layout
+- Responsive grid system
+- Smooth animations and transitions
+- Interactive charts via Chart.js
+
+## 🚀 Getting Started
+
+### Prerequisites
+- Modern web browser (Chrome, Firefox, Safari, Edge)
+- Web server (optional, for best experience)
+
+### Installation
+
+1. **Clone or download the repository**
+ ```bash
+ cd dashboard
+ ```
+
+2. **Open in browser**
+ - **Option 1**: Open `index.html` directly in your browser
+ - **Option 2**: Use a local web server (recommended):
+ ```bash
+ # Python 3
+ python -m http.server 8000
+
+ # Node.js
+ npx serve
+ ```
+ - Navigate to `http://localhost:8000`
+
+### No Build Process Required
+The dashboard uses CDN-hosted libraries:
+- Chart.js (v4.4.0) for data visualization
+- Font Awesome (v6.4.0) for icons
+
+## 📁 File Structure
+
+```
+/dashboard
+├── index.html # Main dashboard
+├── policies.html # Policy management
+├── scripts.html # Script library
+├── compliance.html # Compliance reports
+├── settings.html # Settings page
+├── css/
+│ ├── main.css # Main stylesheet with purple theme
+│ ├── dashboard.css # Dashboard-specific styles
+│ └── responsive.css # Mobile responsive styles
+├── js/
+│ ├── dashboard.js # Main dashboard logic
+│ ├── agents.js # Agent management
+│ ├── charts.js # Chart configurations
+│ ├── api.js # API integration layer
+│ └── websocket.js # Real-time updates simulation
+├── assets/
+│ ├── logo.svg # Lion logo
+│ └── icons/ # (using Font Awesome)
+├── data/
+│ └── mock-data.json # Mock data for demonstration
+└── README.md # This file
+```
+
+## 🔌 API Integration
+
+### Mock Mode (Default)
+The dashboard runs in mock mode by default, using `data/mock-data.json` for demonstration.
+
+### Connecting to Real API
+
+1. **Update API Configuration** in `js/api.js`:
+ ```javascript
+ constructor() {
+ this.baseUrl = 'https://your-api-endpoint.com/api';
+ this.mockMode = false; // Disable mock mode
+ }
+ ```
+
+2. **Configure WebSocket** in `js/websocket.js`:
+ ```javascript
+ connect(url = 'wss://your-websocket-endpoint.com') {
+ this.simulationMode = false; // Disable simulation
+ // ... rest of the code
+ }
+ ```
+
+### API Endpoints Expected
+
+```
+GET /api/platform/status # Platform status
+GET /api/agents # All agents
+GET /api/agents/:id # Specific agent
+POST /api/agents/:id/start # Start agent
+POST /api/agents/:id/stop # Stop agent
+GET /api/activities # Activity feed
+GET /api/policies # All policies
+GET /api/metrics # Metrics data
+GET /api/regions # Region data
+GET /api/blast-radius # Blast radius data
+```
+
+### WebSocket Events
+
+```javascript
+// Agent status update
+{
+ type: 'agent_status',
+ payload: {
+ agentId: 'policy',
+ status: 'active',
+ timestamp: '2024-02-15T07:30:00Z'
+ }
+}
+
+// New activity
+{
+ type: 'activity',
+ payload: {
+ type: 'policy',
+ title: 'Policy Check Completed',
+ description: 'All policies validated',
+ time: 'just now'
+ }
+}
+
+// Metric update
+{
+ type: 'metric_update',
+ payload: {
+ type: 'system_health',
+ value: 98,
+ timestamp: '2024-02-15T07:30:00Z'
+ }
+}
+```
+
+## 📱 Responsive Design
+
+The dashboard is fully responsive and works on:
+- **Desktop**: Full feature set with side navigation
+- **Tablet**: Optimized grid layouts
+- **Mobile**: Collapsed navigation, stacked layouts
+
+Breakpoints:
+- Desktop: > 1024px
+- Tablet: 768px - 1024px
+- Mobile: < 768px
+
+## 🔄 Real-Time Updates
+
+### Auto-Refresh
+- Dashboard data refreshes every 30 seconds
+- Agent metrics update every 5 seconds
+- WebSocket provides instant updates (when connected)
+
+### Manual Refresh
+Click the refresh button in the header to manually update all data.
+
+## 🎯 Features in Detail
+
+### Agent Management
+- Start/stop individual agents
+- View real-time metrics
+- Monitor processing queues
+- Track success rates
+
+### Policy Enforcement
+- Search policies
+- View OPA rules
+- Simulate policy execution
+- Track violations
+
+### Blast Radius Analysis
+- Visual impact prediction
+- Affected resources count
+- Risk level indicators
+- Approval workflow
+
+### Cost Optimization
+- Bandwidth savings tracking
+- Compute efficiency metrics
+- Storage utilization
+- Cost trend analysis
+
+## 🔧 Customization
+
+### Changing Colors
+Edit `css/main.css`:
+```css
+:root {
+ --primary-purple: #5B4B8A;
+ --accent-orange: #FF6B35;
+ /* ... modify as needed */
+}
+```
+
+### Adding New Metrics
+1. Add chart configuration in `js/charts.js`
+2. Update mock data in `data/mock-data.json`
+3. Add chart canvas in HTML
+4. Initialize in dashboard
+
+### Custom Agents
+Add new agent cards to `index.html` and update `data/mock-data.json` with agent configuration.
+
+## 🐛 Troubleshooting
+
+### Charts Not Displaying
+- Ensure Chart.js CDN is accessible
+- Check browser console for errors
+- Verify canvas elements have valid IDs
+
+### WebSocket Not Connecting
+- Simulation mode is enabled by default
+- Check `simulationMode` in `js/websocket.js`
+- Verify WebSocket URL if using real connection
+
+### Mock Data Not Loading
+- Ensure `data/mock-data.json` exists
+- Check file path is correct
+- Verify JSON is valid
+
+## 📊 Browser Support
+
+- Chrome/Edge: Latest 2 versions
+- Firefox: Latest 2 versions
+- Safari: Latest 2 versions
+- Mobile browsers: iOS Safari, Chrome Android
+
+## 🔒 Security Notes
+
+- Never commit real API keys or credentials
+- Use environment variables for sensitive data
+- Implement proper authentication in production
+- Enable HTTPS for all API connections
+- Sanitize user inputs
+
+## 📝 License
+
+This dashboard is part of the Multi-Agent Infrastructure Control Platform project.
+
+## 🤝 Contributing
+
+To contribute:
+1. Follow existing code style
+2. Test on multiple browsers
+3. Ensure responsive design works
+4. Update documentation as needed
+
+## 📧 Support
+
+For issues or questions, please refer to the main project repository.
+
+## 🎉 Acknowledgments
+
+- Chart.js for beautiful data visualization
+- Font Awesome for comprehensive icon library
+- Modern web standards for making this possible without a build process
diff --git a/dashboard/compliance.html b/dashboard/compliance.html
new file mode 100644
index 0000000..260e581
--- /dev/null
+++ b/dashboard/compliance.html
@@ -0,0 +1,633 @@
+
+
+
+
+
+ Compliance Reports - Multi-Agent Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Overall Score
+
96%
+
compliance rating
+
+
+
+
+
+
+
+
Audit Events
+
1,234
+
logged this month
+
+
+
+
+
+
+
+
Markers
+
45
+
active compliance points
+
+
+
+
+
+
+
+
Issues
+
11
+
require attention
+
+
+
+
+
+
+
+
+ Compliance Frameworks
+
+
+
+
+
+
+
+ Controls
+ 156
+
+
+ Passed
+ 153
+
+
+ Failed
+ 3
+
+
+
+
+
+
+
+
+
+ Controls
+ 89
+
+
+ Passed
+ 85
+
+
+ Failed
+ 4
+
+
+
+
+
+
+
+
+
+ Controls
+ 67
+
+
+ Passed
+ 63
+
+
+ Failed
+ 4
+
+
+
+
+
+
+
+
+
+ Compliance Trends
+
+
+
+
+
+
+
+
+
+ Recent Audit Events
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Timestamp |
+ Event Type |
+ Resource |
+ User |
+ Status |
+ Actions |
+
+
+
+
+ | 2024-02-15 07:30:00 |
+ Configuration Change |
+ s3://production-data |
+ admin@example.com |
+ Compliant |
+ |
+
+
+ | 2024-02-15 07:25:00 |
+ Access Event |
+ rds://prod-db |
+ user@example.com |
+ Compliant |
+ |
+
+
+ | 2024-02-15 07:20:00 |
+ Policy Violation |
+ ec2://i-1234567 |
+ service-account |
+ Warning |
+ |
+
+
+ | 2024-02-15 07:15:00 |
+ Configuration Change |
+ iam://role/admin |
+ admin@example.com |
+ Compliant |
+ |
+
+
+ | 2024-02-15 07:10:00 |
+ Access Event |
+ s3://backup-storage |
+ backup-service |
+ Compliant |
+ |
+
+
+
+
+
+
+
+
+
+
+ Compliance Markers
+
+
+
+
+
+
+
+
Encryption at Rest
+
s3://production-data
+
Last checked: 2 minutes ago
+
+
Compliant
+
+
+
+
+
+
+
+
Automated Backups
+
rds://prod-db
+
Last checked: 5 minutes ago
+
+
Compliant
+
+
+
+
+
+
+
+
Access Logging
+
lb://production-lb
+
Last checked: 10 minutes ago
+
+
Warning
+
+
+
+
+
+
+
+
Multi-Factor Auth
+
iam://root-account
+
Last checked: 1 hour ago
+
+
Compliant
+
+
+
+
+
+
+
+
+
+
diff --git a/dashboard/scripts.html b/dashboard/scripts.html
new file mode 100644
index 0000000..61af3d3
--- /dev/null
+++ b/dashboard/scripts.html
@@ -0,0 +1,533 @@
+
+
+
+
+
+ Script Library - Multi-Agent Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Total Scripts
+
156
+
available adapters
+
+
+
+
+
+
+
+
Total Downloads
+
2.7K
+
this month
+
+
+
+
+
+
+
+
Cloud Providers
+
5
+
supported platforms
+
+
+
+
+
+
+
+
Average Rating
+
4.8
+
out of 5 stars
+
+
+
+
+
+
+
+
+ Browse by Category
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Auto-Scale Infrastructure
+
Automatically scales compute resources based on demand using predictive algorithms
+
+ 1,234
+ 4.9
+
+
+
+
+
+
+
+
Cost Optimizer
+
Identifies and terminates unused resources to reduce infrastructure costs
+
+ 892
+ 4.7
+
+
+
+
+
+
+
+
Security Audit
+
Runs comprehensive security checks across infrastructure and reports vulnerabilities
+
+ 567
+ 4.8
+
+
+
+
+
+
+
+
Health Monitor
+
Monitors system health metrics and sends alerts for anomalies
+
+ 445
+ 4.6
+
+
+
+
+
+
+
+
Automated Backup
+
Schedules and executes regular backups of critical data with rotation
+
+ 678
+ 4.9
+
+
+
+
+
+
+
+
Blue-Green Deployer
+
Implements blue-green deployment strategy with automatic rollback
+
+ 823
+ 4.8
+
+
+
+
+
+
+
+
+
+ Adapter Marketplace
+
+
+
+ Browse and install community-contributed adapters for various cloud providers and tools
+
+
+
+
+
AWS Adapter
+
56 scripts
+
+
+
+
Azure Adapter
+
42 scripts
+
+
+
+
GCP Adapter
+
38 scripts
+
+
+
+
Kubernetes Adapter
+
29 scripts
+
+
+
+
+
+
+
+
+
diff --git a/dashboard/settings.html b/dashboard/settings.html
new file mode 100644
index 0000000..24feb86
--- /dev/null
+++ b/dashboard/settings.html
@@ -0,0 +1,659 @@
+
+
+
+
+
+ Settings - Multi-Agent Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ General Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Agent Configuration
+
+
+
+
+
+
+
+
+ API Endpoints
+
+
+
+
+ Test Connection
+
+
+
+ Test your API connection to ensure everything is configured correctly
+
+
+
+
+
+
+
+
+
+ Cloud Provider Credentials
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notification Preferences
+
+
+
+
Email Notifications
+
+
+
+
+
+
+
+
+
+
+
PagerDuty Integration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+