Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ async def list_conversations():
return storage.list_conversations()


@app.delete("/api/conversations")
async def delete_conversations():
"""Delete all conversations from storage."""
storage.delete_all_conversations()
return {"status": "ok"}


@app.post("/api/conversations", response_model=Conversation)
async def create_conversation(request: CreateConversationRequest):
"""Create a new conversation."""
Expand Down
15 changes: 15 additions & 0 deletions backend/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,18 @@ def update_conversation_title(conversation_id: str, title: str):

conversation["title"] = title
save_conversation(conversation)


def delete_all_conversations():
"""
Delete all conversation files from the data directory.
"""
ensure_data_dir()
for filename in os.listdir(DATA_DIR):
if filename.endswith('.json'):
path = os.path.join(DATA_DIR, filename)
try:
os.remove(path)
except OSError:
# ignore failures to remove individual files
pass
13 changes: 13 additions & 0 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ function App() {
}
};

const handleClearConversations = async () => {
if (!window.confirm('Clear all conversations? This cannot be undone.')) return;
try {
await api.deleteAllConversations();
setConversations([]);
setCurrentConversationId(null);
setCurrentConversation(null);
} catch (error) {
console.error('Failed to clear conversations:', error);
}
};

const handleSelectConversation = (id) => {
setCurrentConversationId(id);
};
Expand Down Expand Up @@ -188,6 +200,7 @@ function App() {
currentConversationId={currentConversationId}
onSelectConversation={handleSelectConversation}
onNewConversation={handleNewConversation}
onClearConversations={handleClearConversations}
/>
<ChatInterface
conversation={currentConversation}
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,17 @@ export const api = {
}
}
},

/**
* Delete all conversations from the backend.
*/
async deleteAllConversations() {
const response = await fetch(`${API_BASE}/api/conversations`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error('Failed to delete conversations');
}
return response.json();
},
};
16 changes: 16 additions & 0 deletions frontend/src/components/Sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@
border-color: #357abd;
}

.clear-history-btn {
width: 100%;
margin-top: 8px;
padding: 8px;
background: #fff;
border: 1px solid #d9534f;
color: #d9534f;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
}

.clear-history-btn:hover {
background: #fcebea;
}

.conversation-list {
flex: 1;
overflow-y: auto;
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/components/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default function Sidebar({
currentConversationId,
onSelectConversation,
onNewConversation,
onClearConversations,
}) {
return (
<div className="sidebar">
Expand All @@ -14,6 +15,14 @@ export default function Sidebar({
<button className="new-conversation-btn" onClick={onNewConversation}>
+ New Conversation
</button>
<button
className="clear-history-btn"
onClick={() => {
if (typeof onClearConversations === 'function') onClearConversations();
}}
>
Clear History
</button>
</div>

<div className="conversation-list">
Expand Down