diff --git a/src/components/Process/Row.vue b/src/components/Process/Row.vue
index 126a37be755c24bc5bfc5f37f12fd8b01168fbd0..8eb421f9ae1f460ee6eb5ec811f9887a6f8bf399 100644
--- a/src/components/Process/Row.vue
+++ b/src/components/Process/Row.vue
@@ -57,7 +57,7 @@
         <p class="control" v-if="canDelete">
           <button
             class="button has-text-danger"
-            v-on:click="remove"
+            v-on:click="deleteModal = hasAdminAccess"
             :disabled="!hasAdminAccess || null"
             :title="hasAdminAccess ? 'Delete this process' : 'An admin access is required to delete this process'"
           >
@@ -67,25 +67,47 @@
       </div>
     </td>
   </tr>
+  <Modal v-model="deleteModal" title="Delete process">
+    <span>
+      Are you sure you want to delete process <strong>{{ deleteModalText }}</strong>?
+    </span>
+    <br />
+    <span>This action is irreversible.</span>
+    <template v-slot:footer="{ close }">
+      <button class="button" v-on:click="close">Cancel</button>
+      <button
+        class="button is-danger"
+        :class="{ 'is-loading': deleteLoading }"
+        v-on:click="remove"
+      >
+        Delete
+      </button>
+    </template>
+  </Modal>
 </template>
 
 <script>
-import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
+import { mapState, mapGetters, mapActions as mapVuexActions } from 'vuex'
+import { mapActions } from 'pinia'
 
 import { PROCESS_MODES, PROCESS_FINAL_STATES } from '@/config'
 import { ago, errorParser, humanTimedelta, secondsToTimedelta } from '@/helpers'
-import { corporaMixin } from '@/mixins'
+import { corporaMixin, truncateMixin } from '@/mixins'
 
 import ItemId from '@/components/ItemId.vue'
 import StateTag from './StateTag.vue'
+import Modal from '@/components/Modal.vue'
+import { useNotificationStore } from '@/stores'
 
 export default {
   mixins: [
-    corporaMixin
+    corporaMixin,
+    truncateMixin
   ],
   components: {
     ItemId,
-    StateTag
+    StateTag,
+    Modal
   },
   emits: ['update'],
   props: {
@@ -94,6 +116,10 @@ export default {
       required: true
     }
   },
+  data: () => ({
+    deleteModal: false,
+    deleteLoading: false
+  }),
   computed: {
     ...mapState('process', ['processes']),
     ...mapGetters('auth', ['isVerified']),
@@ -164,17 +190,26 @@ export default {
     durationText () {
       if (['unscheduled', 'pending'].includes(this.process.state)) return 'Pending for '
       return 'Running for '
+    },
+    deleteModalText () {
+      if (this.process.name?.length > 0) return `${this.truncateShort(this.process.name)} (${this.process.id})`
+      return this.process.id
     }
   },
   methods: {
-    ...mapActions('process', ['deleteProcess', 'retryProcess']),
-    ...mapMutations('notifications', ['notify']),
+    ...mapVuexActions('process', ['deleteProcess', 'retryProcess']),
+    ...mapActions(useNotificationStore, ['notify']),
     async remove () {
+      if (this.deleteLoading || !this.hasAdminAccess) return
+      this.deleteLoading = true
       try {
         const response = await this.deleteProcess(this.processId)
         if (response.status === 204) this.$emit('update')
+        this.deleteModal = false
       } catch (err) {
         this.notify({ type: 'error', text: errorParser(err) })
+      } finally {
+        this.deleteLoading = false
       }
     },
     async retry () {