Infrastructure as Code (IaC) Dashboard

Total Stacks
0
Total Managed Resources
0
Total Monthly Cost
$0

Stacks by Status

Monthly Cost by Stack

All Stacks

Stack/EnvironmentProviderStatusResourcesMonthly CostLast Sync

Configure Infrastructure Stacks

Stack/Environment Name ProviderStatusResources Monthly Cost ($)Last SyncAction

Error: Could not load required libraries.

'; return; } let iac_statusChart, iac_costChart; const TABS = ['dashboardTab', 'configTab']; let iac_currentTabIndex = 0; const ICONS = { aws: ``, azure: ``, gcp: `` }; const STATUS_CONFIG = { Synced: { bg: '#dcfce7', text: '#166534', color: '#22c55e' }, Drifted: { bg: '#fef9c3', text: '#854d0e', color: '#f59e0b' }, Error: { bg: '#fee2e2', text: '#991b1b', color: '#ef4444' } }; const sampleData = [ { stackName: "prod-us-east-1-main-app", provider: "aws", status: "Synced", resources: 125, cost: 5500, lastSync: "2025-07-08" }, { stackName: "prod-us-west-2-analytics-db", provider: "aws", status: "Synced", resources: 15, cost: 2300, lastSync: "2025-07-08" }, { stackName: "staging-central-us-api", provider: "azure", status: "Drifted", resources: 75, cost: 1200, lastSync: "2025-07-07" }, { stackName: "dev-gcp-europe-west-1-testing", provider: "gcp", status: "Synced", resources: 30, cost: 450, lastSync: "2025-07-09" }, { stackName: "shared-services-networking", provider: "aws", status: "Error", resources: 40, cost: 800, lastSync: "2025-07-05" }, ]; function iac_initialize() { sampleData.forEach(d => iac_add_row(d)); iac_updateDashboard(); iac_updateNavButtons(); } window.iac_add_row = function(data = {}) { const tableBody = document.getElementById('iac-input-table-body'); const row = tableBody.insertRow(); row.innerHTML = ` `; } function iac_collectData() { const rows = document.getElementById('iac-input-table-body').rows; let data = []; for (let row of rows) { data.push({ stackName: row.querySelector('.stackName').value, provider: row.querySelector('.provider').value, status: row.querySelector('.status').value, resources: parseInt(row.querySelector('.resources').value) || 0, cost: parseInt(row.querySelector('.cost').value) || 0, lastSync: row.querySelector('.lastSync').value, }); } return data; } window.iac_updateDashboard = function() { const data = iac_collectData(); iac_updateSummaryMetrics(data); iac_updateStatusChart(data); iac_updateCostChart(data); iac_renderTable(data); iac_changeTab('dashboardTab'); } function iac_updateSummaryMetrics(data) { document.getElementById('summary-stacks').textContent = data.length; document.getElementById('summary-resources').textContent = data.reduce((sum, s) => sum + s.resources, 0).toLocaleString(); const totalCost = data.reduce((sum, s) => sum + s.cost, 0); document.getElementById('summary-cost').textContent = `$${totalCost.toLocaleString()}`; } function iac_updateStatusChart(data) { const ctx = document.getElementById('iac-status-chart'); if (iac_statusChart) iac_statusChart.destroy(); const statusCounts = data.reduce((acc, s) => { acc[s.status] = (acc[s.status] || 0) + 1; return acc; }, {}); const labels = Object.keys(STATUS_CONFIG); const chartData = labels.map(label => statusCounts[label] || 0); const colors = labels.map(label => STATUS_CONFIG[label].color); iac_statusChart = new Chart(ctx, { type: 'doughnut', data: { labels: labels, datasets: [{ data: chartData, backgroundColor: colors, borderColor: '#ffffff', borderWidth: 2, }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } } }); } function iac_updateCostChart(data) { const ctx = document.getElementById('iac-cost-chart'); if (iac_costChart) iac_costChart.destroy(); const sortedData = [...data].sort((a,b) => b.cost - a.cost); iac_costChart = new Chart(ctx, { type: 'bar', data: { labels: sortedData.map(d => d.stackName), datasets: [{ label: 'Monthly Cost ($)', data: sortedData.map(d => d.cost), backgroundColor: '#60a5fa', borderColor: '#2563eb', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { callback: (v) => '$' + v.toLocaleString() } } }, plugins: { legend: { display: false } } } }); } function iac_renderTable(data) { const tableBody = document.getElementById('iac-table-body'); tableBody.innerHTML = ''; data.forEach(s => { const row = tableBody.insertRow(); row.innerHTML = ` ${s.stackName} ${ICONS[s.provider] || ''} ${s.provider.toUpperCase()} ${s.status} ${s.resources.toLocaleString()} $${s.cost.toLocaleString()} ${s.lastSync} `; }); } window.iac_downloadPDF = function() { const { jsPDF } = window.jspdf; const doc = new jsPDF('landscape'); const data = iac_collectData(); doc.setFontSize(20); doc.text("Infrastructure as Code (IaC) Report", 148, 20, { align: 'center' }); const statusCanvas = document.getElementById('iac-status-chart').toDataURL('image/png', 1.0); const costCanvas = document.getElementById('iac-cost-chart').toDataURL('image/png', 1.0); doc.addImage(statusCanvas, 'PNG', 20, 35, 80, 80); doc.addImage(costCanvas, 'PNG', 110, 35, 170, 80); const tableHead = [['Stack/Environment', 'Provider', 'Status', 'Resources', 'Monthly Cost', 'Last Sync']]; const tableBody = data.map(s => [s.stackName, s.provider.toUpperCase(), s.status, s.resources, `$${s.cost.toLocaleString()}`, s.lastSync]); doc.autoTable({ head: tableHead, body: tableBody, startY: 120, theme: 'grid', headStyles: { fillColor: '#111827' } }); doc.save('IaC_Dashboard_Report.pdf'); } // --- TABBING & NAVIGATION --- window.iac_changeTab = function(tabId) { document.querySelectorAll('.iac-tab-content').forEach(c => c.classList.remove('active')); document.querySelectorAll('.iac-tab-button').forEach(b => b.classList.remove('active')); document.getElementById(tabId).classList.add('active'); const activeButton = Array.from(document.querySelectorAll('.iac-tab-button')).find(btn => btn.getAttribute('onclick').includes(tabId)); if (activeButton) activeButton.classList.add('active'); iac_currentTabIndex = TABS.indexOf(tabId); iac_updateNavButtons(); } window.iac_navigateTabs = function(direction) { let newIndex = iac_currentTabIndex; if (direction === 'next') newIndex = Math.min(newIndex + 1, TABS.length - 1); else if (direction === 'prev') newIndex = Math.max(newIndex - 1, 0); iac_changeTab(TABS[newIndex]); } function iac_updateNavButtons() { const prevBtn = document.getElementById('iac-prev-btn'); const nextBtn = document.getElementById('iac-next-btn'); if(prevBtn) prevBtn.disabled = iac_currentTabIndex === 0; if(nextBtn) nextBtn.disabled = iac_currentTabIndex === TABS.length - 1; } iac_initialize(); });
Scroll to Top