mirror of https://github.com/borgbase/vorta
Merge ee8f805577
into 9cabbbd193
This commit is contained in:
commit
b8b5667157
|
@ -725,6 +725,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="preBackupScriptEditorButton">
|
||||
<property name="toolTip">
|
||||
<string> Open Pre-backup script editor</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -764,6 +778,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="postBackupScriptEditorButton">
|
||||
<property name="toolTip">
|
||||
<string> Open Post-backup script editor</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptEdit</class>
|
||||
<widget class="QDialog" name="ScriptEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>440</width>
|
||||
<height>260</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Script</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Pre/Post-Backup Script:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QTextEdit" name="scriptEdit">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor" stdset="0">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -15,7 +15,13 @@ from typing import Any, Callable, Iterable, List, Optional, Tuple, TypeVar
|
|||
import psutil
|
||||
from PyQt6 import QtCore
|
||||
from PyQt6.QtCore import QFileInfo, QThread, pyqtSignal
|
||||
from PyQt6.QtWidgets import QApplication, QFileDialog, QSystemTrayIcon
|
||||
from PyQt6.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QApplication,
|
||||
QFileDialog,
|
||||
QSystemTrayIcon,
|
||||
QTreeView,
|
||||
)
|
||||
|
||||
from vorta.borg._compatibility import BorgCompatibility
|
||||
from vorta.log import logger
|
||||
|
@ -166,12 +172,17 @@ def get_dict_from_list(dataDict, mapList):
|
|||
return reduce(lambda d, k: d.setdefault(k, {}), mapList, dataDict)
|
||||
|
||||
|
||||
def choose_file_dialog(parent, title, want_folder=True):
|
||||
def choose_file_dialog(parent, title, want_folder=True, file_filter=None, single_selection=False):
|
||||
dialog = QFileDialog(parent, title, os.path.expanduser('~'))
|
||||
dialog.setFileMode(QFileDialog.FileMode.Directory if want_folder else QFileDialog.FileMode.ExistingFiles)
|
||||
dialog.setParent(parent, QtCore.Qt.WindowType.Sheet)
|
||||
if want_folder:
|
||||
dialog.setOption(QFileDialog.Option.ShowDirsOnly)
|
||||
elif file_filter:
|
||||
dialog.setNameFilter(file_filter)
|
||||
if single_selection:
|
||||
tree_view = dialog.findChild(QTreeView)
|
||||
tree_view.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
return dialog
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from vorta.i18n import get_locale
|
|||
from vorta.scheduler import ScheduleStatusType
|
||||
from vorta.store.models import BackupProfileMixin, EventLogModel, WifiSettingModel
|
||||
from vorta.utils import get_asset, get_sorted_wifis
|
||||
from vorta.views.script_edit_dialog import ScriptEditWindow
|
||||
from vorta.views.utils import get_colored_icon
|
||||
|
||||
uifile = get_asset('UI/scheduletab.ui')
|
||||
|
@ -81,6 +82,8 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
|||
self.scheduleIntervalCount.valueChanged.connect(self.on_scheduler_change)
|
||||
self.scheduleIntervalUnit.currentIndexChanged.connect(self.on_scheduler_change)
|
||||
self.scheduleFixedTime.timeChanged.connect(self.on_scheduler_change)
|
||||
self.preBackupScriptEditorButton.clicked.connect(lambda: self.launch_script_editor(context="pre"))
|
||||
self.postBackupScriptEditorButton.clicked.connect(lambda: self.launch_script_editor(context="post"))
|
||||
|
||||
# Network and shell commands events
|
||||
self.meteredNetworksCheckBox.stateChanged.connect(
|
||||
|
@ -135,6 +138,8 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
|||
self.toolBox.setItemIcon(1, get_colored_icon('wifi'))
|
||||
self.toolBox.setItemIcon(2, get_colored_icon('tasks'))
|
||||
self.toolBox.setItemIcon(3, get_colored_icon('terminal'))
|
||||
self.preBackupScriptEditorButton.setIcon(get_colored_icon('edit'))
|
||||
self.postBackupScriptEditorButton.setIcon(get_colored_icon('edit'))
|
||||
|
||||
def populate_from_profile(self):
|
||||
"""Populate current view with data from selected profile."""
|
||||
|
@ -237,3 +242,8 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
|||
QTableWidgetItem(str(log_line.returncode)),
|
||||
)
|
||||
self.logTableWidget.setSortingEnabled(sorting) # restore sorting now that modifications are done
|
||||
|
||||
def launch_script_editor(self, context: str) -> None:
|
||||
edit_window = ScriptEditWindow(context, profile=self.profile())
|
||||
edit_window.exec()
|
||||
self.populate_from_profile() # Refresh the view after the script has been edited.
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
from PyQt6 import QtCore, uic
|
||||
from PyQt6.QtWidgets import QDialogButtonBox
|
||||
|
||||
from vorta.utils import get_asset
|
||||
|
||||
uifile = get_asset("UI/scriptedit.ui")
|
||||
ScriptEditUI, ScriptEditBase = uic.loadUiType(uifile)
|
||||
|
||||
|
||||
class ScriptEditWindow(ScriptEditUI, ScriptEditBase):
|
||||
def __init__(self, context: str, profile, parent=None) -> None:
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
|
||||
|
||||
self.context = context
|
||||
if context == "pre":
|
||||
self.setWindowTitle(self.tr("Edit Pre-Backup Script"))
|
||||
self.label.setText(self.tr("Pre-Backup Script:"))
|
||||
elif context == "post":
|
||||
self.setWindowTitle(self.tr("Edit Post-Backup Script"))
|
||||
self.label.setText(self.tr("Post-Backup Script:"))
|
||||
|
||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setText(self.tr("Save"))
|
||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(self.tr("Cancel"))
|
||||
|
||||
self.profile = profile
|
||||
|
||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Save).clicked.connect(self.save_script)
|
||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).clicked.connect(self.close)
|
||||
|
||||
# Populate data from profile
|
||||
self.populate_from_profile()
|
||||
|
||||
def populate_from_profile(self):
|
||||
"""Populate the script editor with the current profile's script."""
|
||||
profile = self.profile
|
||||
if self.context == "pre":
|
||||
self.scriptEdit.setPlainText(profile.pre_backup_cmd)
|
||||
elif self.context == "post":
|
||||
self.scriptEdit.setPlainText(profile.post_backup_cmd)
|
||||
|
||||
def save_profile_attr(self, attr, new_value):
|
||||
profile = self.profile
|
||||
setattr(profile, attr, new_value)
|
||||
profile.save()
|
||||
|
||||
def save_script(self):
|
||||
script = self.scriptEdit.toPlainText()
|
||||
profile = self.profile
|
||||
if self.context == "pre":
|
||||
self.save_profile_attr("pre_backup_cmd", script)
|
||||
elif self.context == "post":
|
||||
self.save_profile_attr("post_backup_cmd", script)
|
||||
profile.save()
|
||||
self.close()
|
Loading…
Reference in New Issue