Skip to content

Commit 2261aa6

Browse files
adulbrichclaude
andcommitted
feat(raw): drop conversions when the user removes the frames
Wires `dropRawConversions` into the two places that already know the user changed their mind. Removing a set two frames in no longer makes a newly added set wait about 15 s for frames nobody wants. Fixes the index those handlers removed by, which had to change for the wiring to be correct at all. The preview is handed a sorted copy and reports an index into it; `onRemoveIndex` applied that index to the unsorted stored array, so once `onAdd` appended a file that sorted earlier, removing an image deleted the wrong one -- and dropping the conversion for one frame while the form removed another would have left the cache and the UI disagreeing about which frame was gone. The index is now resolved against the array the user saw, and the file removed by identity so the stored order is left alone. Closes #248 Closes #251 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent ebb5ebc commit 2261aa6

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

src/components/ui/image-matrix-input.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
import { isTauri } from "@/lib/host/env";
2626
import { pickFiles, pickImageSets } from "@/lib/host/pick";
2727
import { imageFileExtensions } from "@/lib/image-file-extensions";
28+
import { dropRawConversions } from "@/lib/raw-preview";
2829
import { cn } from "@/lib/utils";
2930
import { Field, FieldContent, FieldError } from "./field";
3031
import { HoverCard, HoverCardContent, HoverCardTrigger } from "./hover-card";
@@ -200,6 +201,12 @@ export function ImageMatrixInput<
200201
<FieldContent className="flex flex-col gap-0 divide-y overflow-y-auto">
201202
{value?.map((row: ImageSet, index: number) => {
202203
const issue = issuesByIndex?.[index];
204+
// The preview renders files sorted, and reports the index of what
205+
// the user actually clicked. Resolving that index here, against the
206+
// same array, is what keeps "remove this one" meaning the frame
207+
// under the cursor rather than whichever one happens to sit at that
208+
// position in the stored order. See #251.
209+
const sorted = row.files.toSorted((a, b) => a.localeCompare(b));
203210

204211
return (
205212
<div
@@ -211,7 +218,7 @@ export function ImageMatrixInput<
211218
>
212219
<ImageSetPreview
213220
disabled={disabled}
214-
files={row.files.toSorted((a, b) => a.localeCompare(b))}
221+
files={sorted}
215222
name={row.name}
216223
onAdd={async () => {
217224
const newFiles = await pickFiles({
@@ -230,12 +237,26 @@ export function ImageMatrixInput<
230237
}}
231238
onClick={setSelectedImage}
232239
onRemove={() => {
240+
dropRawConversions(row.files);
233241
field.onChange(value.filter((_, i) => i !== index));
234242
}}
235243
onRemoveIndex={(deleteIndex) => {
244+
const removed = sorted[deleteIndex];
245+
// The preview maps over the array it was handed, so this
246+
// index is always in bounds -- the check is only what
247+
// `noUncheckedIndexedAccess` needs to see.
248+
if (removed === undefined) {
249+
return;
250+
}
251+
dropRawConversions([removed]);
236252
value[index] = {
237253
...row,
238-
files: row.files.filter((_, i) => i !== deleteIndex),
254+
// Filtered by identity rather than by writing `sorted`
255+
// back, which would also normalise the stored order on
256+
// the first removal -- a change `onAdd` would undo on the
257+
// next addition, so the array would flip between sorted
258+
// and not depending on which the user did last.
259+
files: row.files.filter((file) => file !== removed),
239260
};
240261
field.onChange([...value]);
241262
}}

0 commit comments

Comments
 (0)