Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
40 changes: 31 additions & 9 deletions webview-ui/src/components/history/HistoryPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,61 @@ import { memo } from "react"
import { vscode } from "@/utils/vscode"
import { formatLargeNumber, formatDate } from "@/utils/format"
import { Button } from "@/components/ui"
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"

import { useExtensionState } from "../../context/ExtensionStateContext"
import { useAppTranslation } from "../../i18n/TranslationContext"
import { CopyButton } from "./CopyButton"
import { useTaskSearch } from "./useTaskSearch"

type HistoryPreviewProps = {
showHistoryView: () => void
}
const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
const { taskHistory } = useExtensionState()
const { tasks, showAllWorkspaces, setShowAllWorkspaces } = useTaskSearch()
const { t } = useAppTranslation()

return (
<div className="flex flex-col gap-3 shrink-0 mx-5">
<div className="flex items-center justify-between text-vscode-descriptionForeground">
<div className="flex items-center gap-1">
<span className="codicon codicon-comment-discussion scale-90 mr-1" />
<span className="font-medium text-xs uppercase">{t("history:recentTasks")}</span>
<div className="flex items-center gap-4">
<div className="flex items-center gap-1">
<span className="codicon codicon-comment-discussion scale-90 mr-1" />
<span className="font-medium text-xs uppercase">{t("history:recentTasks")}</span>
</div>
<div
className="flex items-center gap-1 text-xs opacity-80 hover:opacity-100 cursor-pointer"
onClick={() => setShowAllWorkspaces(!showAllWorkspaces)}>
<VSCodeCheckbox
checked={showAllWorkspaces}
onChange={(e) => setShowAllWorkspaces((e.target as HTMLInputElement).checked)}
/>
<span className="text-vscode-foreground select-none">{t("history:showAllWorkspaces")}</span>
</div>
</div>
<Button variant="ghost" size="sm" onClick={() => showHistoryView()} className="uppercase">
{t("history:viewAll")}
</Button>
</div>
{taskHistory.slice(0, 3).map((item) => (
{tasks.slice(0, 3).map((item) => (
<div
key={item.id}
className="bg-vscode-toolbar-hoverBackground/50 hover:bg-vscode-toolbar-hoverBackground/75 rounded-xs relative overflow-hidden opacity-90 hover:opacity-100 cursor-pointer"
onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
<div className="flex flex-col gap-2 p-3 pt-1">
<div className="flex justify-between items-center">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
<div className="flex items-center gap-4">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
{item.workspace && (
<span className="text-xs text-vscode-descriptionForeground flex items-center gap-1">
<span className="codicon codicon-folder" />
<span className="truncate max-w-[300px]">
{item.workspace.split("/").slice(-2).join("/") || item.workspace}
</span>
</span>
)}
</div>
<CopyButton itemTask={item.task} />
</div>
<div
Expand Down
107 changes: 69 additions & 38 deletions webview-ui/src/components/history/HistoryView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ type HistoryViewProps = {
type SortOption = "newest" | "oldest" | "mostExpensive" | "mostTokens" | "mostRelevant"

const HistoryView = ({ onDone }: HistoryViewProps) => {
const { tasks, searchQuery, setSearchQuery, sortOption, setSortOption, setLastNonRelevantSort } = useTaskSearch()
const {
tasks,
searchQuery,
setSearchQuery,
sortOption,
setSortOption,
setLastNonRelevantSort,
showAllWorkspaces,
setShowAllWorkspaces,
} = useTaskSearch()
const { t } = useAppTranslation()

const [deleteTaskId, setDeleteTaskId] = useState<string | null>(null)
Expand Down Expand Up @@ -147,21 +156,34 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
</VSCodeRadio>
</VSCodeRadioGroup>

<div className="flex items-center gap-2" onClick={() => setShowAllWorkspaces(!showAllWorkspaces)}>
<VSCodeCheckbox
checked={showAllWorkspaces}
onChange={(e) => setShowAllWorkspaces((e.target as HTMLInputElement).checked)}
/>
<span className="text-vscode-foreground">{t("history:showAllWorkspaces")}</span>
</div>

{/* Select all control in selection mode */}
{isSelectionMode && tasks.length > 0 && (
<div className="flex items-center py-1 px-2 bg-vscode-editor-background rounded">
<VSCodeCheckbox
checked={tasks.length > 0 && selectedTaskIds.length === tasks.length}
onChange={(e) => toggleSelectAll((e.target as HTMLInputElement).checked)}
/>
<span className="ml-2 text-vscode-foreground">
{selectedTaskIds.length === tasks.length
? t("history:deselectAll")
: t("history:selectAll")}
</span>
<span className="ml-auto text-vscode-descriptionForeground text-xs">
{t("history:selectedItems", { selected: selectedTaskIds.length, total: tasks.length })}
</span>
<div className="flex items-center gap-2">
<VSCodeCheckbox
checked={tasks.length > 0 && selectedTaskIds.length === tasks.length}
onChange={(e) => toggleSelectAll((e.target as HTMLInputElement).checked)}
/>
<span className="text-vscode-foreground">
{selectedTaskIds.length === tasks.length
? t("history:deselectAll")
: t("history:selectAll")}
</span>
<span className="ml-auto text-vscode-descriptionForeground text-xs">
{t("history:selectedItems", {
selected: selectedTaskIds.length,
total: tasks.length,
})}
</span>
</div>
</div>
)}
</div>
Expand Down Expand Up @@ -214,33 +236,42 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {

<div className="flex-1">
<div className="flex justify-between items-center">
<span className="text-vscode-descriptionForeground font-medium text-sm uppercase">
{formatDate(item.ts)}
</span>
<div className="flex flex-row">
{!isSelectionMode && (
<Button
variant="ghost"
size="sm"
title={t("history:deleteTaskTitle")}
data-testid="delete-task-button"
onClick={(e) => {
e.stopPropagation()

if (e.shiftKey) {
vscode.postMessage({
type: "deleteTaskWithId",
text: item.id,
})
} else {
setDeleteTaskId(item.id)
}
}}>
<span className="codicon codicon-trash" />
{item.size && prettyBytes(item.size)}
</Button>
<div className="flex items-center gap-4">
<span className="text-vscode-descriptionForeground font-medium text-sm uppercase">
{formatDate(item.ts)}
</span>
{item.workspace && (
<span className="text-xs text-vscode-descriptionForeground flex items-center gap-1">
<span className="codicon codicon-folder" />
<span
className="truncate max-w-[300px]"
dangerouslySetInnerHTML={{ __html: item.workspace }}
/>
</span>
)}
</div>
{!isSelectionMode && (
<Button
variant="ghost"
size="sm"
title={t("history:deleteTaskTitle")}
data-testid="delete-task-button"
onClick={(e) => {
e.stopPropagation()

if (e.shiftKey) {
vscode.postMessage({
type: "deleteTaskWithId",
text: item.id,
})
} else {
setDeleteTaskId(item.id)
}
}}>
<span className="codicon codicon-trash" />
{item.size && prettyBytes(item.size)}
</Button>
)}
</div>
<div
style={{
Expand Down
39 changes: 30 additions & 9 deletions webview-ui/src/components/history/useTaskSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
type SortOption = "newest" | "oldest" | "mostExpensive" | "mostTokens" | "mostRelevant"

export const useTaskSearch = () => {
const { taskHistory } = useExtensionState()
const { taskHistory, cwd } = useExtensionState()
const [searchQuery, setSearchQuery] = useState("")
const [sortOption, setSortOption] = useState<SortOption>("newest")
const [lastNonRelevantSort, setLastNonRelevantSort] = useState<SortOption | null>("newest")
const [showAllWorkspaces, setShowAllWorkspaces] = useState(false)

useEffect(() => {
if (searchQuery && sortOption !== "mostRelevant" && !lastNonRelevantSort) {
Expand All @@ -28,22 +29,40 @@ export const useTaskSearch = () => {

const fzf = useMemo(() => {
return new Fzf(presentableTasks, {
selector: (item) => item.task,
selector: (item) => `${item.task} ${item.workspace || ""}`,
})
}, [presentableTasks])

const tasks = useMemo(() => {
let results = presentableTasks
// First filter by workspace if enabled
let results = showAllWorkspaces ? presentableTasks : presentableTasks.filter((item) => item.workspace === cwd)

if (searchQuery) {
const searchResults = fzf.find(searchQuery)
results = searchResults.map((result) => ({
...result.item,
task: highlightFzfMatch(result.item.task, Array.from(result.positions)),
}))
results = searchResults
.map((result) => {
const positions = Array.from(result.positions)
const taskEndIndex = result.item.task.length

return {
...result.item,
task: highlightFzfMatch(
result.item.task,
positions.filter((p) => p < taskEndIndex),
),
workspace: result.item.workspace
? highlightFzfMatch(
result.item.workspace,
positions.filter((p) => p > taskEndIndex).map((p) => p - taskEndIndex - 1),
)
: undefined,
}
})
.filter((item) => (showAllWorkspaces ? true : item.workspace === cwd))
}

// First apply search if needed
const searchResults = searchQuery ? results : presentableTasks
const searchResults = results

// Then sort the results
return [...searchResults].sort((a, b) => {
Expand All @@ -64,7 +83,7 @@ export const useTaskSearch = () => {
return (b.ts || 0) - (a.ts || 0)
}
})
}, [presentableTasks, searchQuery, fzf, sortOption])
}, [presentableTasks, searchQuery, fzf, sortOption, showAllWorkspaces, cwd])

return {
tasks,
Expand All @@ -74,5 +93,7 @@ export const useTaskSearch = () => {
setSortOption,
lastNonRelevantSort,
setLastNonRelevantSort,
showAllWorkspaces,
setShowAllWorkspaces,
}
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/ca/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Eliminar tasques",
"confirmDeleteTasks": "Estàs segur que vols eliminar {{count}} tasques?",
"deleteTasksWarning": "Les tasques eliminades no es poden recuperar. Si us plau, assegura't que vols continuar.",
"deleteItems": "Eliminar {{count}} elements"
"deleteItems": "Eliminar {{count}} elements",
"showAllWorkspaces": "Mostrar tasques de tots els espais de treball"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/de/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Aufgaben löschen",
"confirmDeleteTasks": "Bist du sicher, dass du {{count}} Aufgaben löschen möchtest?",
"deleteTasksWarning": "Gelöschte Aufgaben können nicht wiederhergestellt werden. Bitte vergewissere dich, dass du fortfahren möchtest.",
"deleteItems": "{{count}} Elemente löschen"
"deleteItems": "{{count}} Elemente löschen",
"showAllWorkspaces": "Aufgaben aus allen Arbeitsbereichen anzeigen"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/en/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Delete Tasks",
"confirmDeleteTasks": "Are you sure you want to delete {{count}} tasks?",
"deleteTasksWarning": "Deleted tasks cannot be recovered. Please make sure you want to proceed.",
"deleteItems": "Delete {{count}} Items"
"deleteItems": "Delete {{count}} Items",
"showAllWorkspaces": "Show tasks from all workspaces"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/es/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Eliminar tareas",
"confirmDeleteTasks": "¿Estás seguro de que quieres eliminar {{count}} tareas?",
"deleteTasksWarning": "Las tareas eliminadas no se pueden recuperar. Por favor, asegúrate de que quieres continuar.",
"deleteItems": "Eliminar {{count}} elementos"
"deleteItems": "Eliminar {{count}} elementos",
"showAllWorkspaces": "Mostrar tareas de todos los espacios de trabajo"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/fr/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Supprimer les tâches",
"confirmDeleteTasks": "Êtes-vous sûr de vouloir supprimer {{count}} tâches ?",
"deleteTasksWarning": "Les tâches supprimées ne peuvent pas être récupérées. Veuillez confirmer que vous souhaitez continuer.",
"deleteItems": "Supprimer {{count}} éléments"
"deleteItems": "Supprimer {{count}} éléments",
"showAllWorkspaces": "Afficher les tâches de tous les espaces de travail"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/hi/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "कार्य हटाएं",
"confirmDeleteTasks": "क्या आप वाकई {{count}} कार्य हटाना चाहते हैं?",
"deleteTasksWarning": "हटाए गए कार्य पुनर्प्राप्त नहीं किए जा सकते। कृपया सुनिश्चित करें कि आप आगे बढ़ना चाहते हैं।",
"deleteItems": "{{count}} आइटम हटाएं"
"deleteItems": "{{count}} आइटम हटाएं",
"showAllWorkspaces": "सभी वर्कस्पेस से कार्य दिखाएं"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/it/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Elimina attività",
"confirmDeleteTasks": "Sei sicuro di voler eliminare {{count}} attività?",
"deleteTasksWarning": "Le attività eliminate non possono essere recuperate. Assicurati di voler continuare.",
"deleteItems": "Elimina {{count}} elementi"
"deleteItems": "Elimina {{count}} elementi",
"showAllWorkspaces": "Mostra attività da tutti gli spazi di lavoro"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/ja/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "タスクを削除",
"confirmDeleteTasks": "{{count}} 件のタスクを削除してもよろしいですか?",
"deleteTasksWarning": "削除されたタスクは復元できません。続行してもよろしいですか?",
"deleteItems": "{{count}} 項目を削除"
"deleteItems": "{{count}} 項目を削除",
"showAllWorkspaces": "すべてのワークスペースのタスクを表示"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/ko/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "작업 삭제",
"confirmDeleteTasks": "{{count}}개의 작업을 삭제하시겠습니까?",
"deleteTasksWarning": "삭제된 작업은 복구할 수 없습니다. 계속 진행하시겠습니까?",
"deleteItems": "{{count}}개 항목 삭제"
"deleteItems": "{{count}}개 항목 삭제",
"showAllWorkspaces": "모든 워크스페이스의 작업 표시"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/pl/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Usuń zadania",
"confirmDeleteTasks": "Czy na pewno chcesz usunąć {{count}} zadań?",
"deleteTasksWarning": "Usuniętych zadań nie można przywrócić. Upewnij się, że chcesz kontynuować.",
"deleteItems": "Usuń {{count}} elementów"
"deleteItems": "Usuń {{count}} elementów",
"showAllWorkspaces": "Pokaż zadania ze wszystkich przestrzeni roboczych"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/pt-BR/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Excluir tarefas",
"confirmDeleteTasks": "Tem certeza que deseja excluir {{count}} tarefas?",
"deleteTasksWarning": "As tarefas excluídas não podem ser recuperadas. Por favor, certifique-se de que deseja prosseguir.",
"deleteItems": "Excluir {{count}} itens"
"deleteItems": "Excluir {{count}} itens",
"showAllWorkspaces": "Mostrar tarefas de todos os espaços de trabalho"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/tr/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Görevleri Sil",
"confirmDeleteTasks": "{{count}} görevi silmek istediğinizden emin misiniz?",
"deleteTasksWarning": "Silinen görevler geri alınamaz. Lütfen devam etmek istediğinizden emin olun.",
"deleteItems": "{{count}} Öğeyi Sil"
"deleteItems": "{{count}} Öğeyi Sil",
"showAllWorkspaces": "Tüm çalışma alanlarından görevleri göster"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/vi/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "Xóa nhiệm vụ",
"confirmDeleteTasks": "Bạn có chắc chắn muốn xóa {{count}} nhiệm vụ không?",
"deleteTasksWarning": "Các nhiệm vụ đã xóa không thể khôi phục. Vui lòng chắc chắn bạn muốn tiếp tục.",
"deleteItems": "Xóa {{count}} mục"
"deleteItems": "Xóa {{count}} mục",
"showAllWorkspaces": "Hiển thị nhiệm vụ từ tất cả không gian làm việc"
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/zh-CN/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
"deleteTasks": "删除任务",
"confirmDeleteTasks": "确认删除 {{count}} 项任务?",
"deleteTasksWarning": "删除后将无法恢复,请谨慎操作。",
"deleteItems": "删除 {{count}} 项"
"deleteItems": "删除 {{count}} 项",
"showAllWorkspaces": "显示所有工作区的任务"
}
Loading