mirror of
https://github.com/imjasonh/apkviz
synced 2026-07-08 01:45:15 +00:00
This web application visualizes package dependencies in the Wolfi Linux distribution, providing powerful insights into the package ecosystem. Features: - Interactive force-directed dependency graph visualization - Shows both forward dependencies (what a package depends on) and reverse dependencies (what depends on it) - Click any node to re-center the visualization on that package - Transitive dependency analysis with toggle control - Advanced package analytics including: - Criticality scores showing how many packages depend on each package - Total size impact analysis (package + all dependencies) - Dependency depth metrics - Bus factor warnings for critical infrastructure packages - "Most Critical Packages" dashboard showing system-wide statistics - Real-time search with auto-complete - Different visual styles for direct vs transitive dependencies - Playwright-based testing infrastructure for automated UI testing Technical implementation: - TypeScript + D3.js for visualization - Webpack build system - Analyzes Wolfi's APKINDEX for package metadata - Efficient dependency graph algorithms - Responsive design with detailed package information panel 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
50 lines
No EOL
1.6 KiB
JavaScript
50 lines
No EOL
1.6 KiB
JavaScript
const { chromium } = require('playwright');
|
|
|
|
async function testSearch() {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const page = await browser.newPage();
|
|
|
|
// Capture console logs
|
|
const logs = [];
|
|
page.on('console', msg => logs.push(`[${msg.type()}] ${msg.text()}`));
|
|
page.on('pageerror', err => logs.push(`[ERROR] ${err.message}`));
|
|
|
|
await page.goto('http://localhost:8081', { waitUntil: 'networkidle' });
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Search for java
|
|
await page.type('#search', 'java');
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Check for errors
|
|
const hasErrors = logs.some(log => log.includes('node not found'));
|
|
console.log('Has errors after search:', hasErrors);
|
|
|
|
if (hasErrors) {
|
|
console.log('\nError logs:');
|
|
logs.filter(log => log.includes('ERROR') || log.includes('error')).forEach(log => console.log(log));
|
|
}
|
|
|
|
// Take screenshot
|
|
await page.screenshot({ path: 'playwright-output/search-result.png', fullPage: true });
|
|
console.log('\nScreenshot saved to search-result.png');
|
|
|
|
// Get visualization state
|
|
const vizState = await page.evaluate(() => {
|
|
const circles = document.querySelectorAll('circle');
|
|
const lines = document.querySelectorAll('line');
|
|
return {
|
|
nodeCount: circles.length,
|
|
linkCount: lines.length,
|
|
nodes: Array.from(circles).slice(0, 5).map(c => c.parentElement?.textContent || 'unknown')
|
|
};
|
|
});
|
|
|
|
console.log('\nVisualization state:');
|
|
console.log(`Nodes: ${vizState.nodeCount}, Links: ${vizState.linkCount}`);
|
|
console.log('First few nodes:', vizState.nodes);
|
|
|
|
await browser.close();
|
|
}
|
|
|
|
testSearch().catch(console.error); |