Add route tester controls
This commit is contained in:
197
routes/web.php
197
routes/web.php
@@ -37,6 +37,11 @@ Route::get('/', function () {
|
|||||||
</div>
|
</div>
|
||||||
<div class="auth %s">%s</div>
|
<div class="auth %s">%s</div>
|
||||||
<a href="%s" target="_blank" rel="noreferrer">%s</a>
|
<a href="%s" target="_blank" rel="noreferrer">%s</a>
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" data-action="open" data-url="%s">Abrir</button>
|
||||||
|
<button type="button" data-action="copy" data-url="%s">Copiar</button>
|
||||||
|
<button type="button" data-action="request" data-auth="%s" data-url="%s">Testar</button>
|
||||||
|
</div>
|
||||||
</article>',
|
</article>',
|
||||||
e($route['method']),
|
e($route['method']),
|
||||||
e($route['name']),
|
e($route['name']),
|
||||||
@@ -44,6 +49,10 @@ Route::get('/', function () {
|
|||||||
e($route['auth']),
|
e($route['auth']),
|
||||||
e($url),
|
e($url),
|
||||||
e($url),
|
e($url),
|
||||||
|
e($url),
|
||||||
|
e($url),
|
||||||
|
e($route['type']),
|
||||||
|
e($url),
|
||||||
);
|
);
|
||||||
})->implode('');
|
})->implode('');
|
||||||
|
|
||||||
@@ -119,6 +128,53 @@ Route::get('/', function () {
|
|||||||
background: rgba(23, 33, 61, 0.86);
|
background: rgba(23, 33, 61, 0.86);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.token-panel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: 12px;
|
||||||
|
width: min(860px, 100%);
|
||||||
|
margin: 0 auto 28px;
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid var(--panel-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(23, 33, 61, 0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-panel label {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-panel input {
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 42px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid var(--panel-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--code);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border: 1px solid rgba(255, 216, 74, 0.42);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(255, 216, 74, 0.12);
|
||||||
|
color: var(--gold);
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: rgba(255, 216, 74, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.status strong {
|
.status strong {
|
||||||
color: var(--gold);
|
color: var(--gold);
|
||||||
}
|
}
|
||||||
@@ -216,6 +272,51 @@ Route::get('/', function () {
|
|||||||
outline: 1px solid var(--gold);
|
outline: 1px solid var(--gold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions button {
|
||||||
|
flex: 1 1 108px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
display: none;
|
||||||
|
margin-top: 28px;
|
||||||
|
padding: 18px;
|
||||||
|
border: 1px solid var(--panel-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(8, 11, 24, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
max-height: 420px;
|
||||||
|
margin: 0;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
color: #e8edff;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
margin-top: 34px;
|
margin-top: 34px;
|
||||||
color: #697399;
|
color: #697399;
|
||||||
@@ -232,6 +333,10 @@ Route::get('/', function () {
|
|||||||
.grid {
|
.grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.token-panel {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -248,12 +353,104 @@ Route::get('/', function () {
|
|||||||
<span>Service: <strong>api-ranking-jogos</strong></span>
|
<span>Service: <strong>api-ranking-jogos</strong></span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="token-panel" aria-label="Token JWT">
|
||||||
|
<label for="jwt-token">JWT para testar rotas privadas</label>
|
||||||
|
<input id="jwt-token" type="password" autocomplete="off" placeholder="Cole somente o token, sem Bearer">
|
||||||
|
<button type="button" id="save-token">Salvar token</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="grid">
|
<section class="grid">
|
||||||
{$cards}
|
{$cards}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="result" class="result" aria-live="polite">
|
||||||
|
<div class="result-header">
|
||||||
|
<strong id="result-title">Resposta</strong>
|
||||||
|
<span id="result-status"></span>
|
||||||
|
</div>
|
||||||
|
<pre id="result-body"></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
<footer>api-ranking-jogos - Railway</footer>
|
<footer>api-ranking-jogos - Railway</footer>
|
||||||
</main>
|
</main>
|
||||||
|
<script>
|
||||||
|
const tokenInput = document.getElementById('jwt-token');
|
||||||
|
const saveToken = document.getElementById('save-token');
|
||||||
|
const result = document.getElementById('result');
|
||||||
|
const resultTitle = document.getElementById('result-title');
|
||||||
|
const resultStatus = document.getElementById('result-status');
|
||||||
|
const resultBody = document.getElementById('result-body');
|
||||||
|
|
||||||
|
tokenInput.value = localStorage.getItem('rankingJwtToken') || '';
|
||||||
|
|
||||||
|
saveToken.addEventListener('click', () => {
|
||||||
|
localStorage.setItem('rankingJwtToken', tokenInput.value.trim());
|
||||||
|
saveToken.textContent = 'Salvo';
|
||||||
|
setTimeout(() => saveToken.textContent = 'Salvar token', 1400);
|
||||||
|
});
|
||||||
|
|
||||||
|
function showResult(title, status, body) {
|
||||||
|
result.classList.add('visible');
|
||||||
|
resultTitle.textContent = title;
|
||||||
|
resultStatus.textContent = status;
|
||||||
|
resultBody.textContent = body;
|
||||||
|
result.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyText(text) {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', async (event) => {
|
||||||
|
const button = event.target.closest('button[data-action]');
|
||||||
|
|
||||||
|
if (!button) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = button.dataset.url;
|
||||||
|
const action = button.dataset.action;
|
||||||
|
|
||||||
|
if (action === 'open') {
|
||||||
|
window.open(url, '_blank', 'noreferrer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'copy') {
|
||||||
|
await copyText(url);
|
||||||
|
const previous = button.textContent;
|
||||||
|
button.textContent = 'Copiado';
|
||||||
|
setTimeout(() => button.textContent = previous, 1200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = { Accept: 'application/json' };
|
||||||
|
const authType = button.dataset.auth;
|
||||||
|
const token = tokenInput.value.trim();
|
||||||
|
|
||||||
|
if ((authType === 'jwt' || authType === 'diagnostic') && token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((authType === 'jwt' || authType === 'diagnostic') && !token) {
|
||||||
|
showResult('Token ausente', '401 local', 'Cole um JWT no campo acima para testar esta rota.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
showResult('Carregando', '...', '');
|
||||||
|
const response = await fetch(url, { headers });
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
const body = contentType.includes('application/json')
|
||||||
|
? JSON.stringify(await response.json(), null, 2)
|
||||||
|
: await response.text();
|
||||||
|
|
||||||
|
showResult(url, `${response.status} ${response.statusText}`, body);
|
||||||
|
} catch (error) {
|
||||||
|
showResult(url, 'Erro', error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
HTML);
|
HTML);
|
||||||
|
|||||||
Reference in New Issue
Block a user