Skip to content
Closed
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
2 changes: 2 additions & 0 deletions webview-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 15 additions & 13 deletions webview-ui/src/components/history/DeleteTaskDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import React from "react"
import { useCallback } from "react"
import { AlertDialogProps } from "@radix-ui/react-alert-dialog"

import { vscode } from "@/utils/vscode"
import {
AlertDialog,
AlertDialogAction,
Expand All @@ -8,24 +11,23 @@ import {
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui"
import { vscode } from "@/utils/vscode"
Button,
} from "@/components/ui"

interface DeleteTaskDialogProps {
interface DeleteTaskDialogProps extends AlertDialogProps {
taskId: string
open: boolean
onOpenChange: (open: boolean) => void
}

export const DeleteTaskDialog = ({ taskId, open, onOpenChange }: DeleteTaskDialogProps) => {
const handleDelete = () => {
export const DeleteTaskDialog = ({ taskId, ...props }: DeleteTaskDialogProps) => {
const { onOpenChange } = props

const onDelete = useCallback(() => {
vscode.postMessage({ type: "deleteTaskWithId", text: taskId })
onOpenChange(false)
}
onOpenChange?.(false)
}, [taskId, onOpenChange])

return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialog {...props}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Task</AlertDialogTitle>
Expand All @@ -38,7 +40,7 @@ export const DeleteTaskDialog = ({ taskId, open, onOpenChange }: DeleteTaskDialo
<Button variant="secondary">Cancel</Button>
</AlertDialogCancel>
<AlertDialogAction asChild>
<Button variant="destructive" onClick={handleDelete}>
<Button variant="destructive" onClick={onDelete}>
Delete
</Button>
</AlertDialogAction>
Expand Down
45 changes: 22 additions & 23 deletions webview-ui/src/components/history/HistoryView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { memo, useMemo, useState, useEffect } from "react"
import { DeleteTaskDialog } from "./DeleteTaskDialog"
import { Fzf } from "fzf"
import prettyBytes from "pretty-bytes"
import { Virtuoso } from "react-virtuoso"
Expand All @@ -11,6 +10,7 @@ import { formatLargeNumber } from "../../utils/format"
import { highlightFzfMatch } from "../../utils/highlight"
import { useCopyToClipboard } from "../../utils/clipboard"
import { Button } from "../ui"
import { DeleteTaskDialog } from "./DeleteTaskDialog"

type HistoryViewProps = {
onDone: () => void
Expand All @@ -34,31 +34,14 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
}
}, [searchQuery, sortOption, lastNonRelevantSort])

const handleHistorySelect = (id: string) => {
vscode.postMessage({ type: "showTaskWithId", text: id })
}
const handleHistorySelect = (id: string) => vscode.postMessage({ type: "showTaskWithId", text: id })

const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
const [isConfirmDeleteTask, setIsConfirmDeleteTask] = useState(false)
const [taskToDelete, setTaskToDelete] = useState<string | null>(null)

const handleDeleteHistoryItem = (id: string) => {
setTaskToDelete(id)
setDeleteDialogOpen(true)
}

const formatDate = (timestamp: number) => {
const date = new Date(timestamp)
return date
?.toLocaleString("en-US", {
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
hour12: true,
})
.replace(", ", " ")
.replace(" at", ",")
.toUpperCase()
setIsConfirmDeleteTask(true)
}

const presentableTasks = useMemo(() => {
Expand Down Expand Up @@ -406,9 +389,10 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
{taskToDelete && (
<DeleteTaskDialog
taskId={taskToDelete}
open={deleteDialogOpen}
open={isConfirmDeleteTask}
onOpenChange={(open) => {
setDeleteDialogOpen(open)
setIsConfirmDeleteTask(open)

if (!open) {
setTaskToDelete(null)
}
Expand Down Expand Up @@ -443,4 +427,19 @@ const ExportButton = ({ itemId }: { itemId: string }) => (
</Button>
)

const formatDate = (timestamp: number) => {
const date = new Date(timestamp)
return date
?.toLocaleString("en-US", {
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
hour12: true,
})
.replace(", ", " ")
.replace(" at", ",")
.toUpperCase()
}

export default memo(HistoryView)
151 changes: 77 additions & 74 deletions webview-ui/src/components/ui/alert-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,94 +4,97 @@ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

const AlertDialog = AlertDialogPrimitive.Root

const AlertDialogTrigger = AlertDialogPrimitive.Trigger
function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
}

const AlertDialogPortal = AlertDialogPrimitive.Portal
function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
}

const AlertDialogOverlay = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
}

const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
return (
<AlertDialogPrimitive.Overlay
data-slot="alert-dialog-overlay"
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-vscode-editor-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
className,
)}
{...props}
/>
</AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
)
}

const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-2 text-left", className)} {...props} />
)
AlertDialogHeader.displayName = "AlertDialogHeader"
function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
data-slot="alert-dialog-content"
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
className,
)}
{...props}
/>
</AlertDialogPortal>
)
}

const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-row justify-end space-x-2", className)} {...props} />
)
AlertDialogFooter.displayName = "AlertDialogFooter"
function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-header"
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
{...props}
/>
)
}

const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold", className)} {...props} />
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-footer"
className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
{...props}
/>
)
}

function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
return (
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn("text-lg font-semibold", className)}
{...props}
/>
)
}

const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-base text-muted-foreground", className)}
{...props}
/>
))
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
function AlertDialogDescription({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
return (
<AlertDialogPrimitive.Description
data-slot="alert-dialog-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
)
}

const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
return <AlertDialogPrimitive.Action className={cn(buttonVariants(), className)} {...props} />
}

const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(buttonVariants({ variant: "secondary" }), "mt-0", className)}
{...props}
/>
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
return <AlertDialogPrimitive.Cancel className={cn(buttonVariants({ variant: "outline" }), className)} {...props} />
}

export {
AlertDialog,
Expand Down
Loading
Loading