Skip to content
Merged
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
1 change: 1 addition & 0 deletions apps/code/src/main/services/context-menu/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const externalAppAction = z.discriminatedUnion("type", [
const taskAction = z.discriminatedUnion("type", [
z.object({ type: z.literal("rename") }),
z.object({ type: z.literal("pin") }),
z.object({ type: z.literal("copy-task-id") }),
z.object({ type: z.literal("suspend") }),
z.object({ type: z.literal("archive") }),
z.object({ type: z.literal("delete") }),
Expand Down
1 change: 1 addition & 0 deletions apps/code/src/main/services/context-menu/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class ContextMenuService {
return this.showMenu<TaskAction>([
this.item("Rename", { type: "rename" }),
this.item(isPinned ? "Unpin" : "Pin", { type: "pin" }),
this.item("Copy Task ID", { type: "copy-task-id" }),
this.separator(),
...(worktreePath
? [this.item("Suspend", { type: "suspend" as const })]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ import { useWorkspace } from "@features/workspace/hooks/useWorkspace";
import { useBlurOnEscape } from "@hooks/useBlurOnEscape";
import { useFileWatcher } from "@hooks/useFileWatcher";
import { useSetHeaderContent } from "@hooks/useSetHeaderContent";
import { Box, Flex, Text, Tooltip } from "@radix-ui/themes";
import { Box, Flex, Text } from "@radix-ui/themes";
import type { Task } from "@shared/types";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useHotkeys, useHotkeysContext } from "react-hotkeys-hook";
import { toast } from "sonner";
import { ExternalAppsOpener } from "./ExternalAppsOpener";

const MIN_REVIEW_WIDTH = 300;
Expand Down Expand Up @@ -86,33 +85,20 @@ export function TaskDetail({ task: initialTask }: TaskDetailProps) {
useBlurOnEscape();
useWorkspaceEvents(taskId);

const copyTaskId = useCallback(() => {
navigator.clipboard.writeText(taskId);
toast.success("Task ID copied");
}, [taskId]);

const headerContent = useMemo(
() => (
<Flex align="center" justify="between" gap="2" width="100%">
<Text size="1" weight="medium" truncate style={{ minWidth: 0 }}>
{task.title}
</Text>
<Flex align="center" gap="2" className="shrink-0">
<Tooltip content="Copy task ID">
<button
type="button"
onClick={copyTaskId}
className="no-drag cursor-pointer border-0 bg-transparent p-0 font-mono text-[10px] text-gray-9 hover:text-gray-11"
style={{ lineHeight: "20px" }}
>
{taskId}
</button>
</Tooltip>
{openTargetPath && <ExternalAppsOpener targetPath={openTargetPath} />}
</Flex>
{openTargetPath && (
<Flex align="center" gap="2" className="shrink-0">
<ExternalAppsOpener targetPath={openTargetPath} />
</Flex>
)}
</Flex>
),
[task.title, taskId, openTargetPath, copyTaskId],
[task.title, openTargetPath],
);

useSetHeaderContent(headerContent);
Expand Down
5 changes: 5 additions & 0 deletions apps/code/src/renderer/hooks/useTaskContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Task } from "@shared/types";
import { handleExternalAppAction } from "@utils/handleExternalAppAction";
import { logger } from "@utils/logger";
import { useCallback, useState } from "react";
import { toast } from "sonner";

const log = logger.scope("context-menu");

Expand Down Expand Up @@ -47,6 +48,10 @@ export function useTaskContextMenu() {
case "pin":
onTogglePin?.();
break;
case "copy-task-id":
navigator.clipboard.writeText(task.id);
toast.success("Task ID copied");
break;
case "suspend":
await suspendTask({ taskId: task.id, reason: "manual" });
break;
Expand Down
Loading