OK display sessioni ed editing

This commit is contained in:
Samuele E. Locatelli
2025-09-05 10:03:38 +00:00
parent 595c337095
commit ccd3855a9d
+91 -79
View File
@@ -1,15 +1,17 @@
// src/SessionTable.jsx
import React, { useEffect, useState, useRef } from "react";
import { getSessionId } from "./useSessionId";
import SessionEditor from "./SessionEditor";
export default function SessionTable({ userId, onSelectSession, onClosePanel }) {
const [sessions, setSessions] = useState([]);
const [loading, setLoading] = useState(false);
const [editingSessionId, setEditingSessionId] = useState(null);
const [editName, setEditName] = useState("");
const activeSessionId = getSessionId();
const wsRef = useRef(null);
const [showEditor, setShowEditor] = useState(false);
const [editorSession, setEditorSession] = useState(null);
const fetchSessions = async () => {
if (!userId) return;
setLoading(true);
@@ -27,10 +29,8 @@ export default function SessionTable({ userId, onSelectSession, onClosePanel })
useEffect(() => {
if (!userId) return;
// Caricamento iniziale
fetchSessions();
// Apri WebSocket
const wsUrl = `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/v1/ws/sessions?user_id=${userId}`;
const ws = new WebSocket(wsUrl);
wsRef.current = ws;
@@ -42,7 +42,6 @@ export default function SessionTable({ userId, onSelectSession, onClosePanel })
ws.onmessage = (event) => {
try {
const msg = JSON.parse(event.data);
// Possibili tipi di evento: full_list, created, updated, deleted
if (msg.type === "full_list") {
setSessions(msg.sessions);
} else if (msg.type === "created") {
@@ -73,84 +72,76 @@ export default function SessionTable({ userId, onSelectSession, onClosePanel })
}, [userId]);
const startEditing = (session) => {
setEditingSessionId(session.session_id);
setEditName(session.session_name);
setEditorSession(session);
setShowEditor(true);
};
const saveName = async (sessionId) => {
const handleEditorConfirm = async ({ session_name, model_name }) => {
try {
await fetch(`/v1/sessions/${sessionId}?user_id=${userId}`, {
await fetch(`/v1/sessions/${editorSession.session_id}?user_id=${userId}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ session_name: editName }),
body: JSON.stringify({ session_name, model_name })
});
// Aggiornamento ottimistico
setSessions((prev) =>
prev.map((s) =>
s.session_id === sessionId ? { ...s, session_name: editName } : s
s.session_id === editorSession.session_id
? { ...s, session_name, model_name }
: s
)
);
setEditingSessionId(null);
setShowEditor(false);
setEditorSession(null);
} catch (err) {
console.error("Failed to rename session", err);
console.error("Failed to update session", err);
}
};
const handleEditorCancel = () => {
setShowEditor(false);
setEditorSession(null);
};
const deleteSession = async (sessionId) => {
if (!window.confirm("Delete this session and its history?")) return;
try {
await fetch(`/v1/sessions/${sessionId}?user_id=${userId}`, { method: "DELETE" });
// Non serve fetchSessions: il WS notificherà la cancellazione
} catch (err) {
console.error("Failed to delete session", err);
}
};
return (
<div className="table-responsive session-table">
<table className="table table-striped table-hover align-middle">
<thead>
<tr>
<th></th>
<th>Session</th>
<th>Created</th>
<th className="text-nowrap"># mess</th>
<th></th>
</tr>
</thead>
<tbody>
{loading && <tr><td colSpan="5" className="text-center">Loading</td></tr>}
{!loading && sessions.length === 0 && (
<tr><td colSpan="5" className="text-center">No sessions found</td></tr>
)}
{!loading && sessions.map((s) => (
<tr
key={s.session_id}
className={s.session_id === activeSessionId ? "table-primary" : ""}
>
<td className="text-end text-nowrap">
<button
className="btn btn-sm px-1 btn-outline-secondary me-1"
onClick={() => startEditing(s)}
title="Rename"
></button>
</td>
<td>
{editingSessionId === s.session_id ? (
<input
type="text"
className="form-control form-control-sm"
value={editName}
onChange={(e) => setEditName(e.target.value)}
onBlur={() => saveName(s.session_id)}
onKeyDown={(e) => {
if (e.key === "Enter") saveName(s.session_id);
if (e.key === "Escape") setEditingSessionId(null);
}}
autoFocus
/>
) : (
<span
<>
<div className="table-responsive session-table">
<table className="table table-striped table-hover align-middle">
<thead>
<tr>
<th></th>
<th>Session/Model</th>
<th class="text-end">Created/Mess</th>
<th></th>
</tr>
</thead>
<tbody>
{loading && <tr><td colSpan="6" className="text-center">Loading</td></tr>}
{!loading && sessions.length === 0 && (
<tr><td colSpan="6" className="text-center">No sessions found</td></tr>
)}
{!loading && sessions.map((s) => (
<tr
key={s.session_id}
className={s.session_id === activeSessionId ? "table-primary" : ""}
>
<td className="text-end text-nowrap">
<button
className="btn btn-sm px-1 btn-outline-secondary me-1"
onClick={() => startEditing(s)}
title="Edit session"
></button>
</td>
<td>
<div
role="button"
className="text-primary"
onClick={() => {
@@ -160,26 +151,47 @@ export default function SessionTable({ userId, onSelectSession, onClosePanel })
title="Click to load this session"
>
{s.session_name}
</span>
)}
</td>
<td>{new Date(s.created_at).toLocaleString()}</td>
<td title={s.history_size_bytes}>
{s.message_count}
</td>
<td className="text-end text-nowrap">
<button
className="btn btn-sm px-1 btn-outline-danger"
onClick={() => deleteSession(s.session_id)}
title="Delete"
>🗑</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="text-muted small">
{s.model_name
? s.model_name.length > 20
? `${s.model_name.slice(0, 20)}`
: s.model_name
: "default"}
</div>
</td>
<td class="text-end">
<div class="small">{new Date(s.created_at).toLocaleString()}</div>
<div class="small">
# mess: {s.message_count}
</div>
</td>
<td className="text-end text-nowrap">
<button
className="btn btn-sm px-1 btn-outline-danger"
onClick={() => deleteSession(s.session_id)}
title="Delete"
>🗑</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
{showEditor && (
<>
<div className="modal-backdrop fade show"></div>
<SessionEditor
mode="edit"
initialName={editorSession?.session_name || ""}
initialModel={editorSession?.model_name || ""}
onConfirm={handleEditorConfirm}
onCancel={handleEditorCancel}
/>
</>
)}
</>
);
}