Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated servicedashboard #125

Merged
merged 1 commit into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/cloud/api/web/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<link rel="shortcut icon" href="/favicons/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/favicons/site.webmanifest" />
<script type="module" crossorigin src="/assets/index-B4Tzad_m.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DKo-QLsn.css">
<script type="module" crossorigin src="/assets/index-BmszrEo7.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-0YCAHuDK.css">
</head>
<body>
<div id="root"></div>
Expand Down
4 changes: 2 additions & 2 deletions web/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<link rel="shortcut icon" href="/favicons/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/favicons/site.webmanifest" />
<script type="module" crossorigin src="/assets/index-B4Tzad_m.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DKo-QLsn.css">
<script type="module" crossorigin src="/assets/index-BmszrEo7.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-0YCAHuDK.css">
</head>
<body>
<div id="root"></div>
Expand Down
106 changes: 105 additions & 1 deletion web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 9 additions & 8 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
"private": true,
"type": "module",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"lucide-react": "^0.263.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1",
"recharts": "^2.10.3",
"tailwindcss": "^3.4.1",
"tailwindcss-animate": "^1.0.7",
"recharts": "^2.10.3",
"@radix-ui/react-navigation-menu": "^1.1.4"
"xlsx": "^0.18.5"
},
"scripts": {
"dev": "vite",
Expand All @@ -23,8 +24,8 @@
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.4.14",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32"
"postcss": "^8.4.32",
"vite": "^5.4.14"
}
}
}
125 changes: 125 additions & 0 deletions web/src/components/ExportButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React from 'react';
import * as XLSX from 'xlsx';
import { Download } from 'lucide-react';

const ExportButton = ({ sweepDetails }) => {
const handleExport = () => {
// Create workbook
const wb = XLSX.utils.book_new();

// Create summary sheet
const summaryData = [{
Network: sweepDetails.network,
'Total Hosts': sweepDetails.total_hosts,
'Available Hosts': sweepDetails.available_hosts,
'Last Sweep': new Date(sweepDetails.last_sweep * 1000).toLocaleString(),
'Available %': ((sweepDetails.available_hosts / sweepDetails.total_hosts) * 100).toFixed(2) + '%'
}];
const summarySheet = XLSX.utils.json_to_sheet(summaryData);
XLSX.utils.book_append_sheet(wb, summarySheet, "Summary");

// Create ports sheet
if (sweepDetails.ports && sweepDetails.ports.length > 0) {
const portsData = sweepDetails.ports.map(port => ({
Port: port.port,
'Hosts Available': port.available,
'Response Rate': ((port.available / sweepDetails.total_hosts) * 100).toFixed(2) + '%'
}));
const portsSheet = XLSX.utils.json_to_sheet(portsData);
XLSX.utils.book_append_sheet(wb, portsSheet, "Ports");
}

// Create hosts sheet with sorted data
if (sweepDetails.hosts && sweepDetails.hosts.length > 0) {
const hostsData = sweepDetails.hosts.map(host => {
const openPorts = host.port_results
?.filter(port => port.available)
.map(port => port.port)
.join(', ') || '';

let icmpStatus = 'N/A';
let responseTime = 'N/A';

// Handle ICMP status and response time
if (host.icmp_status) {
// Format ICMP status
icmpStatus = host.icmp_status.packet_loss === 0
? 'Responding'
: `${host.icmp_status.packet_loss}% Packet Loss`;

// Format response time if available
if (typeof host.icmp_status.round_trip === 'number') {
responseTime = (host.icmp_status.round_trip / 1000000).toFixed(2) + 'ms';
}
}

return {
Host: host.host,
Status: host.available ? 'Online' : 'Offline',
'Open Ports': openPorts,
'ICMP Status': icmpStatus,
'Response Time': responseTime,
'First Seen': new Date(host.first_seen).toLocaleString(),
'Last Seen': new Date(host.last_seen).toLocaleString()
};
});

// Sort hosts by IP address
hostsData.sort((a, b) => {
const aMatch = a.Host.match(/(\d+)$/);
const bMatch = b.Host.match(/(\d+)$/);
if (aMatch && bMatch) {
return parseInt(aMatch[1]) - parseInt(bMatch[1]);
}
return a.Host.localeCompare(b.Host);
});

const hostsSheet = XLSX.utils.json_to_sheet(hostsData);
XLSX.utils.book_append_sheet(wb, hostsSheet, "Hosts");
}

// Auto-size columns for all sheets
const sheets = ['Summary', 'Ports', 'Hosts'];
sheets.forEach(sheet => {
if (wb.Sheets[sheet]) {
const worksheet = wb.Sheets[sheet];
const range = XLSX.utils.decode_range(worksheet['!ref']);

for (let C = range.s.c; C <= range.e.c; ++C) {
let max_width = 0;

for (let R = range.s.r; R <= range.e.r; ++R) {
const cell_address = { c: C, r: R };
const cell_ref = XLSX.utils.encode_cell(cell_address);

if (worksheet[cell_ref]) {
const value = worksheet[cell_ref].v.toString();
max_width = Math.max(max_width, value.length);
}
}

worksheet['!cols'] = worksheet['!cols'] || [];
worksheet['!cols'][C] = { wch: max_width + 2 };
}
}
});

// Generate timestamp for filename
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);

// Save the file
XLSX.writeFile(wb, `network-sweep-${timestamp}.xlsx`);
};

return (
<button
onClick={handleExport}
className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
>
<Download size={16} />
Export Results
</button>
);
};

export default ExportButton;
Loading
Loading