@@ -690,4 +690,162 @@ export async function onBeforeRouteLeaveCreateEditViewGuard(initialValues: any,
690690 leaveGuardActive . setActive ( false ) ;
691691 }
692692 } ) ;
693+ }
694+
695+ export async function executeCustomAction ( {
696+ actionId,
697+ resourceId,
698+ recordId,
699+ extra = { } ,
700+ onSuccess,
701+ onError,
702+ setLoadingState,
703+ } : {
704+ actionId : string | number ,
705+ resourceId : string ,
706+ recordId : string | number ,
707+ extra ?: Record < string , any > ,
708+ onSuccess ?: ( data : any ) => Promise < void > ,
709+ onError ?: ( error : string ) => void ,
710+ setLoadingState ?: ( loading : boolean ) => void ,
711+ } ) : Promise < any > {
712+ setLoadingState ?.( true ) ;
713+
714+ try {
715+ const data = await callAdminForthApi ( {
716+ path : '/start_custom_action' ,
717+ method : 'POST' ,
718+ body : {
719+ resourceId,
720+ actionId,
721+ recordId,
722+ extra : extra || { } ,
723+ }
724+ } ) ;
725+
726+ if ( data ?. redirectUrl ) {
727+ // Check if the URL should open in a new tab
728+ if ( data . redirectUrl . includes ( 'target=_blank' ) ) {
729+ window . open ( data . redirectUrl . replace ( '&target=_blank' , '' ) . replace ( '?target=_blank' , '' ) , '_blank' ) ;
730+ } else {
731+ // Navigate within the app
732+ if ( data . redirectUrl . startsWith ( 'http' ) ) {
733+ window . location . href = data . redirectUrl ;
734+ } else {
735+ router . push ( data . redirectUrl ) ;
736+ }
737+ }
738+ return data ;
739+ }
740+
741+ if ( data ?. ok ) {
742+ if ( onSuccess ) {
743+ await onSuccess ( data ) ;
744+ }
745+ return data ;
746+ }
747+
748+ if ( data ?. error ) {
749+ if ( onError ) {
750+ onError ( data . error ) ;
751+ }
752+ }
753+
754+ return data ;
755+ } finally {
756+ setLoadingState ?.( false ) ;
757+ }
758+ }
759+
760+ export async function executeCustomBulkAction ( {
761+ actionId,
762+ resourceId,
763+ recordIds,
764+ extra = { } ,
765+ onSuccess,
766+ onError,
767+ setLoadingState,
768+ confirmMessage,
769+ } : {
770+ actionId : string | number ,
771+ resourceId : string ,
772+ recordIds : ( string | number ) [ ] ,
773+ extra ?: Record < string , any > ,
774+ onSuccess ?: ( results : any [ ] ) => Promise < void > ,
775+ onError ?: ( error : string ) => void ,
776+ setLoadingState ?: ( loading : boolean ) => void ,
777+ confirmMessage ?: string ,
778+ } ) : Promise < any > {
779+ if ( ! recordIds || recordIds . length === 0 ) {
780+ if ( onError ) {
781+ onError ( 'No records selected' ) ;
782+ }
783+ return { error : 'No records selected' } ;
784+ }
785+
786+ if ( confirmMessage ) {
787+ const { confirm } = useAdminforth ( ) ;
788+ const confirmed = await confirm ( {
789+ message : confirmMessage ,
790+ } ) ;
791+ if ( ! confirmed ) {
792+ return { cancelled : true } ;
793+ }
794+ }
795+
796+ setLoadingState ?.( true ) ;
797+
798+ try {
799+ // Execute action for all records in parallel using Promise.all
800+ const results = await Promise . all (
801+ recordIds . map ( recordId =>
802+ callAdminForthApi ( {
803+ path : '/start_custom_action' ,
804+ method : 'POST' ,
805+ body : {
806+ resourceId,
807+ actionId,
808+ recordId,
809+ extra : extra || { } ,
810+ }
811+ } )
812+ )
813+ ) ;
814+
815+ const lastResult = results [ results . length - 1 ] ;
816+ if ( lastResult ?. redirectUrl ) {
817+ if ( lastResult . redirectUrl . includes ( 'target=_blank' ) ) {
818+ window . open ( lastResult . redirectUrl . replace ( '&target=_blank' , '' ) . replace ( '?target=_blank' , '' ) , '_blank' ) ;
819+ } else {
820+ if ( lastResult . redirectUrl . startsWith ( 'http' ) ) {
821+ window . location . href = lastResult . redirectUrl ;
822+ } else {
823+ router . push ( lastResult . redirectUrl ) ;
824+ }
825+ }
826+ return lastResult ;
827+ }
828+
829+ const allSucceeded = results . every ( r => r ?. ok ) ;
830+ const hasErrors = results . some ( r => r ?. error ) ;
831+
832+ if ( allSucceeded ) {
833+ if ( onSuccess ) {
834+ await onSuccess ( results ) ;
835+ }
836+ return { ok : true , results } ;
837+ }
838+
839+ if ( hasErrors ) {
840+ const errorMessages = results . filter ( r => r ?. error ) . map ( r => r . error ) . join ( ', ' ) ;
841+ if ( onError ) {
842+ onError ( errorMessages ) ;
843+ }
844+ return { error : errorMessages , results } ;
845+ }
846+
847+ return { results } ;
848+ } finally {
849+ setLoadingState ?.( false ) ;
850+ }
693851}
0 commit comments