77 :download =" download_percentage"
88 :extraction =" extraction_percentage"
99 :statustext =" status_text"
10+ :cancelable =" !!active_abort_controller"
11+ @cancel =" cancelInstallOperation"
1012 />
1113 <v-dialog
1214 v-model =" show_dialog"
@@ -510,6 +512,7 @@ export default Vue.extend({
510512 active_operation_identifier: localStorage .getItem (ACTIVE_OPERATION_KEY ) as null | string ,
511513 active_operation_type: (localStorage .getItem (ACTIVE_OPERATION_TYPE_KEY ) ?? null ) as null | ' install' | ' update' ,
512514 session: null as Session | null ,
515+ active_abort_controller: null as null | AbortController ,
513516 }
514517 },
515518 computed: {
@@ -619,6 +622,8 @@ export default Vue.extend({
619622 clearInterval (this .metrics_interval )
620623 this .stopUploadKeepAlive ()
621624 this .session = null
625+ this .active_abort_controller ?.abort ()
626+ this .active_abort_controller = null
622627 },
623628 methods: {
624629 async initializeZenohSession() {
@@ -635,6 +640,25 @@ export default Vue.extend({
635640 clearEditedExtension() {
636641 this .edited_extension = null
637642 },
643+ beginInstallOperation(): AbortController {
644+ this .active_abort_controller ?.abort ()
645+ const controller = new AbortController ()
646+ this .active_abort_controller = controller
647+ return controller
648+ },
649+ cancelInstallOperation(): void {
650+ this .active_abort_controller ?.abort ()
651+ },
652+ showAlertError(error : unknown ): void {
653+ this .alerter = true
654+ this .alerter_error = String (error )
655+ },
656+ finishInstallOperation(): void {
657+ this .active_abort_controller = null
658+ this .clearInstallingState ()
659+ this .resetPullOutput ()
660+ this .fetchInstalledExtensions ()
661+ },
638662 setInstallFromFilePhase(phase : TarInstallPhase ) {
639663 this .install_from_file_phase = phase
640664 if (phase !== ' error' ) {
@@ -791,24 +815,30 @@ export default Vue.extend({
791815 async update(extension : InstalledExtensionData , version : string ) {
792816 this .setInstallingState (extension .identifier , ' update' )
793817 this .show_pull_output = true
794- const tracker = this .getTracker ()
818+ const controller = this .beginInstallOperation ()
819+ const tracker = this .getTracker (controller .signal )
795820 kraken .updateExtensionToVersion (
796821 extension .identifier ,
797822 version ,
798823 (progressEvent ) => this .handleDownloadProgress (progressEvent .event , tracker ),
824+ controller .signal ,
799825 )
800826 .then (() => {
801- this .fetchInstalledExtensions ()
802827 notifier .pushSuccess (' EXTENSION_UPDATE_SUCCESS' , ` ${extension .name } updated successfully. ` , true )
803828 })
804- .catch ((error ) => {
805- this .alerter = true
806- this .alerter_error = String (error )
829+ .catch (async (error ) => {
830+ if (axios .isCancel (error )) {
831+ if (controller !== this .active_abort_controller ) return
832+ await kraken .uninstallExtensionVersion (extension .identifier , version )
833+ .catch (() => { /* version may not be registered yet */ })
834+ notifier .pushInfo (' EXTENSION_UPDATE_CANCELLED' , ' Extension update was cancelled.' , true )
835+ return
836+ }
837+ this .showAlertError (error )
807838 notifier .pushBackError (' EXTENSION_UPDATE_FAIL' , error )
808839 })
809840 .finally (() => {
810- this .clearInstallingState ()
811- this .resetPullOutput ()
841+ if (controller === this .active_abort_controller ) this .finishInstallOperation ()
812842 })
813843 },
814844 metricsFor(extension : InstalledExtensionData ): { cpu: number , memory: number } | Record <string , never > {
@@ -929,24 +959,30 @@ export default Vue.extend({
929959 this .setInstallingState (extension .identifier , ' install' )
930960 this .show_dialog = false
931961 this .show_pull_output = true
932- const tracker = this .getTracker ()
962+ const controller = this .beginInstallOperation ()
963+ const tracker = this .getTracker (controller .signal )
933964
934965 kraken .installExtension (
935966 extension ,
936967 (progressEvent ) => this .handleDownloadProgress (progressEvent .event , tracker ),
968+ controller .signal ,
937969 )
938970 .then (() => {
939- this .fetchInstalledExtensions ()
940971 notifier .pushSuccess (' EXTENSION_INSTALL_SUCCESS' , ` ${extension .name } installed successfully. ` , true )
941972 })
942- .catch ((error ) => {
943- this .alerter = true
944- this .alerter_error = String (error )
945- notifier .pushBackError (' EXTENSIONS_INSTALL_FAIL' , error )
973+ .catch (async (error ) => {
974+ if (axios .isCancel (error )) {
975+ if (controller !== this .active_abort_controller ) return
976+ await kraken .uninstallExtensionVersion (extension .identifier , extension .tag )
977+ .catch (() => { /* version may not be registered yet */ })
978+ notifier .pushInfo (' EXTENSION_INSTALL_CANCELLED' , ' Extension install was cancelled.' , true )
979+ return
980+ }
981+ this .showAlertError (error )
982+ notifier .pushBackError (' EXTENSION_INSTALL_FAIL' , error )
946983 })
947984 .finally (() => {
948- this .clearInstallingState ()
949- this .resetPullOutput ()
985+ if (controller === this .active_abort_controller ) this .finishInstallOperation ()
950986 })
951987 },
952988 async performActionFromModal(
@@ -1055,17 +1091,17 @@ export default Vue.extend({
10551091 temp [extension .identifier ].loading = loading
10561092 this .installed_extensions = temp
10571093 },
1058- getTracker(): PullTracker {
1094+ getTracker(signal : AbortSignal ): PullTracker {
10591095 return new PullTracker (
10601096 () => {
10611097 setTimeout (() => {
10621098 this .show_pull_output = false
10631099 }, 1000 )
10641100 },
10651101 (error ) => {
1066- this . alerter = true
1067- this .alerter_error = String (error )
1068- notifier .pushBackError (' EXTENSIONS_INSTALL_FAIL ' , error )
1102+ if ( signal . aborted ) return
1103+ this .showAlertError (error )
1104+ notifier .pushBackError (' EXTENSION_INSTALL_FAIL ' , error )
10691105 this .show_pull_output = false
10701106 },
10711107 )
@@ -1119,7 +1155,8 @@ export default Vue.extend({
11191155 }
11201156
11211157 this .show_pull_output = true
1122- const tracker = this .getTracker ()
1158+ const controller = this .beginInstallOperation ()
1159+ const tracker = this .getTracker (controller .signal )
11231160 this .setInstallFromFilePhase (' installing' )
11241161 this .install_from_file_install_progress = 0
11251162 this .install_from_file_status_text = ' Starting installation...'
@@ -1129,20 +1166,29 @@ export default Vue.extend({
11291166 extension ,
11301167 this .upload_temp_tag ,
11311168 (progressEvent ) => this .handleDownloadProgress (progressEvent .event , tracker ),
1169+ controller .signal ,
11321170 )
11331171 this .setInstallFromFilePhase (' success' )
11341172 this .install_from_file_status_text = ' Extension installed successfully'
11351173 this .stopUploadKeepAlive ()
11361174 this .upload_temp_tag = null
11371175 this .upload_metadata = null
1138- this .fetchInstalledExtensions ()
11391176 } catch (error ) {
1140- this .applyInstallFromFileError (String (error ))
1141- this .alerter = true
1142- this .alerter_error = String (error )
1143- notifier .pushBackError (' EXTENSION_FINALIZE_FAIL' , error )
1177+ if (axios .isCancel (error )) {
1178+ if (controller === this .active_abort_controller ) {
1179+ this .setInstallFromFilePhase (' ready' )
1180+ this .install_from_file_status_text = ' '
1181+ await kraken .uninstallExtensionVersion (extension .identifier , extension .tag )
1182+ .catch (() => { /* version may not be registered yet */ })
1183+ notifier .pushInfo (' EXTENSION_INSTALL_CANCELLED' , ' Installation from file was cancelled.' , true )
1184+ }
1185+ } else {
1186+ this .applyInstallFromFileError (String (error ))
1187+ this .showAlertError (error )
1188+ notifier .pushBackError (' EXTENSION_FINALIZE_FAIL' , error )
1189+ }
11441190 } finally {
1145- this .resetPullOutput ()
1191+ if ( controller === this .active_abort_controller ) this . finishInstallOperation ()
11461192 }
11471193 },
11481194 setInstallingState(identifier : string , action : ' install' | ' update' ): void {
0 commit comments