Skip to content

Commit a1703e5

Browse files
Yash02RajputJamesGeorg
authored andcommitted
fix: ensure all files are selected across paginated file lists
1 parent 94a3b8f commit a1703e5

1 file changed

Lines changed: 61 additions & 27 deletions

File tree

  • airborne_dashboard/app/dashboard/[orgId]/[appId]/packages/create

airborne_dashboard/app/dashboard/[orgId]/[appId]/packages/create/page.tsx

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export default function CreatePackagePage() {
5050
// Step 2: Package Files
5151
const [searchQuery, setSearchQuery] = useState("");
5252
const [packageFileCurrentPage, setPackageFileCurrentPage] = useState(1);
53-
const [selected, setSelected] = useState<Record<string, boolean>>({});
53+
const [selectedFiles, setSelectedFiles] = useState<Map<string, string>>(new Map()); // Map<file_path, file_id>
54+
5455
const [isSubmitting, setIsSubmitting] = useState(false);
5556
const router = useRouter();
5657

@@ -102,23 +103,25 @@ export default function CreatePackagePage() {
102103
const availableFiles = useMemo(() => {
103104
if (!selectedIndexFile) return files;
104105
return files.filter((f) => {
105-
const indexKey = selectedIndexFile.id || `${selectedIndexFile.file_path}@${selectedIndexFile.version}`;
106-
const fileKey = f.id || `${f.file_path}@${f.version}`;
106+
const indexKey = selectedIndexFile.id || `${selectedIndexFile.file_path}@version:${selectedIndexFile.version}`;
107+
const fileKey = f.id || `${f.file_path}@version:${f.version}`;
107108
return fileKey !== indexKey;
108109
});
109110
}, [files, selectedIndexFile]);
110111

111-
const toggle = (f: ApiFile) => {
112-
const key = f.id || `${f.file_path}@${f.version}`;
113-
setSelected((prev) => ({ ...prev, [key]: !prev[key] }));
114-
};
112+
const toggle = (fileId: string) => {
113+
const file_path = fileId.split("@version:")[0];
115114

116-
const selectedList = useMemo(() => {
117-
return availableFiles.filter((f) => {
118-
const key = f.id || `${f.file_path}@${f.version}`;
119-
return selected[key];
115+
setSelectedFiles((prev) => {
116+
const newMap = new Map(prev);
117+
if (newMap.has(file_path)) {
118+
newMap.delete(file_path);
119+
} else {
120+
newMap.set(file_path, fileId);
121+
}
122+
return newMap;
120123
});
121-
}, [availableFiles, selected]);
124+
};
122125

123126
const canProceedToStep = (step: number) => {
124127
switch (step) {
@@ -253,7 +256,7 @@ export default function CreatePackagePage() {
253256
return;
254257
}
255258

256-
const fileIds = selectedList.map((f) => f.id || f.file_path);
259+
const fileIds = Array.from(selectedFiles.values());
257260
const indexPath = selectedIndexFile ? `${selectedIndexFile.file_path}@version:${selectedIndexFile.version}` : "";
258261

259262
await apiFetch(
@@ -395,11 +398,11 @@ export default function CreatePackagePage() {
395398
</TableHeader>
396399
<TableBody>
397400
{indexFiles.map((f) => {
398-
const key = f.id || `${f.file_path}@${f.version}`;
401+
const key = f.id || `${f.file_path}@version:${f.version}`;
399402
const isSelected =
400403
selectedIndexFile &&
401404
(selectedIndexFile.id ||
402-
`${selectedIndexFile.file_path}@${selectedIndexFile.version}`) === key;
405+
`${selectedIndexFile.file_path}@version:${selectedIndexFile.version}`) === key;
403406
return (
404407
<TableRow key={key}>
405408
<TableCell>
@@ -516,13 +519,35 @@ export default function CreatePackagePage() {
516519
</TableHeader>
517520
<TableBody>
518521
{availableFiles.map((f) => {
519-
const key = f.id || `${f.file_path}@${f.version}`;
522+
const fileId = f.id || `${f.file_path}@version:${f.version}`;
523+
const selectedFileId = selectedFiles.get(f.file_path);
524+
const isThisVersionSelected = selectedFileId === fileId;
525+
const isAnotherVersionSelected = selectedFileId && selectedFileId !== fileId;
526+
const isSameAsIndexFile = selectedIndexFile && f.file_path === selectedIndexFile.file_path;
527+
520528
return (
521-
<TableRow key={key}>
529+
<TableRow
530+
key={fileId}
531+
className={isAnotherVersionSelected || isSameAsIndexFile ? "opacity-50" : ""}
532+
>
522533
<TableCell>
523-
<Checkbox checked={!!selected[key]} onCheckedChange={() => toggle(f)} />
534+
<Checkbox
535+
checked={isThisVersionSelected}
536+
disabled={!!isAnotherVersionSelected || !!isSameAsIndexFile}
537+
onCheckedChange={() => toggle(fileId)}
538+
/>
539+
</TableCell>
540+
<TableCell className="font-mono text-sm">
541+
{f.file_path}
542+
{isAnotherVersionSelected && (
543+
<div className="text-xs text-amber-600 mt-1">Another version already selected</div>
544+
)}
545+
{isSameAsIndexFile && (
546+
<div className="text-xs text-amber-600 mt-1">
547+
Another version is selected as the index file
548+
</div>
549+
)}
524550
</TableCell>
525-
<TableCell className="font-mono text-sm">{f.file_path}</TableCell>
526551
<TableCell className="text-muted-foreground">{f.version}</TableCell>
527552
<TableCell className="text-muted-foreground">{f.tag || "—"}</TableCell>
528553
</TableRow>
@@ -576,20 +601,29 @@ export default function CreatePackagePage() {
576601
</div>
577602
)}
578603

579-
{selectedList.length > 0 && (
604+
{selectedFiles.size > 0 && (
580605
<div className="mt-4 space-y-2">
581-
<Label>Selected Files ({selectedList.length})</Label>
606+
<Label>Selected Files ({selectedFiles.size})</Label>
582607
<div className="max-h-40 overflow-y-auto space-y-1">
583-
{selectedList.map((f) => {
584-
const key = f.id || `${f.file_path}@${f.version}`;
608+
{Array.from(selectedFiles.values()).map((fileId) => {
609+
const [file_path, versionPart] = fileId.split("@version:");
585610
return (
586-
<div key={key} className="flex items-center justify-between p-2 bg-muted/50 rounded text-sm">
611+
<div
612+
key={file_path}
613+
className="flex items-center justify-between p-2 bg-muted/50 rounded text-sm"
614+
>
587615
<div className="flex items-center gap-2">
588616
<FileText className="h-4 w-4" />
589-
<span className="font-mono">{f.file_path}</span>
590-
<span className="text-muted-foreground">(v{f.version})</span>
617+
<span className="font-mono">{file_path}</span>
618+
{versionPart && <span className="text-muted-foreground">(Version {versionPart})</span>}
591619
</div>
592-
<Button variant="ghost" size="sm" onClick={() => toggle(f)}>
620+
<Button
621+
variant="ghost"
622+
size="sm"
623+
onClick={() => {
624+
toggle(fileId);
625+
}}
626+
>
593627
Remove
594628
</Button>
595629
</div>

0 commit comments

Comments
 (0)