@@ -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