@@ -10,6 +10,8 @@ import {
1010 EnablePackage ,
1111 PullApk ,
1212 UninstallMultiplePackages ,
13+ DisableMultiplePackages ,
14+ EnableMultiplePackages ,
1315} from '../../../wailsjs/go/backend/App' ;
1416import { backend } from '../../../wailsjs/go/models' ;
1517
@@ -90,6 +92,11 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
9092 const [ isBatchUninstalling , setIsBatchUninstalling ] = useState ( false ) ;
9193 const [ isBatchUninstallOpen , setIsBatchUninstallOpen ] = useState ( false ) ;
9294
95+ const [ isBatchDisabling , setIsBatchDisabling ] = useState ( false ) ;
96+ const [ isBatchDisablingOpen , setIsBatchDisablingOpen ] = useState ( false ) ;
97+ const [ isBatchEnabling , setIsBatchEnabling ] = useState ( false ) ;
98+ const [ isBatchEnablingOpen , setIsBatchEnablingOpen ] = useState ( false ) ;
99+
93100 const loadPackages = async ( currentFilter : FilterType ) => {
94101 setIsLoadingList ( true ) ;
95102 try {
@@ -330,6 +337,60 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
330337 setIsBatchUninstallOpen ( false ) ;
331338 }
332339 } ;
340+
341+ const handleMultiDisable = async ( ) => {
342+ if ( selectedPackages . length === 0 ) return ;
343+ setIsBatchDisabling ( true ) ;
344+ const toastId = toast . loading (
345+ `Disabling ${ selectedPackages . length } packages...`
346+ ) ;
347+ try {
348+ const output = await DisableMultiplePackages ( selectedPackages ) ;
349+ toast . success ( 'Batch Disable Complete' , {
350+ description : output ,
351+ id : toastId ,
352+ duration : 8000 ,
353+ } ) ;
354+ loadPackages ( filter ) ;
355+ setSelectedPackages ( [ ] ) ;
356+ } catch ( error ) {
357+ toast . error ( 'Batch Disable Failed' , {
358+ description : String ( error ) ,
359+ id : toastId ,
360+ } ) ;
361+ } finally {
362+ setIsBatchDisabling ( false ) ;
363+ setIsBatchDisablingOpen ( false ) ;
364+ }
365+ } ;
366+
367+ const handleMultiEnable = async ( ) => {
368+ if ( selectedPackages . length === 0 ) return ;
369+ setIsBatchEnabling ( true ) ;
370+ const toastId = toast . loading (
371+ `Enabling ${ selectedPackages . length } packages...`
372+ ) ;
373+ try {
374+ const output = await EnableMultiplePackages ( selectedPackages ) ;
375+ toast . success ( 'Batch Enable Complete' , {
376+ description : output ,
377+ id : toastId ,
378+ duration : 8000 ,
379+ } ) ;
380+ loadPackages ( filter ) ;
381+ setSelectedPackages ( [ ] ) ;
382+ } catch ( error ) {
383+ toast . error ( 'Batch Enable Failed' , {
384+ description : String ( error ) ,
385+ id : toastId ,
386+ } ) ;
387+ } finally {
388+ setIsBatchEnabling ( false ) ;
389+ setIsBatchEnablingOpen ( false ) ;
390+ }
391+ } ;
392+
393+ const isBusy = isLoadingList || isBatchUninstalling || isBatchDisabling || isBatchEnabling ;
333394
334395 return (
335396 < >
@@ -396,6 +457,78 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
396457 </ AlertDialogContent >
397458 </ AlertDialog >
398459
460+ < AlertDialog
461+ open = { isBatchDisablingOpen }
462+ onOpenChange = { setIsBatchDisablingOpen }
463+ >
464+ < AlertDialogContent >
465+ < AlertDialogHeader >
466+ < AlertDialogTitle > Are you sure?</ AlertDialogTitle >
467+ < AlertDialogDescription >
468+ You are about to attempt to disable{ ' ' }
469+ < span className = "font-semibold text-foreground" >
470+ { selectedPackages . length } selected packages
471+ </ span >
472+ .
473+ < br />
474+ < strong className = "text-destructive" >
475+ System apps will likely fail (this is normal).
476+ </ strong >
477+ </ AlertDialogDescription >
478+ </ AlertDialogHeader >
479+ < AlertDialogFooter >
480+ < AlertDialogCancel disabled = { isBatchDisabling } >
481+ Cancel
482+ </ AlertDialogCancel >
483+ < AlertDialogAction
484+ onClick = { handleMultiDisable }
485+ disabled = { isBatchDisabling }
486+ >
487+ { isBatchDisabling ? (
488+ < Loader2 className = "mr-2 h-4 w-4 animate-spin" />
489+ ) : (
490+ < EyeOff className = "mr-2 h-4 w-4" />
491+ ) }
492+ Yes, Disable { selectedPackages . length }
493+ </ AlertDialogAction >
494+ </ AlertDialogFooter >
495+ </ AlertDialogContent >
496+ </ AlertDialog >
497+
498+ < AlertDialog
499+ open = { isBatchEnablingOpen }
500+ onOpenChange = { setIsBatchEnablingOpen }
501+ >
502+ < AlertDialogContent >
503+ < AlertDialogHeader >
504+ < AlertDialogTitle > Are you sure?</ AlertDialogTitle >
505+ < AlertDialogDescription >
506+ You are about to attempt to enable{ ' ' }
507+ < span className = "font-semibold text-foreground" >
508+ { selectedPackages . length } selected packages
509+ </ span >
510+ .
511+ </ AlertDialogDescription >
512+ </ AlertDialogHeader >
513+ < AlertDialogFooter >
514+ < AlertDialogCancel disabled = { isBatchEnabling } >
515+ Cancel
516+ </ AlertDialogCancel >
517+ < AlertDialogAction
518+ onClick = { handleMultiEnable }
519+ disabled = { isBatchEnabling }
520+ >
521+ { isBatchEnabling ? (
522+ < Loader2 className = "mr-2 h-4 w-4 animate-spin" />
523+ ) : (
524+ < Eye className = "mr-2 h-4 w-4" />
525+ ) }
526+ Yes, Enable { selectedPackages . length }
527+ </ AlertDialogAction >
528+ </ AlertDialogFooter >
529+ </ AlertDialogContent >
530+ </ AlertDialog >
531+
399532 < div className = "flex flex-col gap-6" >
400533
401534 < div className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
@@ -519,7 +652,8 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
519652 List of applications installed on the device.
520653 </ CardDescription >
521654 </ div >
522- < div className = "flex items-center gap-2" >
655+ < div className = "flex items-center gap-2 flex-wrap justify-end" >
656+ { /* Grup Filter */ }
523657 < Button
524658 variant = { filter === 'user' ? 'default' : 'outline' }
525659 size = "sm"
@@ -545,22 +679,41 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
545679 variant = "ghost"
546680 size = "icon"
547681 onClick = { ( ) => loadPackages ( filter ) }
548- disabled = { isLoadingList || isBatchUninstalling }
682+ disabled = { isBusy }
549683 >
550- { isLoadingList ? (
684+ { isBusy ? (
551685 < Loader2 className = "h-4 w-4 animate-spin" />
552686 ) : (
553687 < RefreshCw className = "h-4 w-4" />
554688 ) }
555689 </ Button >
690+
691+ < Button
692+ variant = "outline"
693+ size = "sm"
694+ disabled = { selectedPackages . length === 0 || isBusy }
695+ onClick = { ( ) => setIsBatchEnablingOpen ( true ) }
696+ >
697+ < Eye className = "mr-2 h-4 w-4" />
698+ Enable ({ selectedPackages . length } )
699+ </ Button >
700+ < Button
701+ variant = "outline"
702+ size = "sm"
703+ disabled = { selectedPackages . length === 0 || isBusy }
704+ onClick = { ( ) => setIsBatchDisablingOpen ( true ) }
705+ >
706+ < EyeOff className = "mr-2 h-4 w-4" />
707+ Disable ({ selectedPackages . length } )
708+ </ Button >
556709 < Button
557710 variant = "destructive"
558711 size = "sm"
559- disabled = { selectedPackages . length === 0 || isBatchUninstalling }
712+ disabled = { selectedPackages . length === 0 || isBusy }
560713 onClick = { ( ) => setIsBatchUninstallOpen ( true ) }
561714 >
562715 < Trash2 className = "mr-2 h-4 w-4" />
563- Uninstall Selected ({ selectedPackages . length } )
716+ Uninstall ({ selectedPackages . length } )
564717 </ Button >
565718 </ div >
566719 </ CardHeader >
0 commit comments