mirror of
https://github.com/borgbase/vorta
synced 2025-03-12 07:09:37 +00:00
Select and delete multiple archives. By @real-yfprojects (#1307)
This commit is contained in:
parent
b650ed3eb6
commit
03480112e6
3 changed files with 85 additions and 59 deletions
|
@ -265,25 +265,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="bDelete">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete selected archive</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -319,6 +300,25 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="bDelete">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete selected archive</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -349,8 +349,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>781</width>
|
||||
<height>371</height>
|
||||
<width>540</width>
|
||||
<height>352</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from typing import List
|
||||
|
||||
from vorta.store.models import RepoModel
|
||||
|
||||
from .borg_job import BorgJob
|
||||
|
@ -23,17 +25,22 @@ class BorgDeleteJob(BorgJob):
|
|||
self.app.backup_progress_event.emit(self.tr('Archive deleted.'))
|
||||
|
||||
@classmethod
|
||||
def prepare(cls, profile):
|
||||
def prepare(cls, profile, archives: List[str]):
|
||||
ret = super().prepare(profile)
|
||||
if not ret['ok']:
|
||||
return ret
|
||||
else:
|
||||
ret['ok'] = False # Set back to false, so we can do our own checks here.
|
||||
|
||||
cmd = ['borg', 'delete', '--info', '--log-json']
|
||||
cmd.append(f'{profile.repo.url}')
|
||||
if len(archives) <= 0:
|
||||
return ret
|
||||
|
||||
ret['ok'] = True
|
||||
cmd = ['borg', 'delete', '--info', '--log-json']
|
||||
cmd.append(f'{profile.repo.url}::{archives[0]}')
|
||||
cmd.extend(archives[1:])
|
||||
|
||||
ret['archives'] = archives
|
||||
ret['cmd'] = cmd
|
||||
ret['ok'] = True
|
||||
|
||||
return ret
|
||||
|
|
|
@ -23,7 +23,6 @@ from vorta.borg.mount import BorgMountJob
|
|||
from vorta.borg.prune import BorgPruneJob
|
||||
from vorta.borg.rename import BorgRenameJob
|
||||
from vorta.borg.umount import BorgUmountJob
|
||||
from vorta.i18n import trans_late
|
||||
from vorta.store.models import ArchiveModel, BackupProfileMixin
|
||||
from vorta.utils import (choose_file_dialog, format_archive_name, get_asset,
|
||||
get_mount_points, pretty_bytes)
|
||||
|
@ -56,6 +55,7 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
|||
#: Tooltip dict to save the tooltips set in the designer
|
||||
self.tooltip_dict: Dict[QWidget, str] = {}
|
||||
self.tooltip_dict[self.bDiff] = self.bDiff.toolTip()
|
||||
self.tooltip_dict[self.bDelete] = self.bDelete.toolTip()
|
||||
|
||||
header = self.archiveTable.horizontalHeader()
|
||||
header.setVisible(True)
|
||||
|
@ -161,16 +161,16 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
|||
self.refresh_archive_info))
|
||||
archive_actions.append(
|
||||
menu.addAction(self.bMountArchive.icon(), self.bMountArchive.text(),
|
||||
self.bmount_clicked))
|
||||
self.bmountarchive_clicked))
|
||||
archive_actions.append(
|
||||
menu.addAction(self.bExtract.icon(), self.bExtract.text(),
|
||||
self.extract_action))
|
||||
archive_actions.append(
|
||||
menu.addAction(self.bRename.icon(), self.bRename.text(),
|
||||
self.rename_action))
|
||||
archive_actions.append(
|
||||
menu.addAction(self.bDelete.icon(), self.bDelete.text(),
|
||||
self.delete_action))
|
||||
# deletion possible with one but also multiple archives
|
||||
menu.addAction(self.bDelete.icon(), self.bDelete.text(),
|
||||
self.delete_action)
|
||||
|
||||
if not (self.repoactions_enabled and len(selected_rows) <= 1):
|
||||
for action in archive_actions:
|
||||
|
@ -185,7 +185,7 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
|||
selected_rows = self.archiveTable.selectionModel().selectedRows(
|
||||
index.column())
|
||||
diff_action.setEnabled(self.repoactions_enabled
|
||||
and len(selected_rows) > 1)
|
||||
and len(selected_rows) == 2)
|
||||
|
||||
menu.popup(self.archiveTable.viewport().mapToGlobal(pos))
|
||||
|
||||
|
@ -296,15 +296,18 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
|||
# Toggle archive actions frame
|
||||
layout: QLayout = self.fArchiveActions.layout()
|
||||
|
||||
# Make sure at maximum 2 rows are selected.
|
||||
if len(indexes) > 2:
|
||||
selectionModel.select(
|
||||
indexes[0], QItemSelectionModel.SelectionFlag.Deselect
|
||||
| QItemSelectionModel.SelectionFlag.Rows)
|
||||
indexes = selectionModel.selectedRows()
|
||||
# toggle delete button
|
||||
if len(indexes) > 0:
|
||||
self.bDelete.setEnabled(True)
|
||||
self.bDelete.setToolTip(self.tooltip_dict.get(self.bDelete, ""))
|
||||
else:
|
||||
self.bDelete.setEnabled(False)
|
||||
tooltip = self.tooltip_dict[self.bDelete]
|
||||
self.bDelete.setToolTip(tooltip + " " +
|
||||
self.tr("(Select two archives)"))
|
||||
|
||||
# Toggle diff button
|
||||
if len(indexes) >= 2:
|
||||
if len(indexes) == 2:
|
||||
# Enable diff button
|
||||
self.bDiff.setEnabled(True)
|
||||
self.bDiff.setToolTip(self.tooltip_dict.get(self.bDiff, ""))
|
||||
|
@ -763,35 +766,51 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
|||
def delete_action(self):
|
||||
# Since this function modify the UI, we can't put the whole function in a JobQUeue.
|
||||
|
||||
params = BorgDeleteJob.prepare(self.profile())
|
||||
# determine selected archives
|
||||
archives = []
|
||||
for index in self.archiveTable.selectionModel().selectedRows():
|
||||
archive_cell = self.archiveTable.item(index.row(), 4)
|
||||
if archive_cell:
|
||||
archives.append(archive_cell.text())
|
||||
|
||||
if not archives:
|
||||
self._set_status(self.tr("No archive selected"))
|
||||
return
|
||||
|
||||
params = BorgDeleteJob.prepare(self.profile(), archives)
|
||||
if not params['ok']:
|
||||
self._set_status(params['message'])
|
||||
return
|
||||
|
||||
self.archive_name = self.selected_archive_name()
|
||||
if self.archive_name is not None:
|
||||
if not self.confirm_dialog(trans_late('ArchiveTab', "Confirm deletion"),
|
||||
trans_late('ArchiveTab', "Are you sure you want to delete the archive?")):
|
||||
return
|
||||
params['cmd'][-1] += f'::{self.archive_name}'
|
||||
job = BorgDeleteJob(params['cmd'], params, self.profile().repo.id)
|
||||
job.updated.connect(self._set_status)
|
||||
job.result.connect(self.delete_result)
|
||||
self._toggle_all_buttons(False)
|
||||
self.app.jobs_manager.add_job(job)
|
||||
|
||||
if len(archives) > 1:
|
||||
body = self.tr("Are you sure you want to delete all the selected archives?")
|
||||
else:
|
||||
self._set_status(self.tr("No archive selected"))
|
||||
body = self.tr("Are you sure you want to delete the selected archive?")
|
||||
if not self.confirm_dialog(self.tr("Confirm deletion"), body):
|
||||
return
|
||||
|
||||
job = BorgDeleteJob(params['cmd'], params, self.profile().repo.id)
|
||||
job.updated.connect(self._set_status)
|
||||
job.result.connect(self.delete_result)
|
||||
self._toggle_all_buttons(False)
|
||||
self.app.jobs_manager.add_job(job)
|
||||
|
||||
def delete_result(self, result):
|
||||
archives = result['params']['archives']
|
||||
if result['returncode'] == 0:
|
||||
self._set_status(self.tr('Archive deleted.'))
|
||||
deleted_row = self.archiveTable.findItems(self.archive_name, QtCore.Qt.MatchExactly)[0].row()
|
||||
self.archiveTable.removeRow(deleted_row)
|
||||
ArchiveModel.get(name=self.archive_name).delete_instance()
|
||||
del self.archive_name
|
||||
else:
|
||||
self._toggle_all_buttons(True)
|
||||
if len(archives) > 1:
|
||||
status = self.tr('Archives deleted.')
|
||||
else:
|
||||
status = self.tr('Archive deleted.')
|
||||
self._set_status(status)
|
||||
|
||||
# remove rows from list and database
|
||||
for archive in archives:
|
||||
for entry in self.archiveTable.findItems(archive, QtCore.Qt.MatchExactly):
|
||||
self.archiveTable.removeRow(entry.row())
|
||||
ArchiveModel.get(name=archive).delete_instance()
|
||||
|
||||
self._toggle_all_buttons(True)
|
||||
|
||||
def diff_action(self):
|
||||
"""
|
||||
|
|
Loading…
Add table
Reference in a new issue