({
messages,
onPreRestore,
onRestoreMessage,
onRestoreCode,
onSummarize,
onClose,
preselectedMessage,
}: Props)
| 71 | const MAX_VISIBLE_MESSAGES = 7; |
| 72 | |
| 73 | export function MessageSelector({ |
| 74 | messages, |
| 75 | onPreRestore, |
| 76 | onRestoreMessage, |
| 77 | onRestoreCode, |
| 78 | onSummarize, |
| 79 | onClose, |
| 80 | preselectedMessage, |
| 81 | }: Props): React.ReactNode { |
| 82 | const fileHistory = useAppState(s => s.fileHistory); |
| 83 | const [error, setError] = useState<string | undefined>(undefined); |
| 84 | const isFileHistoryEnabled = fileHistoryEnabled(); |
| 85 | |
| 86 | // Add current prompt as a virtual message |
| 87 | const currentUUID = useMemo(randomUUID, []); |
| 88 | const messageOptions = useMemo( |
| 89 | () => [ |
| 90 | ...messages.filter(selectableUserMessagesFilter), |
| 91 | { |
| 92 | ...createUserMessage({ |
| 93 | content: '', |
| 94 | }), |
| 95 | uuid: currentUUID, |
| 96 | } as UserMessage, |
| 97 | ], |
| 98 | [messages, currentUUID], |
| 99 | ); |
| 100 | const [selectedIndex, setSelectedIndex] = useState(messageOptions.length - 1); |
| 101 | |
| 102 | // Orient the selected message as the middle of the visible options |
| 103 | const firstVisibleIndex = Math.max( |
| 104 | 0, |
| 105 | Math.min(selectedIndex - Math.floor(MAX_VISIBLE_MESSAGES / 2), messageOptions.length - MAX_VISIBLE_MESSAGES), |
| 106 | ); |
| 107 | |
| 108 | const hasMessagesToSelect = messageOptions.length > 1; |
| 109 | |
| 110 | const [messageToRestore, setMessageToRestore] = useState<UserMessage | undefined>(preselectedMessage); |
| 111 | const [diffStatsForRestore, setDiffStatsForRestore] = useState<DiffStats | undefined>(undefined); |
| 112 | |
| 113 | useEffect(() => { |
| 114 | if (!preselectedMessage || !isFileHistoryEnabled) return; |
| 115 | let cancelled = false; |
| 116 | void fileHistoryGetDiffStats(fileHistory, preselectedMessage.uuid).then(stats => { |
| 117 | if (!cancelled) setDiffStatsForRestore(stats); |
| 118 | }); |
| 119 | return () => { |
| 120 | cancelled = true; |
| 121 | }; |
| 122 | }, [preselectedMessage, isFileHistoryEnabled, fileHistory]); |
| 123 | |
| 124 | const [isRestoring, setIsRestoring] = useState(false); |
| 125 | const [restoringOption, setRestoringOption] = useState<RestoreOption | null>(null); |
| 126 | const [selectedRestoreOption, setSelectedRestoreOption] = useState<RestoreOption>('both'); |
| 127 | // Per-option feedback state; Select's internal inputValues Map persists |
| 128 | // per-option text independently, so sharing one variable would desync. |
| 129 | const [summarizeFromFeedback, setSummarizeFromFeedback] = useState(''); |
| 130 | const [summarizeUpToFeedback, setSummarizeUpToFeedback] = useState(''); |
nothing calls this directly
no test coverage detected