94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
import { IconLayoutList, IconPlayerPlay, IconSend, IconTrash, IconX } from "@tabler/icons-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Button } from "@kandev/ui";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export type QueuePanelHeaderProps = {
|
|
count: number;
|
|
max: number;
|
|
isFull: boolean;
|
|
canDrain: boolean;
|
|
isLoading: boolean;
|
|
cancellationPending: boolean;
|
|
onClear: () => void;
|
|
onDrain: () => void;
|
|
onSendNow: () => void;
|
|
onClose: () => void;
|
|
};
|
|
|
|
export function QueuePanelHeader({
|
|
count,
|
|
max,
|
|
isFull,
|
|
canDrain,
|
|
isLoading,
|
|
cancellationPending,
|
|
onClear,
|
|
onDrain,
|
|
onSendNow,
|
|
onClose,
|
|
}: QueuePanelHeaderProps) {
|
|
const { t } = useTranslation();
|
|
const capacityText =
|
|
max > 0
|
|
? t(isFull ? "chat:queueCapacityFull" : "chat:queueCapacity", { count, max })
|
|
: t("chat:queueCount", { count });
|
|
return (
|
|
<div className="flex shrink-0 items-center justify-between gap-3 py-1">
|
|
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
<IconLayoutList className="h-3.5 w-3.5" />
|
|
<span className="uppercase tracking-wide">{t("chat:queued")}</span>
|
|
<span className={cn(isFull && "text-amber-600 dark:text-amber-400")}>{capacityText}</span>
|
|
</div>
|
|
<div className="flex flex-wrap items-center justify-end gap-1">
|
|
{canDrain && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="h-6 px-1.5 text-xs text-muted-foreground hover:text-foreground cursor-pointer [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:px-3"
|
|
onClick={onDrain}
|
|
disabled={isLoading}
|
|
title={t("chat:runNextQueuedMessage")}
|
|
data-testid="queue-drain-next"
|
|
>
|
|
<IconPlayerPlay className="mr-1 h-3 w-3" />
|
|
{t("chat:runNext")}
|
|
</Button>
|
|
)}
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="h-6 px-1.5 text-xs text-muted-foreground hover:text-foreground cursor-pointer [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:px-3"
|
|
onClick={onSendNow}
|
|
disabled={isLoading || cancellationPending}
|
|
title={t("chat:sendNowQueuedMessages")}
|
|
data-testid="queue-send-now"
|
|
>
|
|
<IconSend className="mr-1 h-3 w-3" />
|
|
{t("chat:sendNow")}
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="h-6 px-1.5 text-xs text-muted-foreground hover:text-foreground cursor-pointer [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:px-3"
|
|
onClick={onClear}
|
|
title={t("chat:clearAllQueuedMessages")}
|
|
data-testid="queue-clear-all"
|
|
>
|
|
<IconTrash className="mr-1 h-3 w-3" />
|
|
{t("chat:clearAll")}
|
|
</Button>
|
|
<button
|
|
type="button"
|
|
onClick={onClose}
|
|
aria-label={t("chat:collapseQueuedMessages")}
|
|
data-testid="queue-close"
|
|
className="inline-flex h-6 w-6 items-center justify-center text-muted-foreground hover:text-foreground cursor-pointer rounded p-1 [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:w-11"
|
|
>
|
|
<IconX className="h-3.5 w-3.5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|