Compare commits

...

3 Commits

Author SHA1 Message Date
1b51235a09 fix(binary): preserve whitespace wrapping in pseudocode viewer 2026-07-04 18:39:26 -03:00
0e610bbf54 fix(libraries): reset import dialog state on open via key prop
Use a counter key prop that increments each time the dialog opens, ensuring
a fresh component instance with cleared file input, parsed data, and errors.
2026-07-04 18:19:07 -03:00
a4828c4d45 fix(chat): hide mutation suggestion cards when no session is selected
Skip pendingSuggestions in mergedMessages and previousMutationSuggestions
rendering when activeSessionId is null. Also fix empty state check to not
consider API suggestions as content when no session is active.
2026-07-04 18:17:25 -03:00
3 changed files with 41 additions and 27 deletions

View File

@ -168,9 +168,11 @@ export function AIChatPanel({
| { kind: "suggestion"; data: MutationSuggestionResponse }
> = messages.map((m) => ({ kind: "message" as const, data: m }));
for (const s of pendingSuggestions ?? []) {
if (!s.createdAt) continue;
items.push({ kind: "suggestion" as const, data: s });
if (activeSessionId) {
for (const s of pendingSuggestions ?? []) {
if (!s.createdAt) continue;
items.push({ kind: "suggestion" as const, data: s });
}
}
items.sort((a, b) => {
@ -180,7 +182,7 @@ export function AIChatPanel({
});
return items;
}, [messages, pendingSuggestions]);
}, [messages, pendingSuggestions, activeSessionId]);
// Track manual scroll to respect user reading position
useEffect(() => {
@ -319,7 +321,9 @@ export function AIChatPanel({
ref={scrollContainerRef}
className="flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto"
>
{messages.length === 0 && !pendingSuggestions?.length && !isStreaming ? (
{messages.length === 0 &&
!(activeSessionId && pendingSuggestions?.length) &&
!isStreaming ? (
<div className="flex flex-1 flex-col items-center justify-center p-4">
<Bot className="text-muted-foreground mx-auto mb-4 h-12 w-12" />
<h3 className="text-foreground mb-2 font-medium">AI Analysis Assistant</h3>
@ -432,26 +436,27 @@ export function AIChatPanel({
})}
</>
)}
{previousMutationSuggestions
.filter(
(s, i, arr) =>
!pendingIds.has(s.mutationId) &&
!resolvedIds.has(s.mutationId) &&
arr.findIndex((x) => x.mutationId === s.mutationId) === i
)
.map((s) => (
<MutationSuggestionCard
key={s.mutationId}
mutationId={s.mutationId}
targetType={s.targetType}
targetId={s.targetId}
fieldName={s.fieldName}
oldValue={s.oldValue}
newValue={s.newValue}
onRenameApplied={onRenameApplied}
onResolved={handleResolved}
/>
))}
{activeSessionId &&
previousMutationSuggestions
.filter(
(s, i, arr) =>
!pendingIds.has(s.mutationId) &&
!resolvedIds.has(s.mutationId) &&
arr.findIndex((x) => x.mutationId === s.mutationId) === i
)
.map((s) => (
<MutationSuggestionCard
key={s.mutationId}
mutationId={s.mutationId}
targetType={s.targetType}
targetId={s.targetId}
fieldName={s.fieldName}
oldValue={s.oldValue}
newValue={s.newValue}
onRenameApplied={onRenameApplied}
onResolved={handleResolved}
/>
))}
{isStreaming && (
<>
<div className="mb-4 flex gap-3">

View File

@ -417,7 +417,7 @@ function PseudoRow({ line, lineNumber }: { line: string; lineNumber: number }) {
<td className="w-12 pr-4 text-right align-top text-[var(--code-line-number)] select-none">
{lineNumber}
</td>
<td>
<td className="whitespace-pre-wrap">
<HighlightedCode code={line} />
</td>
</tr>

View File

@ -37,6 +37,7 @@ const Libraries = () => {
} = useLibrariesPage();
const [importDialogOpen, setImportDialogOpen] = useState(false);
const [importDialogKey, setImportDialogKey] = useState(0);
const handleExport = async (library: LibraryResponse) => {
if (!library.id) return;
@ -115,7 +116,14 @@ const Libraries = () => {
</p>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={() => setImportDialogOpen(true)}>
<Button
variant="outline"
size="sm"
onClick={() => {
setImportDialogKey((k) => k + 1);
setImportDialogOpen(true);
}}
>
<FileUp className="mr-1.5 h-4 w-4" />
Import Library
</Button>
@ -171,6 +179,7 @@ const Libraries = () => {
/>
<ImportLibraryDialog
key={importDialogKey}
open={importDialogOpen}
onOpenChange={setImportDialogOpen}
isImporting={importMutation.isPending}