Skip to content
38 changes: 30 additions & 8 deletions apps/web/src/components/SidebarV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,11 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
snoozeSupported: boolean;
// Renders the pin glyph. Pinned cards keep the full settle/snooze quick
// actions: settling clears the pin server-side, and snoozing hides the
// card until wake with the pin intact underneath. Pin/unpin themselves
// live in the context menu only.
// card until wake with the pin intact underneath. The pin glyph itself
// is a quick-action that unpins in place; pinning lives in the context
// menu. Like the other lifecycle affordances it is capability-gated so
// it hides rather than fails while the descriptor is not loaded.
pinningSupported: boolean;
isPinned: boolean;
// Compact wake countdown ("2h") for rows in the snoozed shelf.
snoozeWakeLabelText: string | null;
Expand Down Expand Up @@ -431,6 +434,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
onUnsettle: (threadRef: ScopedThreadRef) => void;
onSnooze: (threadRef: ScopedThreadRef, preset: SnoozePreset) => void;
onUnsnooze: (threadRef: ScopedThreadRef) => void;
onUnpin: (threadRef: ScopedThreadRef) => void;
onAcknowledgeWoke: (threadRef: ScopedThreadRef, visitedAt: string) => void;
onChangeRequestState: (threadKey: string, state: "open" | "closed" | "merged" | null) => void;
}) {
Expand All @@ -449,6 +453,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
onThreadClick,
onUnsettle,
onUnsnooze,
onUnpin,
renamingTitle,
thread,
variant,
Expand Down Expand Up @@ -692,6 +697,14 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
},
[onUnsnooze, threadRef],
);
const handleUnpinClick = useCallback(
(event: ReactMouseEvent) => {
event.preventDefault();
event.stopPropagation();
onUnpin(threadRef);
},
[onUnpin, threadRef],
);
const handleSnoozePreset = useCallback(
(preset: SnoozePreset) => {
onSnooze(threadRef, preset);
Expand Down Expand Up @@ -988,12 +1001,16 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
) : (
<span className="flex-1" />
)}
{props.isPinned ? (
<PinIcon
aria-label="Pinned"
role="img"
className="size-3 shrink-0 text-muted-foreground/65"
/>
{props.isPinned && props.pinningSupported ? (
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
<button
type="button"
aria-label="Unpin thread"
title="Unpin thread"
onClick={handleUnpinClick}
className="inline-flex cursor-pointer items-center rounded-sm text-muted-foreground/65 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
>
<PinIcon aria-hidden className="size-3 shrink-0" />
</button>
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
) : null}
{/* The visible state owns this slot's width: status at rest,
actions on hover/keyboard focus or while the popover is open. Keeping
Expand Down Expand Up @@ -3107,6 +3124,10 @@ export default function SidebarV2() {
serverConfigs.get(thread.environmentId)?.environment.capabilities
.threadSnooze === true
}
pinningSupported={
serverConfigs.get(thread.environmentId)?.environment.capabilities
.threadPinning === true
}
isPinned={section === "pinned"}
snoozeWakeLabelText={
section === "snoozed" && thread.snoozedUntil != null
Expand Down Expand Up @@ -3147,6 +3168,7 @@ export default function SidebarV2() {
onUnsettle={attemptUnsettle}
onSnooze={attemptSnooze}
onUnsnooze={attemptUnsnooze}
onUnpin={attemptUnpin}
onAcknowledgeWoke={acknowledgeWoke}
onChangeRequestState={handleChangeRequestState}
/>
Expand Down
Loading