mein-sterntours/dev/frontend-navigation/test-api.html
2026-01-23 17:34:40 +01:00

496 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Navigation API Tester</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #f5f5f5;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
color: #333;
margin-bottom: 10px;
}
.intro {
background: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.config {
background: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.config input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
margin-top: 5px;
}
.endpoint-group {
background: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.endpoint-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.endpoint-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.endpoint-method {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
color: #fff;
}
.method-get {
background: #61affe;
}
.method-post {
background: #49cc90;
}
.endpoint-url {
background: #f7f7f7;
padding: 10px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 14px;
margin-bottom: 15px;
word-break: break-all;
}
.endpoint-description {
color: #666;
margin-bottom: 15px;
}
.test-button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s;
}
.test-button:hover {
background: #45a049;
}
.test-button:disabled {
background: #ccc;
cursor: not-allowed;
}
.result {
margin-top: 15px;
padding: 15px;
border-radius: 4px;
display: none;
}
.result.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.result.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.result-header {
font-weight: bold;
margin-bottom: 10px;
}
.result-meta {
margin-bottom: 10px;
font-size: 14px;
}
.result-data {
background: #f7f7f7;
padding: 10px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 12px;
max-height: 400px;
overflow: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #4CAF50;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-left: 10px;
vertical-align: middle;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.test-all {
background: #2196F3;
color: white;
border: none;
padding: 15px 30px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-bottom: 20px;
transition: background 0.3s;
display: block;
width: 100%;
}
.test-all:hover {
background: #0b7dda;
}
.summary {
background: #fff;
padding: 20px;
border-radius: 8px;
margin-top: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
display: none;
}
.summary h2 {
margin-bottom: 15px;
color: #333;
}
.summary-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 15px;
}
.stat-card {
padding: 15px;
border-radius: 4px;
text-align: center;
}
.stat-card.total {
background: #e3f2fd;
}
.stat-card.success {
background: #d4edda;
}
.stat-card.error {
background: #f8d7da;
}
.stat-number {
font-size: 32px;
font-weight: bold;
margin-bottom: 5px;
}
.stat-label {
font-size: 14px;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<h1>🗺️ Navigation API Tester</h1>
<div class="intro">
<p>Dieses Tool testet alle verfügbaren Endpunkte der Navigation API und zeigt die Ergebnisse in einer strukturierten Form.</p>
</div>
<div class="config">
<label for="baseUrl"><strong>Basis-URL:</strong></label>
<input type="text" id="baseUrl" value="http://localhost/api/navigation" placeholder="http://localhost/api/navigation">
</div>
<button class="test-all" onclick="testAllEndpoints()">Alle Endpunkte testen</button>
<!-- Endpoint 1: Kompletter Navigationsbaum -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Kompletter Navigationsbaum</div>
<span class="endpoint-method method-get">GET</span>
</div>
<div class="endpoint-url">/tree</div>
<div class="endpoint-description">
Gibt den kompletten hierarchischen Navigationsbaum mit allen Seiten zurück.
</div>
<button class="test-button" onclick="testEndpoint('tree', 'GET')">Testen</button>
<div class="result" id="result-tree"></div>
</div>
<!-- Endpoint 2: Aktive Navigationspunkte -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Nur aktive Navigationspunkte</div>
<span class="endpoint-method method-get">GET</span>
</div>
<div class="endpoint-url">/tree/active</div>
<div class="endpoint-description">
Gibt nur aktive Seiten zurück (status = 1 und show_in_navi = 1).
</div>
<button class="test-button" onclick="testEndpoint('tree/active', 'GET')">Testen</button>
<div class="result" id="result-tree-active"></div>
</div>
<!-- Endpoint 3: Teilbaum -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Teilbaum ab Root-ID</div>
<span class="endpoint-method method-get">GET</span>
</div>
<div class="endpoint-url">/tree/{rootId}</div>
<div class="endpoint-description">
Gibt einen Teilbaum zurück, beginnend mit der angegebenen Page-ID.<br>
<input type="number" id="subtreeId" placeholder="Root Page ID" value="1" style="margin-top: 10px; padding: 8px; width: 200px;">
</div>
<button class="test-button" onclick="testEndpoint('tree/' + document.getElementById('subtreeId').value, 'GET')">Testen</button>
<div class="result" id="result-tree-subtree"></div>
</div>
<!-- Endpoint 4: Flache Liste -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Flache Liste</div>
<span class="endpoint-method method-get">GET</span>
</div>
<div class="endpoint-url">/flat</div>
<div class="endpoint-description">
Gibt alle Navigationspunkte als flache Liste zurück (ohne parent-child Beziehung).
</div>
<button class="test-button" onclick="testEndpoint('flat', 'GET')">Testen</button>
<div class="result" id="result-flat"></div>
</div>
<!-- Endpoint 5: Breadcrumb -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Breadcrumb-Pfad</div>
<span class="endpoint-method method-get">GET</span>
</div>
<div class="endpoint-url">/breadcrumb/{pageId}</div>
<div class="endpoint-description">
Gibt den Breadcrumb-Pfad für eine bestimmte Seite zurück.<br>
<input type="number" id="breadcrumbId" placeholder="Page ID" value="1" style="margin-top: 10px; padding: 8px; width: 200px;">
</div>
<button class="test-button" onclick="testEndpoint('breadcrumb/' + document.getElementById('breadcrumbId').value, 'GET')">Testen</button>
<div class="result" id="result-breadcrumb"></div>
</div>
<!-- Endpoint 6: Cache leeren -->
<div class="endpoint-group">
<div class="endpoint-header">
<div class="endpoint-title">Cache leeren</div>
<span class="endpoint-method method-post">POST</span>
</div>
<div class="endpoint-url">/cache/clear</div>
<div class="endpoint-description">
Löscht den kompletten Navigation-Cache.
</div>
<button class="test-button" onclick="testEndpoint('cache/clear', 'POST')">Testen</button>
<div class="result" id="result-cache-clear"></div>
</div>
<!-- Zusammenfassung -->
<div class="summary" id="summary">
<h2>Test-Zusammenfassung</h2>
<div class="summary-stats">
<div class="stat-card total">
<div class="stat-number" id="stat-total">0</div>
<div class="stat-label">Gesamt</div>
</div>
<div class="stat-card success">
<div class="stat-number" id="stat-success">0</div>
<div class="stat-label">Erfolgreich</div>
</div>
<div class="stat-card error">
<div class="stat-number" id="stat-error">0</div>
<div class="stat-label">Fehlgeschlagen</div>
</div>
</div>
</div>
</div>
<script>
let testResults = {};
function getBaseUrl() {
return document.getElementById('baseUrl').value.replace(/\/$/, '');
}
async function testEndpoint(endpoint, method = 'GET') {
const resultId = 'result-' + endpoint.replace(/\//g, '-').replace(/\d+/g, 'subtree');
const resultDiv = document.getElementById(resultId);
resultDiv.style.display = 'block';
resultDiv.className = 'result';
resultDiv.innerHTML = '<div class="result-header">Teste...<span class="loading"></span></div>';
const url = getBaseUrl() + '/' + endpoint;
try {
const startTime = performance.now();
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
const endTime = performance.now();
const duration = Math.round(endTime - startTime);
const data = await response.json();
testResults[endpoint] = response.ok;
if (response.ok) {
resultDiv.className = 'result success';
let html = '<div class="result-header">✓ Erfolgreich</div>';
html += '<div class="result-meta">';
html += `<strong>HTTP Status:</strong> ${response.status}<br>`;
html += `<strong>Dauer:</strong> ${duration}ms<br>`;
if (data.meta) {
html += '<strong>Metadaten:</strong><br>';
for (const [key, value] of Object.entries(data.meta)) {
html += `&nbsp;&nbsp;${key}: ${value}<br>`;
}
}
html += '</div>';
if (data.data) {
html += '<div class="result-data">';
html += JSON.stringify(data.data, null, 2);
html += '</div>';
}
resultDiv.innerHTML = html;
} else {
resultDiv.className = 'result error';
let html = '<div class="result-header">✗ Fehler</div>';
html += '<div class="result-meta">';
html += `<strong>HTTP Status:</strong> ${response.status}<br>`;
html += `<strong>Dauer:</strong> ${duration}ms<br>`;
if (data.error) {
html += `<strong>Fehlermeldung:</strong> ${data.error}`;
}
html += '</div>';
resultDiv.innerHTML = html;
}
} catch (error) {
testResults[endpoint] = false;
resultDiv.className = 'result error';
resultDiv.innerHTML = `
<div class="result-header">✗ Fehler</div>
<div class="result-meta">
<strong>Fehlermeldung:</strong> ${error.message}<br>
<br>
Mögliche Ursachen:<br>
• Server läuft nicht<br>
• CORS-Probleme<br>
• Falsche Base-URL<br>
• Netzwerkfehler
</div>
`;
}
}
async function testAllEndpoints() {
testResults = {};
const endpoints = [
{ path: 'tree', method: 'GET' },
{ path: 'tree/active', method: 'GET' },
{ path: 'tree/1', method: 'GET' },
{ path: 'flat', method: 'GET' },
{ path: 'breadcrumb/1', method: 'GET' },
{ path: 'cache/clear', method: 'POST' }
];
for (const endpoint of endpoints) {
await testEndpoint(endpoint.path, endpoint.method);
await new Promise(resolve => setTimeout(resolve, 500)); // Kurze Pause zwischen Tests
}
updateSummary();
}
function updateSummary() {
const total = Object.keys(testResults).length;
const success = Object.values(testResults).filter(r => r === true).length;
const error = total - success;
document.getElementById('stat-total').textContent = total;
document.getElementById('stat-success').textContent = success;
document.getElementById('stat-error').textContent = error;
document.getElementById('summary').style.display = 'block';
}
</script>
</body>
</html>