| ... | ... | @@ -403,8 +403,12 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 403 | 403 | snoozeSupported: boolean; |
| 404 | 404 | // Renders the pin glyph. Pinned cards keep the full settle/snooze quick |
| 405 | 405 | // actions: settling clears the pin server-side, and snoozing hides the |
| 406 | | // card until wake with the pin intact underneath. Pin/unpin themselves |
| 407 | | // live in the context menu only. |
| 406 | // card until wake with the pin intact underneath. The glyph is also the |
| 407 | // in-row pin state cue (the pinned block has no header), so it always |
| 408 | // shows while pinned; it only becomes a clickable unpin quick-action once |
| 409 | // the pinning capability is confirmed, and stays a passive marker while |
| 410 | // the descriptor is not loaded. Pinning itself lives in the context menu. |
| 411 | pinningSupported: boolean; |
| 408 | 412 | isPinned: boolean; |
| 409 | 413 | // Compact wake countdown ("2h") for rows in the snoozed shelf. |
| 410 | 414 | snoozeWakeLabelText: string | null; |
| ... | ... | @@ -432,6 +436,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 432 | 436 | onUnsettle: (threadRef: ScopedThreadRef) => void; |
| 433 | 437 | onSnooze: (threadRef: ScopedThreadRef, preset: SnoozePreset) => void; |
| 434 | 438 | onUnsnooze: (threadRef: ScopedThreadRef) => void; |
| 439 | onUnpin: (threadRef: ScopedThreadRef) => void; |
| 435 | 440 | onAcknowledgeWoke: (threadRef: ScopedThreadRef, visitedAt: string) => void; |
| 436 | 441 | onChangeRequestState: (threadKey: string, state: "open" | "closed" | "merged" | null) => void; |
| 437 | 442 | }) { |
| ... | ... | @@ -450,6 +455,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 450 | 455 | onThreadClick, |
| 451 | 456 | onUnsettle, |
| 452 | 457 | onUnsnooze, |
| 458 | onUnpin, |
| 453 | 459 | renamingTitle, |
| 454 | 460 | thread, |
| 455 | 461 | variant, |
| ... | ... | @@ -704,6 +710,14 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 704 | 710 | }, |
| 705 | 711 | [onUnsnooze, threadRef], |
| 706 | 712 | ); |
| 713 | const handleUnpinClick = useCallback( |
| 714 | (event: ReactMouseEvent) => { |
| 715 | event.preventDefault(); |
| 716 | event.stopPropagation(); |
| 717 | onUnpin(threadRef); |
| 718 | }, |
| 719 | [onUnpin, threadRef], |
| 720 | ); |
| 707 | 721 | const handleSnoozePreset = useCallback( |
| 708 | 722 | (preset: SnoozePreset) => { |
| 709 | 723 | onSnooze(threadRef, preset); |
| ... | ... | @@ -1001,11 +1015,23 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 1001 | 1015 | <span className="flex-1" /> |
| 1002 | 1016 | )} |
| 1003 | 1017 | {props.isPinned ? ( |
| 1004 | | <PinIcon |
| 1005 | | aria-label="Pinned" |
| 1006 | | role="img" |
| 1007 | | className="size-3 shrink-0 text-muted-foreground/65" |
| 1008 | | /> |
| 1018 | props.pinningSupported ? ( |
| 1019 | <button |
| 1020 | type="button" |
| 1021 | aria-label="Unpin thread" |
| 1022 | title="Unpin thread" |
| 1023 | onClick={handleUnpinClick} |
| 1024 | 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" |
| 1025 | > |
| 1026 | <PinIcon aria-hidden className="size-3 shrink-0" /> |
| 1027 | </button> |
| 1028 | ) : ( |
| 1029 | <PinIcon |
| 1030 | aria-label="Pinned" |
| 1031 | role="img" |
| 1032 | className="size-3 shrink-0 text-muted-foreground/65" |
| 1033 | /> |
| 1034 | ) |
| 1009 | 1035 | ) : null} |
| 1010 | 1036 | {/* The visible state owns this slot's width: status at rest, |
| 1011 | 1037 | actions on hover/keyboard focus or while the popover is open. Keeping |
| ... | ... | @@ -3080,6 +3106,10 @@ export default function SidebarV2() { |
| 3080 | 3106 | serverConfigs.get(thread.environmentId)?.environment.capabilities |
| 3081 | 3107 | .threadSnooze === true |
| 3082 | 3108 | } |
| 3109 | pinningSupported={ |
| 3110 | serverConfigs.get(thread.environmentId)?.environment.capabilities |
| 3111 | .threadPinning === true |
| 3112 | } |
| 3083 | 3113 | isPinned={section === "pinned"} |
| 3084 | 3114 | snoozeWakeLabelText={ |
| 3085 | 3115 | section === "snoozed" && thread.snoozedUntil != null |
| ... | ... | @@ -3120,6 +3150,7 @@ export default function SidebarV2() { |
| 3120 | 3150 | onUnsettle={attemptUnsettle} |
| 3121 | 3151 | onSnooze={attemptSnooze} |
| 3122 | 3152 | onUnsnooze={attemptUnsnooze} |
| 3153 | onUnpin={attemptUnpin} |
| 3123 | 3154 | onAcknowledgeWoke={acknowledgeWoke} |
| 3124 | 3155 | onChangeRequestState={handleChangeRequestState} |
| 3125 | 3156 | /> |