Skip to content

Commit 20c1666

Browse files
Merge pull request #719 from microsoft/psl-clearhistoryadd
fix: Fix of Bug #34657
2 parents 34af4e5 + e327f8e commit 20c1666

File tree

3 files changed

+142
-11
lines changed

3 files changed

+142
-11
lines changed

content-gen/src/app/frontend/src/components/ChatHistory.tsx

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
Compose20Regular,
2525
Delete20Regular,
2626
Edit20Regular,
27+
DismissCircle20Regular,
2728
} from '@fluentui/react-icons';
2829

2930
interface ConversationSummary {
@@ -55,8 +56,30 @@ export function ChatHistory({
5556
const [isLoading, setIsLoading] = useState(true);
5657
const [error, setError] = useState<string | null>(null);
5758
const [showAll, setShowAll] = useState(false);
59+
const [isClearAllDialogOpen, setIsClearAllDialogOpen] = useState(false);
60+
const [isClearing, setIsClearing] = useState(false);
5861
const INITIAL_COUNT = 5;
5962

63+
const handleClearAllConversations = useCallback(async () => {
64+
setIsClearing(true);
65+
try {
66+
const response = await fetch('/api/conversations', {
67+
method: 'DELETE',
68+
});
69+
if (response.ok) {
70+
setConversations([]);
71+
onNewConversation();
72+
setIsClearAllDialogOpen(false);
73+
} else {
74+
console.error('Failed to clear all conversations');
75+
}
76+
} catch (err) {
77+
console.error('Error clearing all conversations:', err);
78+
} finally {
79+
setIsClearing(false);
80+
}
81+
}, [onNewConversation]);
82+
6083
const handleDeleteConversation = useCallback(async (conversationId: string) => {
6184
try {
6285
const response = await fetch(`/api/conversations/${conversationId}`, {
@@ -170,17 +193,51 @@ export function ChatHistory({
170193
backgroundColor: tokens.colorNeutralBackground3,
171194
overflow: 'hidden',
172195
}}>
173-
<Text
174-
weight="semibold"
175-
size={300}
176-
style={{
177-
marginBottom: '12px',
178-
color: tokens.colorNeutralForeground1,
179-
flexShrink: 0,
180-
}}
181-
>
182-
Chat History
183-
</Text>
196+
<div style={{
197+
display: 'flex',
198+
justifyContent: 'space-between',
199+
alignItems: 'center',
200+
marginBottom: '12px',
201+
flexShrink: 0,
202+
}}>
203+
<Text
204+
weight="semibold"
205+
size={300}
206+
style={{
207+
color: tokens.colorNeutralForeground1,
208+
}}
209+
>
210+
Chat History
211+
</Text>
212+
<Menu>
213+
<MenuTrigger disableButtonEnhancement>
214+
<Button
215+
appearance="subtle"
216+
icon={<MoreHorizontal20Regular />}
217+
size="small"
218+
title="More options"
219+
disabled={isGenerating}
220+
style={{
221+
minWidth: '24px',
222+
height: '24px',
223+
padding: '2px',
224+
color: tokens.colorNeutralForeground3,
225+
}}
226+
/>
227+
</MenuTrigger>
228+
<MenuPopover>
229+
<MenuList>
230+
<MenuItem
231+
icon={<DismissCircle20Regular />}
232+
onClick={() => setIsClearAllDialogOpen(true)}
233+
disabled={displayConversations.length === 0}
234+
>
235+
Clear all chat history
236+
</MenuItem>
237+
</MenuList>
238+
</MenuPopover>
239+
</Menu>
240+
</div>
184241

185242
<div style={{
186243
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
@@ -295,6 +352,28 @@ export function ChatHistory({
295352
</Link>
296353
</div>
297354
</div>
355+
356+
{/* Clear All Confirmation Dialog */}
357+
<Dialog open={isClearAllDialogOpen} onOpenChange={(_, data) => !isClearing && setIsClearAllDialogOpen(data.open)}>
358+
<DialogSurface>
359+
<DialogTitle>Clear all chat history</DialogTitle>
360+
<DialogBody>
361+
<DialogContent>
362+
<Text>
363+
Are you sure you want to delete all chat history? This action cannot be undone and all conversations will be permanently removed.
364+
</Text>
365+
</DialogContent>
366+
</DialogBody>
367+
<DialogActions>
368+
<Button appearance="secondary" onClick={() => setIsClearAllDialogOpen(false)} disabled={isClearing}>
369+
Cancel
370+
</Button>
371+
<Button appearance="primary" onClick={handleClearAllConversations} disabled={isClearing}>
372+
{isClearing ? 'Clearing...' : 'Clear All'}
373+
</Button>
374+
</DialogActions>
375+
</DialogSurface>
376+
</Dialog>
298377
</div>
299378
);
300379
}

content-gen/src/backend/app.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,29 @@ async def update_conversation(conversation_id: str):
13191319
return jsonify({"error": "Failed to rename conversation"}), 500
13201320

13211321

1322+
@app.route("/api/conversations", methods=["DELETE"])
1323+
async def delete_all_conversations():
1324+
"""
1325+
Delete all conversations for the current user.
1326+
1327+
Uses authenticated user from EasyAuth headers.
1328+
"""
1329+
auth_user = get_authenticated_user()
1330+
user_id = auth_user["user_principal_id"]
1331+
1332+
try:
1333+
cosmos_service = await get_cosmos_service()
1334+
deleted_count = await cosmos_service.delete_all_conversations(user_id)
1335+
return jsonify({
1336+
"success": True,
1337+
"message": f"Deleted {deleted_count} conversations",
1338+
"deleted_count": deleted_count
1339+
})
1340+
except Exception as e:
1341+
logger.warning(f"Failed to delete all conversations: {e}")
1342+
return jsonify({"error": "Failed to delete conversations"}), 500
1343+
1344+
13221345
# ==================== Brand Guidelines Endpoints ====================
13231346

13241347
@app.route("/api/brand-guidelines", methods=["GET"])

content-gen/src/backend/services/cosmos_service.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,35 @@ async def rename_conversation(
591591
result = await self._conversations_container.upsert_item(conversation)
592592
return result
593593

594+
async def delete_all_conversations(
595+
self,
596+
user_id: str
597+
) -> int:
598+
"""
599+
Delete all conversations for a user.
600+
601+
Args:
602+
user_id: User ID to delete conversations for
603+
604+
Returns:
605+
Number of conversations deleted
606+
"""
607+
await self.initialize()
608+
609+
# First get all conversations for the user
610+
conversations = await self.get_user_conversations(user_id, limit=1000)
611+
612+
deleted_count = 0
613+
for conv in conversations:
614+
try:
615+
await self.delete_conversation(conv["id"], user_id)
616+
deleted_count += 1
617+
except Exception as e:
618+
logger.warning(f"Failed to delete conversation {conv['id']}: {e}")
619+
620+
logger.info(f"Deleted {deleted_count} conversations for user {user_id}")
621+
return deleted_count
622+
594623

595624
# Singleton instance
596625
_cosmos_service: Optional[CosmosDBService] = None

0 commit comments

Comments
 (0)