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