-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement history quick pick (#2250)
This PR closes #1692 - Implemented algorithm to group chats by last interaction timestamp. - Added an icon in the editor panel to display history chats as a quick pick, separated by the group. - Updated the history chats in the Treeview provider to render them as grouped chats. - Remove createCodyChatTreeItems, use the updateTree method of TreeViewProvider to update the list instead. ## Test plan https://github.com/sourcegraph/cody/assets/44617923/5804d8da-a629-4670-8de9-ff3b3da61e25 --------- Co-authored-by: Tim Lucas <[email protected]>
- Loading branch information
1 parent
451dd52
commit 35c6cef
Showing
9 changed files
with
292 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import * as vscode from 'vscode' | ||
|
||
import { getChatPanelTitle } from '../chat/chat-view/chat-helpers' | ||
import { chatHistory } from '../chat/chat-view/ChatHistoryManager' | ||
import type { AuthStatus } from '../chat/protocol' | ||
|
||
import type { CodySidebarTreeItem } from './treeViewItems' | ||
import type { InteractionMessage } from '@sourcegraph/cody-shared' | ||
|
||
interface GroupedChats { | ||
[groupName: string]: CodySidebarTreeItem[] | ||
} | ||
|
||
interface HistoryItem { | ||
label: string | ||
onSelect: () => Promise<void> | ||
kind?: vscode.QuickPickItemKind | ||
} | ||
|
||
interface ChatGroup { | ||
[groupName: string]: CodySidebarTreeItem[] | ||
} | ||
|
||
const dateEqual = (d1: Date, d2: Date): boolean => { | ||
return d1.getDate() === d2.getDate() && monthYearEqual(d1, d2) | ||
} | ||
const monthYearEqual = (d1: Date, d2: Date): boolean => { | ||
return d1.getMonth() === d2.getMonth() && d1.getFullYear() === d2.getFullYear() | ||
} | ||
|
||
export function groupCodyChats(authStatus: AuthStatus | undefined): GroupedChats | null { | ||
const todayChats: CodySidebarTreeItem[] = [] | ||
const yesterdayChats: CodySidebarTreeItem[] = [] | ||
const thisMonthChats: CodySidebarTreeItem[] = [] | ||
const lastMonthChats: CodySidebarTreeItem[] = [] | ||
const nMonthsChats: CodySidebarTreeItem[] = [] | ||
|
||
const today = new Date() | ||
const yesterday = new Date() | ||
yesterday.setDate(yesterday.getDate() - 1) | ||
const lastMonth = new Date() | ||
lastMonth.setDate(0) | ||
|
||
const chatGroups: ChatGroup = { | ||
Today: todayChats, | ||
Yesterday: yesterdayChats, | ||
'This month': thisMonthChats, | ||
'Last month': lastMonthChats, | ||
'N months ago': nMonthsChats, | ||
} | ||
|
||
if (!authStatus) { | ||
return null | ||
} | ||
|
||
const chats = chatHistory.getLocalHistory(authStatus)?.chat | ||
if (!chats) { | ||
return null | ||
} | ||
const chatHistoryEntries = [...Object.entries(chats)] | ||
for (const [id, entry] of chatHistoryEntries) { | ||
let lastHumanMessage: InteractionMessage | undefined = undefined | ||
// Can use Array.prototype.findLast once we drop Node 16 | ||
for (let index = entry.interactions.length - 1; index >= 0; index--) { | ||
lastHumanMessage = entry.interactions[index]?.humanMessage | ||
if (lastHumanMessage) { | ||
break | ||
} | ||
} | ||
if (lastHumanMessage?.displayText && lastHumanMessage?.text) { | ||
const lastDisplayText = lastHumanMessage.displayText.split('\n')[0] | ||
const chatTitle = chats[id].chatTitle || getChatPanelTitle(lastDisplayText, false) | ||
|
||
const lastInteractionTimestamp = new Date(entry.lastInteractionTimestamp) | ||
let groupLabel = 'N months ago' | ||
|
||
if (dateEqual(today, lastInteractionTimestamp)) { | ||
groupLabel = 'Today' | ||
} else if (dateEqual(yesterday, lastInteractionTimestamp)) { | ||
groupLabel = 'Yesterday' | ||
} else if (monthYearEqual(today, lastInteractionTimestamp)) { | ||
groupLabel = 'This month' | ||
} else if (monthYearEqual(lastMonth, lastInteractionTimestamp)) { | ||
groupLabel = 'Last month' | ||
} | ||
|
||
const chatGroup = chatGroups[groupLabel] | ||
chatGroup.push({ | ||
id, | ||
title: chatTitle, | ||
icon: 'comment-discussion', | ||
command: { | ||
command: 'cody.chat.panel.restore', | ||
args: [id, chatTitle], | ||
}, | ||
}) | ||
} | ||
} | ||
|
||
return { | ||
Today: todayChats.reverse(), | ||
Yesterday: yesterdayChats.reverse(), | ||
'This month': thisMonthChats.reverse(), | ||
'Last month': lastMonthChats.reverse(), | ||
'N months ago': nMonthsChats.reverse(), | ||
} | ||
} | ||
|
||
export async function displayHistoryQuickPick(authStatus: AuthStatus): Promise<void> { | ||
const groupedChats = groupCodyChats(authStatus) | ||
if (!groupedChats) { | ||
return | ||
} | ||
|
||
const quickPickItems: HistoryItem[] = [] | ||
|
||
const addGroupSeparator = (groupName: string): void => { | ||
quickPickItems.push({ | ||
label: groupName, | ||
onSelect: async () => {}, | ||
kind: vscode.QuickPickItemKind.Separator, | ||
}) | ||
} | ||
|
||
for (const [groupName, chats] of Object.entries(groupedChats)) { | ||
if (chats.length > 0) { | ||
addGroupSeparator(groupName) | ||
|
||
for (const chat of chats) { | ||
quickPickItems.push({ | ||
label: chat.title, | ||
onSelect: async () => { | ||
await vscode.commands.executeCommand( | ||
'cody.chat.panel.restore', | ||
chat.id, | ||
chat.title | ||
) | ||
}, | ||
}) | ||
} | ||
} | ||
} | ||
|
||
const selectedItem = await vscode.window.showQuickPick(quickPickItems, { | ||
placeHolder: 'Search chat history', | ||
}) | ||
|
||
if (selectedItem?.onSelect) { | ||
await selectedItem.onSelect() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.