diff --git a/web-ui/src/components/board-card.tsx b/web-ui/src/components/board-card.tsx index ecbc2d2..618688c 100644 --- a/web-ui/src/components/board-card.tsx +++ b/web-ui/src/components/board-card.tsx @@ -1,21 +1,25 @@ import { Draggable } from "@hello-pangea/dnd"; -import { GitBranch, Play, RotateCcw, Trash2 } from "lucide-react"; +import { buildTaskWorktreeDisplayPath } from "@runtime-task-worktree-path"; +import { Copy, GitBranch, Play, RotateCcw, Trash2 } from "lucide-react"; import type { MouseEvent } from "react"; import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; -import { buildTaskWorktreeDisplayPath } from "@runtime-task-worktree-path"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/components/ui/cn"; +import { Spinner } from "@/components/ui/spinner"; +import { Tooltip } from "@/components/ui/tooltip"; import type { RuntimeTaskSessionSummary } from "@/runtime/types"; import { useTaskWorkspaceSnapshotValue } from "@/stores/workspace-metadata-store"; import type { BoardCard as BoardCardModel, BoardColumnId } from "@/types"; import { getTaskAutoReviewCancelButtonLabel } from "@/types"; import { formatPathForDisplay } from "@/utils/path-display"; import { useMeasure } from "@/utils/react-use"; -import { clampTextWithInlineSuffix, splitPromptToTitleDescriptionByWidth, truncateTaskPromptLabel } from "@/utils/task-prompt"; +import { + clampTextWithInlineSuffix, + splitPromptToTitleDescriptionByWidth, + truncateTaskPromptLabel, +} from "@/utils/task-prompt"; import { DEFAULT_TEXT_MEASURE_FONT, measureTextWidth, readElementFontShorthand } from "@/utils/text-measure"; -import { Button } from "@/components/ui/button"; -import { Spinner } from "@/components/ui/spinner"; -import { Tooltip } from "@/components/ui/tooltip"; -import { cn } from "@/components/ui/cn"; interface CardSessionActivity { dotColor: string; @@ -142,7 +146,6 @@ export function BoardCard({ isDependencyLinking?: boolean; workspacePath?: string | null; }): React.ReactElement { - const [isHovered, setIsHovered] = useState(false); const [titleContainerRef, titleRect] = useMeasure(); const [descriptionContainerRef, descriptionRect] = useMeasure(); const titleRef = useRef(null); @@ -152,6 +155,7 @@ export function BoardCard({ const [titleFont, setTitleFont] = useState(DEFAULT_TEXT_MEASURE_FONT); const [descriptionFont, setDescriptionFont] = useState(DEFAULT_TEXT_MEASURE_FONT); const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false); + const [isCopied, setIsCopied] = useState(false); const reviewWorkspaceSnapshot = useTaskWorkspaceSnapshotValue(card.id); const isTrashCard = columnId === "trash"; const isCardInteractive = !isTrashCard; @@ -273,6 +277,14 @@ export function BoardCard({ const cancelAutomaticActionLabel = !isTrashCard && card.autoReviewEnabled ? getTaskAutoReviewCancelButtonLabel(card.autoReviewMode) : null; + const handleCopyPrompt = (event: MouseEvent) => { + stopEvent(event); + navigator.clipboard.writeText(card.prompt).then(() => { + setIsCopied(true); + setTimeout(() => setIsCopied(false), 1500); + }); + }; + return ( {(provided, snapshot) => { @@ -328,7 +340,6 @@ export function BoardCard({ cursor: "grab", }} onMouseEnter={() => { - setIsHovered(true); onDependencyPointerEnter?.(card.id); }} onMouseMove={() => { @@ -337,22 +348,18 @@ export function BoardCard({ } onDependencyPointerEnter?.(card.id); }} - onMouseLeave={() => setIsHovered(false)} >
- {statusMarker ? ( -
{statusMarker}
- ) : null} + {statusMarker ?
{statusMarker}
: null}

- {columnId === "backlog" ? ( -
{displayPromptSplit.description ? (
@@ -474,7 +494,7 @@ export function BoardCard({
@@ -507,13 +527,13 @@ export function BoardCard({ lineHeight: 1.4, whiteSpace: "normal", overflowWrap: "anywhere", - color: isTrashCard ? SESSION_ACTIVITY_COLOR.muted : undefined, + color: isTrashCard ? SESSION_ACTIVITY_COLOR.muted : undefined, }} > {isTrashCard ? ( @@ -521,24 +541,26 @@ export function BoardCard({ ) : reviewWorkspaceSnapshot ? ( <> - {reviewWorkspacePath} + {reviewWorkspacePath} - {reviewRefLabel} + {reviewRefLabel} {reviewChangeSummary ? ( <> - ( - {reviewChangeSummary.filesLabel} - +{reviewChangeSummary.additions} - -{reviewChangeSummary.deletions} - ) + ( + + {reviewChangeSummary.filesLabel} + + +{reviewChangeSummary.additions} + -{reviewChangeSummary.deletions} + ) ) : null}