Skip to content
Closed
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: 39 additions & 1 deletion apps/web/src/components/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
LinkIcon,
MessageSquareIcon,
PaletteIcon,
PinIcon,
PinOffIcon,
SettingsIcon,
SquarePenIcon,
TextSearchIcon,
Expand All @@ -59,6 +61,7 @@ import { useDesktopLocalBootstraps } from "../connection/useDesktopLocalBootstra
import { useHandleNewThread } from "../hooks/useHandleNewThread";
import { useClientSettings } from "../hooks/useSettings";
import { useTheme } from "../hooks/useTheme";
import { useThreadActions } from "../hooks/useThreadActions";
import { readLocalApi } from "../localApi";
import { desktopLocalBackendId } from "../connection/desktopLocal";
import { filesystemEnvironment } from "../state/filesystem";
Expand All @@ -68,7 +71,7 @@ import { sourceControlEnvironment } from "../state/sourceControl";
import { useAtomCommand } from "../state/use-atom-command";
import { useAtomQueryRunner } from "../state/use-atom-query-runner";
import { useEnvironments, usePrimaryEnvironmentId } from "../state/environments";
import { useProjects, useThreadShells } from "../state/entities";
import { readEnvironmentSupportsPinning, useProjects, useThreadShells } from "../state/entities";
import { useThreadSearch } from "../state/queries";
import { resolveThreadActionProjectRef, startNewThreadFromContext } from "../lib/chatThreadActions";
import {
Expand Down Expand Up @@ -578,6 +581,7 @@ function OpenCommandPaletteDialog(props: {
const primaryEnvironmentId = usePrimaryEnvironmentId();
const { activeDraftThread, activeThread, defaultProjectRef, handleNewThread } =
useHandleNewThread();
const { pinThread, unpinThread } = useThreadActions();
const projects = useProjects();
const projectOrder = useUiStateStore((store) => store.projectOrder);
const threads = useThreadShells();
Expand Down Expand Up @@ -1408,6 +1412,40 @@ function OpenCommandPaletteDialog(props: {
});
}

// Pin is contextual to the thread being read, and hidden on servers that
// predate thread.pin/unpin — same version-skew contract as the sidebar and
// chat-header menus. Drafts never get here: activeThread is null for them.
if (activeThread && readEnvironmentSupportsPinning(activeThread.environmentId)) {
const pinTargetRef = scopeThreadRef(activeThread.environmentId, activeThread.id);
const isPinned = activeThread.pinnedAt != null;
actionItems.push({
kind: "action",
value: isPinned ? "action:unpin-thread" : "action:pin-thread",
searchTerms: isPinned
? ["unpin thread", "unpin current thread"]
: ["pin thread", "pin current thread"],
title: isPinned ? "Unpin current thread" : "Pin current thread",
icon: isPinned ? (
<PinOffIcon className={ITEM_ICON_CLASS} />
) : (
<PinIcon className={ITEM_ICON_CLASS} />
),
run: async () => {
const result = isPinned ? await unpinThread(pinTargetRef) : await pinThread(pinTargetRef);
if (result._tag === "Failure" && !isAtomCommandInterrupted(result)) {
const error = squashAtomCommandFailure(result);
toastManager.add(
stackedThreadToast({
type: "error",
title: isPinned ? "Failed to unpin thread" : "Failed to pin thread",
description: error instanceof Error ? error.message : "An error occurred.",
}),
);
}
},
});
}

actionItems.push({
kind: "action",
value: "action:open-file-picker",
Expand Down
Loading