- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
497 lines
14 KiB
Handlebars
497 lines
14 KiB
Handlebars
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Redirect Intelligence Report - {{check.id}}</title>
|
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
line-height: 1.6;
|
|
color: #333;
|
|
background: white;
|
|
padding: 20px;
|
|
}
|
|
|
|
.header {
|
|
border-bottom: 3px solid #0ea5e9;
|
|
padding-bottom: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.header h1 {
|
|
color: #0ea5e9;
|
|
font-size: 28px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.header .meta {
|
|
color: #666;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.summary-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 15px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.summary-card {
|
|
background: #f8fafc;
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
}
|
|
|
|
.summary-card .label {
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.summary-card .value {
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
color: #1e293b;
|
|
}
|
|
|
|
.status-ok { color: #059669; }
|
|
.status-error { color: #dc2626; }
|
|
.status-timeout { color: #d97706; }
|
|
.status-loop { color: #7c3aed; }
|
|
|
|
h2 {
|
|
color: #1e293b;
|
|
font-size: 20px;
|
|
margin: 30px 0 15px 0;
|
|
padding-bottom: 5px;
|
|
border-bottom: 2px solid #e2e8f0;
|
|
}
|
|
|
|
h3 {
|
|
color: #475569;
|
|
font-size: 16px;
|
|
margin: 20px 0 10px 0;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 15px 0;
|
|
font-size: 13px;
|
|
}
|
|
|
|
th {
|
|
background: #f1f5f9;
|
|
color: #374151;
|
|
font-weight: 600;
|
|
padding: 10px 8px;
|
|
text-align: left;
|
|
border: 1px solid #d1d5db;
|
|
}
|
|
|
|
td {
|
|
padding: 8px;
|
|
border: 1px solid #d1d5db;
|
|
vertical-align: top;
|
|
}
|
|
|
|
tr:nth-child(even) {
|
|
background: #f9fafb;
|
|
}
|
|
|
|
.url-cell {
|
|
word-break: break-all;
|
|
max-width: 200px;
|
|
font-family: 'Consolas', 'Monaco', monospace;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.badge {
|
|
display: inline-block;
|
|
padding: 3px 8px;
|
|
border-radius: 12px;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.badge-success { background: #dcfce7; color: #166534; }
|
|
.badge-redirect { background: #fef3c7; color: #92400e; }
|
|
.badge-error { background: #fee2e2; color: #991b1b; }
|
|
.badge-info { background: #dbeafe; color: #1e40af; }
|
|
|
|
.alert {
|
|
padding: 12px 16px;
|
|
border-radius: 6px;
|
|
margin: 15px 0;
|
|
border-left: 4px solid;
|
|
}
|
|
|
|
.alert-warning {
|
|
background: #fefce8;
|
|
border-color: #eab308;
|
|
color: #713f12;
|
|
}
|
|
|
|
.alert-error {
|
|
background: #fef2f2;
|
|
border-color: #ef4444;
|
|
color: #991b1b;
|
|
}
|
|
|
|
.alert-info {
|
|
background: #eff6ff;
|
|
border-color: #3b82f6;
|
|
color: #1e40af;
|
|
}
|
|
|
|
.mermaid-container {
|
|
background: white;
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.mermaid {
|
|
max-width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
.recommendations {
|
|
background: #f0f9ff;
|
|
border: 1px solid #0ea5e9;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.recommendations h3 {
|
|
color: #0ea5e9;
|
|
margin-top: 0;
|
|
}
|
|
|
|
.recommendations ul {
|
|
margin: 10px 0;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.recommendations li {
|
|
margin: 5px 0;
|
|
}
|
|
|
|
.footer {
|
|
margin-top: 40px;
|
|
padding-top: 20px;
|
|
border-top: 1px solid #e2e8f0;
|
|
text-align: center;
|
|
color: #64748b;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.page-break {
|
|
page-break-before: always;
|
|
}
|
|
|
|
@media print {
|
|
body {
|
|
padding: 0;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.header h1 {
|
|
font-size: 24px;
|
|
}
|
|
|
|
table {
|
|
font-size: 11px;
|
|
}
|
|
|
|
.page-break {
|
|
page-break-before: always;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Header -->
|
|
<div class="header">
|
|
<h1>🔗 Redirect Intelligence Report</h1>
|
|
<div class="meta">
|
|
<strong>Generated:</strong> {{formatDate generatedAt}} |
|
|
<strong>Check ID:</strong> {{check.id}}
|
|
{{#if organization}} | <strong>Organization:</strong> {{organization.name}} ({{organization.plan}}){{/if}}
|
|
{{#if user}} | <strong>Generated by:</strong> {{user.name}}{{/if}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary Cards -->
|
|
<div class="summary-grid">
|
|
<div class="summary-card">
|
|
<div class="label">Status</div>
|
|
<div class="value status-{{check.status}}">{{check.status}}</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="label">Redirects</div>
|
|
<div class="value">{{check.redirectCount}}</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="label">Total Time</div>
|
|
<div class="value">{{formatDuration check.totalTimeMs}}</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="label">Method</div>
|
|
<div class="value">{{check.method}}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- URLs -->
|
|
<h2>URLs</h2>
|
|
<table>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>URL</th>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="badge badge-info">Input</span></td>
|
|
<td class="url-cell">{{check.inputUrl}}</td>
|
|
</tr>
|
|
{{#if check.finalUrl}}
|
|
<tr>
|
|
<td><span class="badge badge-success">Final</span></td>
|
|
<td class="url-cell">{{check.finalUrl}}</td>
|
|
</tr>
|
|
{{/if}}
|
|
</table>
|
|
|
|
<!-- Alerts -->
|
|
{{#if check.error}}
|
|
<div class="alert alert-error">
|
|
<strong>Error:</strong> {{check.error}}
|
|
</div>
|
|
{{/if}}
|
|
|
|
{{#if check.loopDetected}}
|
|
<div class="alert alert-warning">
|
|
<strong>⚠️ Redirect Loop Detected!</strong> The URL redirects in a loop, which can cause infinite redirects and poor user experience.
|
|
</div>
|
|
{{/if}}
|
|
|
|
<!-- Redirect Chain -->
|
|
{{#if check.hops}}
|
|
<h2>Redirect Chain Analysis</h2>
|
|
|
|
<!-- Mermaid Diagram -->
|
|
<div class="mermaid-container">
|
|
<h3>Visual Flow Chart</h3>
|
|
<div class="mermaid">
|
|
{{mermaidDiagram}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hop Details Table -->
|
|
<h3>Detailed Hop Information</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Hop</th>
|
|
<th>URL</th>
|
|
<th>Status</th>
|
|
<th>Type</th>
|
|
<th>Latency</th>
|
|
<th>Content-Type</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{#each check.hops}}
|
|
<tr>
|
|
<td><span class="badge badge-info">{{hopIndex}}</span></td>
|
|
<td class="url-cell">{{url}}</td>
|
|
<td>
|
|
{{#if statusCode}}
|
|
<span class="badge {{#if (gte statusCode 400)}}badge-error{{else if (gte statusCode 300)}}badge-redirect{{else}}badge-success{{/if}}">
|
|
{{statusCode}}
|
|
</span>
|
|
{{else}}-{{/if}}
|
|
</td>
|
|
<td>{{redirectType redirectType}}</td>
|
|
<td>{{#if latencyMs}}{{latencyMs}}ms{{else}}-{{/if}}</td>
|
|
<td>{{#if contentType}}{{contentType}}{{else}}-{{/if}}</td>
|
|
</tr>
|
|
{{/each}}
|
|
</tbody>
|
|
</table>
|
|
{{/if}}
|
|
|
|
<!-- Analysis Results -->
|
|
{{#if analysis}}
|
|
<div class="page-break"></div>
|
|
<h2>Analysis Results</h2>
|
|
|
|
<!-- SSL Analysis -->
|
|
{{#if analysis.ssl}}
|
|
<h3>🔒 SSL Certificate Analysis</h3>
|
|
{{#each analysis.ssl}}
|
|
<table>
|
|
<tr>
|
|
<th colspan="2">Host: {{host}}</th>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Days to Expiry</strong></td>
|
|
<td>{{#if daysToExpiry}}{{daysToExpiry}} days{{else}}N/A{{/if}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Issuer</strong></td>
|
|
<td>{{#if issuer}}{{issuer}}{{else}}N/A{{/if}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Protocol</strong></td>
|
|
<td>{{#if protocol}}{{protocol}}{{else}}N/A{{/if}}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{{#if warningsJson}}
|
|
<div class="alert alert-warning">
|
|
<strong>SSL Warnings:</strong>
|
|
<ul>
|
|
{{#each warningsJson}}
|
|
<li>{{this}}</li>
|
|
{{/each}}
|
|
</ul>
|
|
</div>
|
|
{{/if}}
|
|
{{/each}}
|
|
{{/if}}
|
|
|
|
<!-- SEO Analysis -->
|
|
{{#if analysis.seo}}
|
|
<h3>🔍 SEO Analysis</h3>
|
|
<table>
|
|
<tr>
|
|
<th>SEO Factor</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Robots.txt</strong></td>
|
|
<td>{{analysis.seo.robotsTxtStatus}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Indexing</strong></td>
|
|
<td>{{#if analysis.seo.noindex}}🚫 No Index{{else}}✅ Indexable{{/if}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Following</strong></td>
|
|
<td>{{#if analysis.seo.nofollow}}🚫 No Follow{{else}}✅ Followable{{/if}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Sitemap</strong></td>
|
|
<td>{{#if analysis.seo.sitemapPresent}}✅ Present{{else}}❌ Not Found{{/if}}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{{#if analysis.seo.noindex}}
|
|
<div class="alert alert-warning">
|
|
<strong>⚠️ SEO Warning:</strong> This page is marked as "noindex" and will not appear in search results.
|
|
</div>
|
|
{{/if}}
|
|
{{/if}}
|
|
|
|
<!-- Security Analysis -->
|
|
{{#if analysis.security}}
|
|
<h3>🛡️ Security Analysis</h3>
|
|
<table>
|
|
<tr>
|
|
<th>Security Check</th>
|
|
<th>Result</th>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Safe Browsing</strong></td>
|
|
<td>{{analysis.security.safeBrowsingStatus}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Mixed Content</strong></td>
|
|
<td>{{analysis.security.mixedContent}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>HTTPS Downgrade</strong></td>
|
|
<td>{{#if analysis.security.httpsToHttp}}⚠️ Detected{{else}}✅ None{{/if}}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{{#if analysis.security.httpsToHttp}}
|
|
<div class="alert alert-error">
|
|
<strong>🔒 Security Warning:</strong> HTTPS to HTTP downgrade detected. This can expose sensitive data in transit.
|
|
</div>
|
|
{{/if}}
|
|
{{/if}}
|
|
{{/if}}
|
|
|
|
<!-- Recommendations -->
|
|
<div class="recommendations">
|
|
<h3>💡 Recommendations</h3>
|
|
|
|
<ul>
|
|
{{#if_eq check.status "LOOP"}}
|
|
<li><strong>Fix Redirect Loop:</strong> Review your redirect configuration to prevent infinite loops</li>
|
|
<li><strong>Check Server Configuration:</strong> Ensure proper redirect rules in your web server</li>
|
|
<li><strong>Monitor Performance:</strong> Redirect loops can severely impact site performance</li>
|
|
{{/if_eq}}
|
|
|
|
{{#if check.loopDetected}}
|
|
<li><strong>Immediate Action Required:</strong> Fix the redirect loop to prevent poor user experience</li>
|
|
{{/if}}
|
|
|
|
{{#if analysis.security.httpsToHttp}}
|
|
<li><strong>Security Priority:</strong> Ensure all redirects maintain HTTPS encryption</li>
|
|
<li><strong>Update Configuration:</strong> Modify server rules to prevent HTTPS downgrades</li>
|
|
{{/if}}
|
|
|
|
{{#if analysis.seo.noindex}}
|
|
<li><strong>SEO Review:</strong> Consider if this page should be excluded from search engines</li>
|
|
{{/if}}
|
|
|
|
<!-- General recommendations -->
|
|
<li><strong>Minimize Redirects:</strong> Each redirect adds latency - aim for direct links when possible</li>
|
|
<li><strong>Use 301 for Permanent:</strong> Use HTTP 301 for permanent URL changes for better SEO</li>
|
|
<li><strong>Monitor Regularly:</strong> Set up monitoring to catch redirect issues early</li>
|
|
<li><strong>Test Changes:</strong> Always test redirect changes in staging before production</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="footer">
|
|
<p><strong>Redirect Intelligence v2</strong> - Comprehensive redirect tracking and analysis</p>
|
|
<p>Report generated on {{formatDate generatedAt}} | Check ID: {{check.id}}</p>
|
|
<p>Analysis Engine: Enhanced redirect tracking with SSL, SEO, and security analysis</p>
|
|
</div>
|
|
|
|
<script>
|
|
// Initialize Mermaid
|
|
mermaid.initialize({
|
|
startOnLoad: true,
|
|
theme: 'default',
|
|
themeVariables: {
|
|
primaryColor: '#0ea5e9',
|
|
primaryTextColor: '#1e293b',
|
|
primaryBorderColor: '#0284c7',
|
|
lineColor: '#64748b',
|
|
secondaryColor: '#f1f5f9',
|
|
tertiaryColor: '#f8fafc'
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|