auth-yes/ui/components/SessionsPage.tsx
google-labs-jules[bot] 296bc6a9c3 Hi, Jules here! I have successfully refactored the SessionsPage by decomposing it into pure JSX subcomponents. Here is a summary of what I accomplished:
- Created the `ui/components/sessions/` directory.
- Extracted `EventCockpitDeck.tsx`, `DirectPassDrawer.tsx`, `WorkshopDrawer.tsx`, and `ScopeModal.tsx` from `ui/components/SessionsPage.tsx`.
- Refactored `SessionsPage.tsx` to import and assemble these subcomponents cleanly.
- Preserved zero React dependencies, keeping it pure Hono SSR JSX.
- Preserved all inline client-side JavaScript, DOM IDs, and form submission handlers.
- Formatted and linted all code via `deno fmt` and `deno task lint`.
- Verified that all tests are passing.

Let me know if you need any further adjustments!

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-25 23:19:58 +00:00

754 lines
32 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { AuthenticatedLayout } from "./AuthenticatedLayout.tsx";
import { EventCockpitDeck } from "./sessions/EventCockpitDeck.tsx";
import { DirectPassDrawer } from "./sessions/DirectPassDrawer.tsx";
import { WorkshopDrawer } from "./sessions/WorkshopDrawer.tsx";
import { ScopeModal } from "./sessions/ScopeModal.tsx";
export const SessionsPage = ({
sessions,
currentSessionId,
apps = [],
isAdmin = false,
eventPasses = [],
}: {
sessions: any[];
currentSessionId: string;
apps?: any[];
isAdmin?: boolean;
eventPasses?: any[];
}) => {
return (
<AuthenticatedLayout
title="Sessions & Delegations"
currentPath="/dashboard/sessions"
isAdmin={isAdmin}
>
<div
id="status-banner"
style="display: none; margin-bottom: 1rem; padding: 0.75rem 1rem; border-radius: var(--radius-md); font-size: 0.9rem;"
/>
<EventCockpitDeck eventPasses={eventPasses} />
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 1rem;">
<div>
<h1 style="font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem 0; color: var(--text-primary);">
Active Sessions & Passes
</h1>
<p style="color: var(--text-secondary); margin: 0; font-size: 0.95rem;">
Manage logins, mint 1:1 ephemeral links & CLI tokens, or launch
multi-claim workshop event passes.
</p>
</div>
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
<button
type="button"
class="btn-primary"
style="min-height: 42px; box-shadow: var(--shadow-sm); display: inline-flex; align-items: center; gap: 0.4rem;"
onclick="openDelegateDrawer()"
>
<span style="font-size: 1.1rem;">🔑</span>
<span>+ Delegate Session</span>
</button>
</div>
</div>
{/* Delegate Session Drawer */}
<div
id="delegateDrawer"
class="card"
style="display: none; border-left: 4px solid var(--primary); margin-bottom: 1.5rem;"
>
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem;">
<div style="width: 100%;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<h3 style="margin: 0 0 0.25rem 0; color: var(--text-primary);">
Create New Pass / Session
</h3>
<button
type="button"
onclick="closeDelegateDrawer()"
style="background: none; border: none; font-size: 1.3rem; color: var(--text-muted); cursor: pointer;"
>
&times;
</button>
</div>
<div style="display: flex; background: var(--surface-muted); padding: 4px; border-radius: var(--radius-sm); border: 1px solid var(--border-subtle); gap: 4px; margin-top: 1rem; margin-bottom: 1rem;">
<button
type="button"
id="tabBtnDirectPass"
class="delegate-tab-btn active"
onclick="switchDelegateTab('tabDirectPass')"
>
🔑 1:1 Direct Pass
</button>
<button
type="button"
id="tabBtnWorkshopPass"
class="delegate-tab-btn"
onclick="switchDelegateTab('tabWorkshopPass')"
>
🎟 Multi-Claim Workshop Pass
</button>
</div>
</div>
</div>
<DirectPassDrawer apps={apps} isAdmin={isAdmin} />
<WorkshopDrawer apps={apps} />
</div>
<ScopeModal apps={apps} />
{/* Desktop Table View (≥ 768px) */}
<div class="card desktop-only" style="display: none;">
<div class="table-container">
<table>
<thead>
<tr>
<th>Type & Label</th>
<th>Permissions</th>
<th>Activity</th>
<th>Expires</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{sessions.length === 0
? (
<tr>
<td
colSpan={5}
style="text-align: center; padding: 2rem; color: var(--text-muted);"
>
No active sessions found.
</td>
</tr>
)
: (
sessions.map((session) => {
const isCurrent = session.id === currentSessionId;
const isAgent = !!session.is_agent;
const scopes = Array.isArray(session.custom_scopes)
? session.custom_scopes
: [];
return (
<tr key={session.id}>
<td>
<div style="display: flex; align-items: center; gap: 0.5rem;">
<span style="font-size: 1.1rem;">
{isAgent ? "🔑" : isCurrent ? "📱" : "💻"}
</span>
<div>
<strong style="color: var(--text-primary);">
{session.label ||
(isCurrent ? "This Device" : "Remote Device")}
</strong>
<div style="font-size: 0.75rem; color: var(--text-muted); font-family: monospace;">
{session.id.substring(0, 14)}...
</div>
</div>
</div>
</td>
<td>
{isAgent
? (
<span class="badge badge-info">
{scopes.length > 0
? `${scopes.length} Scopes`
: "Delegated"}
</span>
)
: (
<span class="badge badge-success">
Interactive
</span>
)}
</td>
<td style="color: var(--text-secondary); font-size: 0.85rem;">
{session.last_activity_action
? (
<div>
<span style="color: var(--primary); font-family: monospace; font-size: 0.8rem;">
{session.last_activity_action}
</span>
<div style="font-size: 0.75rem; color: var(--text-muted);">
{new Date(
session.last_activity_at ||
session.created_at,
).toLocaleTimeString()}
</div>
</div>
)
: (
<span>
{new Date(session.created_at)
.toLocaleDateString()}
</span>
)}
</td>
<td style="color: var(--text-secondary); font-size: 0.85rem;">
{new Date(session.expires_at).toLocaleString()}
</td>
<td>
<div style="display: flex; gap: 0.35rem; align-items: center;">
{isAgent && (
<>
<button
type="button"
class="btn-outline"
style="padding: 0.25rem 0.5rem; font-size: 0.75rem; min-height: 30px;"
onclick={`extendSession('${session.id}', 1)`}
title="Extend session by 1 hour"
>
+1h
</button>
<button
type="button"
class="btn-outline"
style="padding: 0.25rem 0.5rem; font-size: 0.75rem; min-height: 30px;"
onclick={`openEditScopesModal('${session.id}', '${
session.label || "Delegated"
}', ${
JSON.stringify(JSON.stringify(scopes))
})`}
title="Edit permissions"
>
Scopes
</button>
</>
)}
{!isCurrent && (
<button
type="button"
class="btn-danger revoke-btn"
data-session-id={session.id}
style="padding: 0.25rem 0.65rem; font-size: 0.8rem; min-height: 30px;"
>
Revoke
</button>
)}
</div>
</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
</div>
{/* Mobile Adaptive Cards View (< 768px) */}
<div
class="mobile-only"
style="display: flex; flex-direction: column; gap: 1rem;"
>
{sessions.length === 0
? (
<div class="card" style="text-align: center; padding: 2rem;">
<p style="color: var(--text-muted); margin: 0;">
No active sessions found.
</p>
</div>
)
: (
sessions.map((session) => {
const isCurrent = session.id === currentSessionId;
const isAgent = !!session.is_agent;
const scopes = Array.isArray(session.custom_scopes)
? session.custom_scopes
: [];
return (
<div class="card" key={session.id} style="margin-bottom: 0;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
<div style="display: flex; align-items: center; gap: 0.65rem;">
<div style="display: flex; align-items: center; justify-content: center; width: 38px; height: 38px; background: var(--surface-muted); border-radius: var(--radius-md); font-size: 1.2rem;">
{isAgent ? "🔑" : isCurrent ? "📱" : "💻"}
</div>
<div>
<div style="font-weight: 700; font-size: 0.95rem; color: var(--text-primary);">
{session.label ||
(isCurrent ? "This Device" : "Remote Device")}
</div>
<div style="font-size: 0.75rem; color: var(--text-muted); font-family: monospace;">
{session.id.substring(0, 14)}...
</div>
</div>
</div>
{isAgent
? <span class="badge badge-info">Delegated</span>
: isCurrent
? <span class="badge badge-success">Active Now</span>
: <span class="badge badge-secondary">Active</span>}
</div>
<div style="font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 1rem; line-height: 1.6;">
{isAgent && (
<div style="margin-bottom: 0.25rem;">
<strong>Scopes:</strong>{" "}
{scopes.length > 0 ? scopes.join(", ") : "Delegated"}
</div>
)}
<div>
<strong>Expires:</strong>{" "}
{new Date(session.expires_at).toLocaleString()}
</div>
{session.last_activity_action && (
<div>
<strong>Last Active:</strong>{" "}
{session.last_activity_action} ({new Date(
session.last_activity_at || session.created_at,
).toLocaleTimeString()})
</div>
)}
</div>
<div style="display: flex; gap: 0.5rem;">
{isAgent && (
<>
<button
type="button"
class="btn-outline"
style="flex: 1; justify-content: center; min-height: 38px; font-size: 0.8rem;"
onclick={`extendSession('${session.id}', 1)`}
>
+1h Extend
</button>
<button
type="button"
class="btn-outline"
style="flex: 1; justify-content: center; min-height: 38px; font-size: 0.8rem;"
onclick={`openEditScopesModal('${session.id}', '${
session.label || "Delegated"
}', ${JSON.stringify(JSON.stringify(scopes))})`}
>
Scopes
</button>
</>
)}
{!isCurrent && (
<button
type="button"
class="btn-danger revoke-btn"
data-session-id={session.id}
style="flex: 1; justify-content: center; min-height: 38px; font-size: 0.85rem;"
>
Revoke
</button>
)}
</div>
</div>
);
})
)}
</div>
<style>
{`
@media (min-width: 768px) {
.desktop-only { display: block !important; }
.mobile-only { display: none !important; }
}
@media (max-width: 767px) {
.desktop-only { display: none !important; }
.mobile-only { display: flex !important; }
}
.pill-btn {
background: var(--surface-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-full);
padding: 0.4rem 0.85rem;
font-size: 0.85rem;
font-weight: 600;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.15s ease;
}
.pill-btn:hover {
border-color: var(--primary);
color: var(--primary);
}
.pill-btn.active {
background: var(--primary-light);
border-color: var(--primary);
color: var(--primary);
}
.delegate-tab-btn {
flex: 1;
padding: 0.5rem 0.75rem;
border-radius: var(--radius-sm);
border: none;
font-weight: 600;
cursor: pointer;
transition: all 0.15s;
background: transparent;
color: var(--text-secondary);
}
.delegate-tab-btn.active {
background: var(--surface-card);
color: var(--primary);
box-shadow: var(--shadow-xs);
}
`}
</style>
<script
dangerouslySetInnerHTML={{
__html: `
let lastMintedToken = "";
function showNotice(msg, isError) {
const banner = document.getElementById('status-banner');
banner.textContent = msg;
banner.style.display = 'block';
banner.style.background = isError ? 'var(--danger-bg)' : 'var(--success-bg)';
banner.style.color = isError ? 'var(--danger-text)' : 'var(--success-text)';
banner.style.border = isError ? '1px solid var(--danger-border)' : '1px solid var(--success-border)';
setTimeout(() => { banner.style.display = 'none'; }, 5000);
}
function openDelegateDrawer() {
document.getElementById('delegateDrawer').style.display = 'block';
document.getElementById('delegateDrawer').scrollIntoView({ behavior: 'smooth' });
}
function closeDelegateDrawer() {
document.getElementById('delegateDrawer').style.display = 'none';
}
function switchDelegateTab(tabId) {
document.getElementById('tabDirectPass').style.display = 'none';
document.getElementById('tabWorkshopPass').style.display = 'none';
document.getElementById('tabBtnDirectPass').classList.remove('active');
document.getElementById('tabBtnWorkshopPass').classList.remove('active');
document.getElementById(tabId).style.display = 'block';
if (tabId === 'tabDirectPass') {
document.getElementById('tabBtnDirectPass').classList.add('active');
} else {
document.getElementById('tabBtnWorkshopPass').classList.add('active');
}
}
function selectSeats(btn, count) {
document.querySelectorAll('.seat-pill').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.getElementById('eventMaxSeats').value = count;
}
function selectEventLifespan(btn, hours) {
document.querySelectorAll('.event-lifespan-pill').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.getElementById('eventLifespanHours').value = hours;
}
function handleTargetAppChange(appName) {
if (appName) {
const scopeVal = 'app:' + appName;
document.querySelectorAll('.scope-checkbox').forEach(cb => {
if (cb.value === scopeVal) cb.checked = true;
});
}
}
function selectLifespan(btn, hours) {
document.querySelectorAll('.lifespan-pill').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.getElementById('delegateHours').value = hours;
}
function selectMode(btn, mode) {
document.querySelectorAll('.mode-pill').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.getElementById('delegateMode').value = mode;
const accordion = document.getElementById('customScopesSection');
if (mode === 'custom') {
accordion.open = true;
}
}
async function handleDelegateSession(e) {
e.preventDefault();
const label = document.getElementById('delegateLabel').value.trim();
const lifespanHours = parseInt(document.getElementById('delegateHours').value) || 1;
let mode = document.getElementById('delegateMode').value;
const targetApp = document.getElementById('delegateTargetApp') ? document.getElementById('delegateTargetApp').value : '';
const customScopes = [];
if (targetApp) {
customScopes.push('app:' + targetApp);
}
if (mode === 'custom' || targetApp) {
document.querySelectorAll('.scope-checkbox:checked').forEach(cb => {
if (!customScopes.includes(cb.value)) {
customScopes.push(cb.value);
}
});
if (targetApp && mode !== 'custom' && mode !== 'admin') {
mode = 'custom';
}
}
const btn = document.getElementById('submitDelegateBtn');
btn.disabled = true;
btn.textContent = 'Minting...';
try {
const res = await fetch('/api/sessions/delegate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ label, lifespanHours, mode, customScopes }),
});
const data = await res.json();
if (res.ok) {
lastMintedToken = data.token;
document.getElementById('handoffMagicLinkText').textContent = window.location.origin + '/pass?token=' + data.token;
document.getElementById('handoffCliText').textContent = 'export AUTH_YES_TOKEN="' + data.token + '"';
document.getElementById('handoffCurlText').textContent = '-H "Authorization: Bearer ' + data.token + '"';
document.getElementById('handoffModal').style.display = 'block';
showNotice('Delegated session created for: ' + data.label, false);
} else {
showNotice(data.error || 'Failed to delegate session', true);
}
} catch (err) {
showNotice('Network error delegating session', true);
} finally {
btn.disabled = false;
btn.textContent = 'Mint & Delegate Session';
}
}
async function handleCreateEvent(e) {
e.preventDefault();
const name = document.getElementById('eventName').value.trim();
const appId = document.getElementById('eventAppId').value || null;
const role = document.getElementById('eventRole').value || 'viewer';
const maxSeats = parseInt(document.getElementById('eventMaxSeats').value) || 0;
const lifespanHours = parseInt(document.getElementById('eventLifespanHours').value) || 3;
const slug = document.getElementById('eventSlug').value.trim() || undefined;
const pinCode = document.getElementById('eventPinCode').value.trim() || undefined;
const btn = document.getElementById('submitEventBtn');
btn.disabled = true;
btn.textContent = 'Launching...';
try {
const res = await fetch('/api/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, appId, role, maxSeats, lifespanHours, slug, pinCode }),
});
const data = await res.json();
if (res.ok && data.success) {
const ev = data.event;
document.getElementById('createdEventTitle').textContent = '🎟️ ' + ev.name + ' Live!';
document.getElementById('eventHandoffPin').textContent = ev.pin_code;
document.getElementById('eventHandoffLink').textContent = window.location.origin + '/e/' + ev.slug;
document.getElementById('eventHandoffCli').textContent = 'curl -sSL ' + window.location.origin + '/join/' + ev.slug + '?format=env | source /dev/stdin';
document.getElementById('eventHandoffModal').style.display = 'block';
showNotice('Workshop pass created: ' + ev.name, false);
} else {
showNotice(data.error || 'Failed to create event pass', true);
}
} catch (err) {
showNotice('Network error creating event pass', true);
} finally {
btn.disabled = false;
btn.textContent = '🎟️ Launch Workshop Pass';
}
}
function copyEventHandoff(type) {
let text = '';
if (type === 'pin') text = document.getElementById('eventHandoffPin').textContent;
if (type === 'link') text = document.getElementById('eventHandoffLink').textContent;
if (type === 'cli') text = document.getElementById('eventHandoffCli').textContent;
navigator.clipboard.writeText(text);
showNotice('Copied to clipboard: ' + text, false);
}
function closeEventHandoffModal() {
document.getElementById('eventHandoffModal').style.display = 'none';
window.location.reload();
}
function copyHandoff(type) {
let text = '';
if (type === 'link') text = document.getElementById('handoffLinkText').textContent;
if (type === 'cli') text = document.getElementById('handoffCliText').textContent;
if (type === 'curl') text = document.getElementById('handoffCurlText').textContent;
if (type === 'magic') text = document.getElementById('handoffMagicLinkText').textContent;
navigator.clipboard.writeText(text);
showNotice('Copied to clipboard: ' + text, false);
}
function closeHandoffModal() {
document.getElementById('handoffModal').style.display = 'none';
window.location.reload();
}
async function extendSession(sessionId, hours) {
try {
const res = await fetch('/api/sessions/' + sessionId + '/extend', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ extendHours: hours }),
});
if (res.ok) {
showNotice('Session extended by ' + hours + ' hour(s)!', false);
setTimeout(() => window.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || 'Failed to extend session', true);
}
} catch (err) {
showNotice('Network error extending session', true);
}
}
function openEditScopesModal(sessionId, label, scopesJson) {
const scopes = JSON.parse(scopesJson || '[]');
document.getElementById('editScopesSessionId').value = sessionId;
document.getElementById('editScopesLabel').textContent = label;
document.querySelectorAll('.edit-scope-chk').forEach(cb => {
cb.checked = scopes.includes(cb.value);
});
document.getElementById('editScopesModal').style.display = 'flex';
}
function closeEditScopesModal() {
document.getElementById('editScopesModal').style.display = 'none';
}
async function saveUpdatedScopes() {
const sessionId = document.getElementById('editScopesSessionId').value;
const customScopes = [];
document.querySelectorAll('.edit-scope-chk:checked').forEach(cb => {
customScopes.push(cb.value);
});
try {
const res = await fetch('/api/sessions/' + sessionId + '/scopes', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ customScopes }),
});
if (res.ok) {
showNotice('Session scopes updated!', false);
setTimeout(() => window.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || 'Failed to update scopes', true);
}
} catch (err) {
showNotice('Network error updating scopes', true);
}
}
function copyText(text) {
navigator.clipboard.writeText(text);
showNotice('Copied to clipboard!', false);
}
// Event Cockpit Actions
document.querySelectorAll('.extend-event-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
const eventId = e.currentTarget.getAttribute('data-event-id');
e.currentTarget.disabled = true;
try {
const res = await fetch('/api/events/' + eventId + '/extend', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ extendHours: 1 })
});
if (res.ok) {
showNotice('Event extended by 1 hour!', false);
setTimeout(() => window.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || 'Failed to extend event', true);
e.currentTarget.disabled = false;
}
} catch (err) {
showNotice('Network error extending event', true);
e.currentTarget.disabled = false;
}
});
});
document.querySelectorAll('.end-event-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
if (!confirm('Are you sure you want to end this workshop? This will immediately revoke ALL active guest sessions and they will lose access.')) return;
const eventId = e.currentTarget.getAttribute('data-event-id');
e.currentTarget.disabled = true;
e.currentTarget.textContent = 'Revoking...';
try {
const res = await fetch('/api/events/' + eventId + '/end', {
method: 'POST',
});
if (res.ok) {
showNotice('Workshop ended and all sessions revoked.', false);
setTimeout(() => window.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || 'Failed to end event', true);
e.currentTarget.disabled = false;
e.currentTarget.textContent = '🔴 End & Revoke All';
}
} catch (err) {
showNotice('Network error ending event', true);
e.currentTarget.disabled = false;
e.currentTarget.textContent = '🔴 End & Revoke All';
}
});
});
// Revoke handler
document.querySelectorAll('.revoke-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
if (!confirm('Revoke this session immediately?')) return;
const sessionId = e.currentTarget.getAttribute('data-session-id');
const originalText = e.currentTarget.textContent;
e.currentTarget.textContent = 'Revoking...';
e.currentTarget.disabled = true;
try {
const res = await fetch('/api/sessions/' + sessionId, {
method: 'DELETE'
});
if (res.ok) {
window.location.reload();
} else {
const data = await res.json();
showNotice(data.error || 'Failed to revoke session', true);
e.currentTarget.textContent = originalText;
e.currentTarget.disabled = false;
}
} catch (err) {
showNotice('Network error revoking session', true);
e.currentTarget.textContent = originalText;
e.currentTarget.disabled = false;
}
});
});
`,
}}
>
</script>
</AuthenticatedLayout>
);
};