auth-yes/ui/components/sessions/SessionDeck.tsx
google-labs-jules[bot] d86642ce31 feat: Sessions UI overhaul and backend revocation fix
- Update `DELETE /api/sessions/:id` in `server/routes/sessions.ts` to allow event creators to delete guests' sessions.
- Update page hierarchy and top headings in `ui/components/SessionsPage.tsx`.
- Refactor `EventAttendeesDrawer.tsx` to `EventGuestsDrawer.tsx` as a fixed slide-over overlay.
- Add multi-event compact view toggle with `localStorage` persistence in `EventCockpitDeck.tsx`.
- Standardize dynamic countdown pills across `EventCockpitDeck.tsx`, `EventGuestsDrawer.tsx`, `SessionDeck.tsx`, and `SessionTable.tsx`.
- Optimize mobile session deck in `SessionDeck.tsx`.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-27 04:06:19 +00:00

123 lines
5.0 KiB
TypeScript
Raw 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.

export const SessionDeck = (
{ sessions, currentSessionId }: {
sessions: any[];
currentSessionId: string;
},
) => {
return (
<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>
<div style="display: flex; align-items: center; gap: 0.5rem;">
{isAgent
? <span class="badge badge-info">Delegated</span>
: isCurrent
? <span class="badge badge-success">Active Now</span>
: <span class="badge badge-secondary">Active</span>}
{!isCurrent && (
<button
type="button"
class="btn-danger revoke-btn"
data-session-id={session.id}
style="padding: 0.15rem 0.5rem; font-size: 0.75rem; min-height: 24px; border-radius: var(--radius-sm);"
>
🗑️ Revoke
</button>
)}
</div>
</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>
<span
class="countdown-pill"
data-expires-at={session.expires_at}
>
⏳ 0h 0m left · (Expires{" "}
{new Date(session.expires_at).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
})})
</span>
</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>
{isAgent && (
<div style="display: flex; gap: 0.5rem;">
<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>
</div>
)}
</div>
);
})
)}
</div>
);
};