From d0a996c1ca08d75b76b9492b8f3734047990249d Mon Sep 17 00:00:00 2001
From: Shivansh Singh <89853707+shivansh02@users.noreply.github.com>
Date: Fri, 19 Jul 2024 19:51:58 +0530
Subject: [PATCH] Schedule tab refactoring. By @shivansh02 (#2035)
---
src/vorta/assets/UI/logpage.ui | 75 ++
src/vorta/assets/UI/networkspage.ui | 62 ++
src/vorta/assets/UI/schedulepage.ui | 597 ++++++++++++++++
src/vorta/assets/UI/scheduletab.ui | 862 +----------------------
src/vorta/assets/UI/shellcommandspage.ui | 191 +++++
src/vorta/views/log_page.py | 59 ++
src/vorta/views/main_window.py | 14 +-
src/vorta/views/networks_page.py | 60 ++
src/vorta/views/schedule_page.py | 137 ++++
src/vorta/views/schedule_tab.py | 258 +------
src/vorta/views/shell_commands_page.py | 45 ++
tests/integration/test_repo.py | 2 +-
tests/unit/test_repo.py | 2 +-
tests/unit/test_schedule.py | 2 +-
14 files changed, 1276 insertions(+), 1090 deletions(-)
create mode 100644 src/vorta/assets/UI/logpage.ui
create mode 100644 src/vorta/assets/UI/networkspage.ui
create mode 100644 src/vorta/assets/UI/schedulepage.ui
create mode 100644 src/vorta/assets/UI/shellcommandspage.ui
create mode 100644 src/vorta/views/log_page.py
create mode 100644 src/vorta/views/networks_page.py
create mode 100644 src/vorta/views/schedule_page.py
create mode 100644 src/vorta/views/shell_commands_page.py
diff --git a/src/vorta/assets/UI/logpage.ui b/src/vorta/assets/UI/logpage.ui
new file mode 100644
index 00000000..f1690ce3
--- /dev/null
+++ b/src/vorta/assets/UI/logpage.ui
@@ -0,0 +1,75 @@
+
+
+ LogPage
+
+
+
+ 0
+ 0
+ 687
+ 384
+
+
+
+ -
+
+
+
+ 11
+ false
+
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Time
+
+
+
+
+ Category
+
+
+
+
+ Subcommand
+
+
+
+
+ Repository
+
+
+
+
+ Returncode
+
+
+
+
+ -
+
+
+ <html><head/><body><p><a href="file:///"><span style=" text-decoration: underline; color:#0984e3;">View the logs</span></a></p></body></html>
+
+
+ 0
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/src/vorta/assets/UI/networkspage.ui b/src/vorta/assets/UI/networkspage.ui
new file mode 100644
index 00000000..088b6dc6
--- /dev/null
+++ b/src/vorta/assets/UI/networkspage.ui
@@ -0,0 +1,62 @@
+
+
+ NetworksPage
+
+
+
+ 0
+ 0
+ 687
+ 384
+
+
+
+ Networks
+
+
+
+ 12
+
+ -
+
+
+ 4
+
+
-
+
+
+ true
+
+
+ Allowed Networks:
+
+
+
+ -
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+ -
+
+
+ Run backups over metered networks
+
+
+ false
+
+
+
+
+
+
+
+
+
diff --git a/src/vorta/assets/UI/schedulepage.ui b/src/vorta/assets/UI/schedulepage.ui
new file mode 100644
index 00000000..cd334313
--- /dev/null
+++ b/src/vorta/assets/UI/schedulepage.ui
@@ -0,0 +1,597 @@
+
+
+ SchedulePage
+
+
+
+ 0
+ 0
+ 687
+ 384
+
+
+
+
+ false
+
+
+
+ Schedule
+
+
+
+ 6
+
+
+ 6
+
+ -
+
+
-
+
+
+ Qt::AlignHCenter|Qt::AlignTop
+
+
+ 8
+
+
+ 4
+
+
-
+
+
+ Backup schedule:
+
+
+
+ -
+
+
+ Manual only
+
+
+
+ -
+
+
+ 4
+
+
+ QLayout::SetMinimumSize
+
+
-
+
+
+ Backup periodically
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+ Interval:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 4
+ 1
+
+
+
+
+ -
+
+
+ 1
+
+
+ 740
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+ 4
+
+
-
+
+
+ Backup daily
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+ Time:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 4
+ 1
+
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 1
+ 4
+
+
+
+
+ -
+
+
+ Missed backups:
+
+
+
+ -
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Run missed backups on startup or wakeup
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 1
+ 4
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Autopruning:
+
+
+
+ -
+
+
+ Prune after each backup
+
+
+
+ -
+
+
+ Validation:
+
+
+
+ -
+
+
+ 4
+
+
+ 4
+
+
-
+
+
+ Validate repository data
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+ Interval:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 4
+ 1
+
+
+
+
+ -
+
+
+ 1
+
+
+ 52
+
+
+ 3
+
+
+
+ -
+
+
+ weeks
+
+
+
+
+
+
+
+
+ -
+
+
+ Compaction:
+
+
+
+ -
+
+
+ 4
+
+
+ 4
+
+
-
+
+
+ Compact repository
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+ Interval:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 4
+ 1
+
+
+
+
+ -
+
+
+ 1
+
+
+ 52
+
+
+ 3
+
+
+
+ -
+
+
+ weeks
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 1
+ 4
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+
+ true
+
+
+
+ Next Backup:
+
+
+
+ -
+
+
+ None scheduled
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/vorta/assets/UI/scheduletab.ui b/src/vorta/assets/UI/scheduletab.ui
index 062c0771..3f497572 100644
--- a/src/vorta/assets/UI/scheduletab.ui
+++ b/src/vorta/assets/UI/scheduletab.ui
@@ -33,7 +33,7 @@
false
-
+
0
@@ -42,588 +42,12 @@
384
-
-
- false
-
-
Schedule
-
-
- 6
-
-
- 6
-
- -
-
-
-
-
-
- Qt::AlignHCenter|Qt::AlignTop
-
-
- 8
-
-
- 4
-
-
-
-
-
- Backup schedule:
-
-
-
- -
-
-
- Manual only
-
-
-
- -
-
-
- 4
-
-
- QLayout::SetMinimumSize
-
-
-
-
-
- Backup periodically
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 4
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Interval:
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 4
- 1
-
-
-
-
- -
-
-
- 1
-
-
- 740
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
- 4
-
-
-
-
-
- Backup daily
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 4
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Time:
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 4
- 1
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 1
- 4
-
-
-
-
- -
-
-
- Missed backups:
-
-
-
- -
-
-
-
- 16777215
- 16777215
-
-
-
- Run missed backups on startup or wakeup
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 1
- 4
-
-
-
-
-
-
- -
-
-
-
-
-
- Autopruning:
-
-
-
- -
-
-
- Prune after each backup
-
-
-
- -
-
-
- Validation:
-
-
-
- -
-
-
- 4
-
-
- 4
-
-
-
-
-
- Validate repository data
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 4
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Interval:
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 4
- 1
-
-
-
-
- -
-
-
- 1
-
-
- 52
-
-
- 3
-
-
-
- -
-
-
- weeks
-
-
-
-
-
-
-
-
- -
-
-
- Compaction:
-
-
-
- -
-
-
- 4
-
-
- 4
-
-
-
-
-
- Compact repository
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 4
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Interval:
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 4
- 1
-
-
-
-
- -
-
-
- 1
-
-
- 52
-
-
- 3
-
-
-
- -
-
-
- weeks
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 1
- 4
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
-
-
-
- true
-
-
-
- Next Backup:
-
-
-
- -
-
-
- None scheduled
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
+
-
+
@@ -636,49 +60,9 @@
Networks
-
-
- 12
-
- -
-
-
- 4
-
-
-
-
-
- true
-
-
- Allowed Networks:
-
-
-
- -
-
-
-
- 0
- 1
-
-
-
-
-
-
- -
-
-
- Run backups over metered networks
-
-
- false
-
-
-
+
-
+
@@ -691,67 +75,10 @@
Log
-
- -
-
-
-
- 11
- false
-
-
-
- false
-
-
- true
-
-
- false
-
-
-
- Time
-
-
-
-
- Category
-
-
-
-
- Subcommand
-
-
-
-
- Repository
-
-
-
-
- Returncode
-
-
-
-
- -
-
-
- <html><head/><body><p><a href="file:///"><span style=" text-decoration: underline; color:#0984e3;">View the logs</span></a></p></body></html>
-
-
- 0
-
-
- true
-
-
-
+
-
-
+
+
0
@@ -763,178 +90,9 @@
Shell Commands
-
-
- 12
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- <html><head/><body><p>Run custom shell commands before and after each backup. The actual backup and post-backup command will only run, if the pre-backup command exits without error (return code 0). Available variables: <span style=" font-family:'Courier';">$repo_url, $profile_name, $profile_slug, $returncode</span></p></body></html>
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
-
-
- true
-
-
-
- -
-
-
- 0
-
-
-
-
-
-
- 100
- 0
-
-
-
- Pre-backup:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
- font-family:'Courier';
-
-
-
-
-
- echo "Before backup of $repo_url"
-
-
-
-
-
- -
-
-
- 0
-
-
-
-
-
-
- 100
- 0
-
-
-
- Post-backup:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font-family:'Courier';
-
-
- echo "Backup of $repo_url ended with $returncode."
-
-
-
-
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- <html><head/><body><p>Extra arguments for <span style=" font-style:italic;">borg create</span>. Possible options are listed in the <a href="https://borgbackup.readthedocs.io/en/stable/usage/create.html"><span style=" text-decoration: underline; color:#0984e3;">the borg documentation</span></a>.</p></body></html>
-
-
- true
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font-family:'Courier';
-
-
- --dry-run --noflags
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 0
- 0
-
-
-
-
+
-
+
diff --git a/src/vorta/assets/UI/shellcommandspage.ui b/src/vorta/assets/UI/shellcommandspage.ui
new file mode 100644
index 00000000..32651c75
--- /dev/null
+++ b/src/vorta/assets/UI/shellcommandspage.ui
@@ -0,0 +1,191 @@
+
+
+ ShellCommandsPage
+
+
+
+ 0
+ 0
+ 687
+ 384
+
+
+
+ Shell Commands
+
+
+
+ 12
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ <html><head/><body><p>Run custom shell commands before and after each backup. The actual backup and post-backup command will only run, if the pre-backup command exits without error (return code 0). Available variables: <span style=" font-family:'Courier';">$repo_url, $profile_name, $profile_slug, $returncode</span></p></body></html>
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+ true
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+ Pre-backup:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ font-family:'Courier';
+
+
+
+
+
+ echo "Before backup of $repo_url"
+
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+ Post-backup:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font-family:'Courier';
+
+
+ echo "Backup of $repo_url ended with $returncode."
+
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ <html><head/><body><p>Extra arguments for <span style=" font-style:italic;">borg create</span>. Possible options are listed in the <a href="https://borgbackup.readthedocs.io/en/stable/usage/create.html"><span style=" text-decoration: underline; color:#0984e3;">the borg documentation</span></a>.</p></body></html>
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ font-family:'Courier';
+
+
+ --dry-run --noflags
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
diff --git a/src/vorta/views/log_page.py b/src/vorta/views/log_page.py
new file mode 100644
index 00000000..d2b2377d
--- /dev/null
+++ b/src/vorta/views/log_page.py
@@ -0,0 +1,59 @@
+from PyQt6 import uic
+from PyQt6.QtWidgets import (
+ QAbstractItemView,
+ QHeaderView,
+ QTableWidgetItem,
+)
+
+from vorta import config
+from vorta.store.models import EventLogModel
+from vorta.utils import get_asset
+
+uifile = get_asset('UI/logpage.ui')
+LogTableUI, LogTableBase = uic.loadUiType(uifile)
+
+
+class LogTableColumn:
+ Time = 0
+ Category = 1
+ Subcommand = 2
+ Repository = 3
+ ReturnCode = 4
+
+
+class LogPage(LogTableBase, LogTableUI):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setupUi(self)
+ self.init_ui()
+
+ def init_ui(self):
+ self.logPage.setAlternatingRowColors(True)
+ header = self.logPage.horizontalHeader()
+ header.setVisible(True)
+ [header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents) for i in range(5)]
+ header.setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
+ self.logPage.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
+ self.logPage.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
+
+ self.logLink.setText(
+ f'Click here for complete logs.'
+ )
+
+ self.populate_logs()
+
+ def populate_logs(self):
+ event_logs = [s for s in EventLogModel.select().order_by(EventLogModel.start_time.desc())]
+
+ sorting = self.logPage.isSortingEnabled()
+ self.logPage.setSortingEnabled(False)
+ self.logPage.setRowCount(len(event_logs))
+ for row, log_line in enumerate(event_logs):
+ formatted_time = log_line.start_time.strftime('%Y-%m-%d %H:%M')
+ self.logPage.setItem(row, LogTableColumn.Time, QTableWidgetItem(formatted_time))
+ self.logPage.setItem(row, LogTableColumn.Category, QTableWidgetItem(log_line.category))
+ self.logPage.setItem(row, LogTableColumn.Subcommand, QTableWidgetItem(log_line.subcommand))
+ self.logPage.setItem(row, LogTableColumn.Repository, QTableWidgetItem(log_line.repo_url))
+ self.logPage.setItem(row, LogTableColumn.ReturnCode, QTableWidgetItem(str(log_line.returncode)))
+ self.logPage.setSortingEnabled(sorting)
diff --git a/src/vorta/views/main_window.py b/src/vorta/views/main_window.py
index f42e04c4..e7b59041 100644
--- a/src/vorta/views/main_window.py
+++ b/src/vorta/views/main_window.py
@@ -80,7 +80,7 @@ def __init__(self, parent=None):
self.tabWidget.setCurrentIndex(0)
self.repoTab.repo_changed.connect(self.archiveTab.populate_from_profile)
- self.repoTab.repo_changed.connect(self.scheduleTab.populate_from_profile)
+ self.repoTab.repo_changed.connect(self.scheduleTab.schedulePage.populate_from_profile)
self.repoTab.repo_added.connect(self.archiveTab.refresh_archive_list)
self.miscTab.refresh_archive.connect(self.archiveTab.populate_from_profile)
@@ -110,8 +110,8 @@ def __init__(self, parent=None):
# OS-specific startup options:
if not get_network_status_monitor().is_network_status_available():
# Hide Wifi-rule section in schedule tab.
- self.scheduleTab.wifiListLabel.hide()
- self.scheduleTab.wifiListWidget.hide()
+ self.scheduleTab.networksPage.wifiListLabel.hide()
+ self.scheduleTab.networksPage.wifiListWidget.hide()
self.scheduleTab.page_2.hide()
self.scheduleTab.toolBox.removeItem(1)
@@ -185,7 +185,7 @@ def profile_selection_changed_action(self, index):
self.archiveTab.populate_from_profile()
self.repoTab.populate_from_profile()
self.sourceTab.populate_from_profile()
- self.scheduleTab.populate_from_profile()
+ self.scheduleTab.schedulePage.populate_from_profile()
SettingsModel.update({SettingsModel.str_value: self.current_profile.id}).where(
SettingsModel.key == 'previous_profile_id'
).execute()
@@ -260,8 +260,8 @@ def profile_imported_event(profile):
self.tr('Profile {} imported.').format(profile.name),
)
self.repoTab.populate_from_profile()
- self.scheduleTab.populate_logs()
- self.scheduleTab.populate_wifi()
+ self.scheduleTab.logPage.populate_logs()
+ self.scheduleTab.networksPage.populate_wifi()
self.miscTab.populate()
self.populate_profile_selector()
@@ -323,7 +323,7 @@ def backup_started_event(self):
def backup_finished_event(self):
self.archiveTab.populate_from_profile()
self.repoTab.init_repo_stats()
- self.scheduleTab.populate_logs()
+ self.scheduleTab.logPage.populate_logs()
if not self.app.jobs_manager.is_worker_running() and (
self.archiveTab.remaining_refresh_archives == 0 or self.archiveTab.remaining_refresh_archives == 1
diff --git a/src/vorta/views/networks_page.py b/src/vorta/views/networks_page.py
new file mode 100644
index 00000000..8ecec3e8
--- /dev/null
+++ b/src/vorta/views/networks_page.py
@@ -0,0 +1,60 @@
+from PyQt6 import uic
+from PyQt6.QtCore import Qt
+from PyQt6.QtWidgets import QCheckBox, QLabel, QListWidget, QListWidgetItem
+
+from vorta.store.models import BackupProfileMixin, WifiSettingModel
+from vorta.utils import get_asset, get_sorted_wifis
+
+uifile = get_asset('UI/networkspage.ui')
+NetworksUI, NetworksBase = uic.loadUiType(uifile)
+
+
+class NetworksPage(NetworksBase, NetworksUI, BackupProfileMixin):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setupUi(self)
+
+ self.wifiListLabel: QLabel = self.findChild(QLabel, 'wifiListLabel')
+ self.meteredNetworksCheckBox: QCheckBox = self.findChild(QCheckBox, 'meteredNetworksCheckBox')
+ self.wifiListWidget: QListWidget = self.findChild(QListWidget, 'wifiListWidget')
+
+ self.populate_wifi()
+ self.setup_connections()
+
+ def setup_connections(self):
+ self.meteredNetworksCheckBox.stateChanged.connect(self.on_metered_networks_state_changed)
+ self.wifiListWidget.itemChanged.connect(self.save_wifi_item)
+
+ def on_metered_networks_state_changed(self, state):
+ profile = self.profile()
+ attr = 'dont_run_on_metered_networks'
+ new_value = state != Qt.CheckState.Checked
+ self.save_profile_attr(attr, new_value)
+ self.meteredNetworksCheckBox.setChecked(False if profile.dont_run_on_metered_networks else True)
+
+ def populate_wifi(self):
+ self.wifiListWidget.clear()
+ profile = self.profile()
+ if profile:
+ for wifi in get_sorted_wifis(profile):
+ item = QListWidgetItem()
+ item.setText(wifi.ssid)
+ item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
+ if wifi.allowed:
+ item.setCheckState(Qt.CheckState.Checked)
+ else:
+ item.setCheckState(Qt.CheckState.Unchecked)
+ self.wifiListWidget.addItem(item)
+
+ def save_wifi_item(self, item):
+ profile = self.profile()
+ if profile:
+ db_item = WifiSettingModel.get(ssid=item.text(), profile=profile.id)
+ db_item.allowed = item.checkState() == Qt.CheckState.Checked
+ db_item.save()
+
+ def save_profile_attr(self, attr, new_value):
+ profile = self.profile()
+ if profile:
+ setattr(profile, attr, new_value)
+ profile.save()
diff --git a/src/vorta/views/schedule_page.py b/src/vorta/views/schedule_page.py
new file mode 100644
index 00000000..5d875ee8
--- /dev/null
+++ b/src/vorta/views/schedule_page.py
@@ -0,0 +1,137 @@
+from PyQt6 import QtCore, uic
+from PyQt6.QtCore import QDateTime, QLocale
+from PyQt6.QtWidgets import QApplication
+
+from vorta.i18n import get_locale
+from vorta.scheduler import ScheduleStatusType
+from vorta.store.models import BackupProfileMixin
+from vorta.utils import get_asset
+
+uifile = get_asset('UI/schedulepage.ui')
+SchedulePageUI, SchedulePageBase = uic.loadUiType(uifile)
+
+
+class SchedulePage(SchedulePageBase, SchedulePageUI, BackupProfileMixin):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.app = QApplication.instance()
+ self.setupUi(self)
+
+ self.schedulerRadioMapping = {
+ 'off': self.scheduleOffRadio,
+ 'interval': self.scheduleIntervalRadio,
+ 'fixed': self.scheduleFixedRadio,
+ }
+
+ self.populate_from_profile()
+
+ self.scheduleIntervalUnit.addItem(self.tr('Minutes'), 'minutes')
+ self.scheduleIntervalUnit.addItem(self.tr('Hours'), 'hours')
+ self.scheduleIntervalUnit.addItem(self.tr('Days'), 'days')
+ self.scheduleIntervalUnit.addItem(self.tr('Weeks'), 'weeks')
+
+ self.framePeriodic.setEnabled(False)
+ self.frameDaily.setEnabled(False)
+ self.frameValidation.setEnabled(False)
+ self.frameCompaction.setEnabled(False)
+
+ self.scheduleIntervalRadio.toggled.connect(self.framePeriodic.setEnabled)
+ self.scheduleFixedRadio.toggled.connect(self.frameDaily.setEnabled)
+ self.validationCheckBox.toggled.connect(self.frameValidation.setEnabled)
+ self.compactionCheckBox.toggled.connect(self.frameCompaction.setEnabled)
+
+ for label, obj in self.schedulerRadioMapping.items():
+ obj.clicked.connect(self.on_scheduler_change)
+ 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.missedBackupsCheckBox.stateChanged.connect(
+ lambda new_val, attr='schedule_make_up_missed': self.save_profile_attr(attr, new_val)
+ )
+ self.pruneCheckBox.stateChanged.connect(lambda new_val, attr='prune_on': self.save_profile_attr(attr, new_val))
+ self.validationCheckBox.stateChanged.connect(
+ lambda new_val, attr='validation_on': self.save_profile_attr(attr, new_val)
+ )
+ self.validationWeeksCount.valueChanged.connect(
+ lambda new_val, attr='validation_weeks': self.save_profile_attr(attr, new_val)
+ )
+ self.compactionCheckBox.stateChanged.connect(
+ lambda new_val, attr='compaction_on': self.save_profile_attr(attr, new_val)
+ )
+ self.compactionWeeksCount.valueChanged.connect(
+ lambda new_val, attr='compaction_weeks': self.save_profile_attr(attr, new_val)
+ )
+
+ self.app.scheduler.schedule_changed.connect(lambda pid: self.draw_next_scheduled_backup())
+
+ self.app.paletteChanged.connect(lambda p: self.set_icons())
+
+ def on_scheduler_change(self, _):
+ profile = self.profile()
+ for label, obj in self.schedulerRadioMapping.items():
+ if obj.isChecked():
+ profile.schedule_mode = label
+ profile.schedule_interval_unit = self.scheduleIntervalUnit.currentData()
+ profile.schedule_interval_count = self.scheduleIntervalCount.value()
+ qtime = self.scheduleFixedTime.time()
+ profile.schedule_fixed_hour, profile.schedule_fixed_minute = (
+ qtime.hour(),
+ qtime.minute(),
+ )
+ profile.save()
+
+ self.app.scheduler.set_timer_for_profile(profile.id)
+ self.draw_next_scheduled_backup()
+
+ def populate_from_profile(self):
+ profile = self.profile()
+ self.schedulerRadioMapping[profile.schedule_mode].setChecked(True)
+ self.scheduleIntervalUnit.setCurrentIndex(self.scheduleIntervalUnit.findData(profile.schedule_interval_unit))
+ self.scheduleIntervalCount.setValue(profile.schedule_interval_count)
+ self.scheduleFixedTime.setTime(QtCore.QTime(profile.schedule_fixed_hour, profile.schedule_fixed_minute))
+
+ self.validationCheckBox.setCheckState(
+ QtCore.Qt.CheckState.Checked if profile.validation_on else QtCore.Qt.CheckState.Unchecked
+ )
+ self.validationWeeksCount.setValue(profile.validation_weeks)
+
+ self.compactionCheckBox.setCheckState(
+ QtCore.Qt.CheckState.Checked if profile.compaction_on else QtCore.Qt.CheckState.Unchecked
+ )
+ self.compactionWeeksCount.setValue(profile.compaction_weeks)
+
+ self.pruneCheckBox.setCheckState(
+ QtCore.Qt.CheckState.Checked if profile.prune_on else QtCore.Qt.CheckState.Unchecked
+ )
+ self.missedBackupsCheckBox.setCheckState(
+ QtCore.Qt.CheckState.Checked if profile.schedule_make_up_missed else QtCore.Qt.CheckState.Unchecked
+ )
+
+ self.draw_next_scheduled_backup()
+
+ def draw_next_scheduled_backup(self):
+ status = self.app.scheduler.next_job_for_profile(self.profile().id)
+ if status.type in (
+ ScheduleStatusType.SCHEDULED,
+ ScheduleStatusType.TOO_FAR_AHEAD,
+ ):
+ time = QDateTime.fromMSecsSinceEpoch(int(status.time.timestamp() * 1000))
+ text = get_locale().toString(time, QLocale.FormatType.LongFormat)
+ elif status.type == ScheduleStatusType.NO_PREVIOUS_BACKUP:
+ text = self.tr('Run a manual backup first')
+ else:
+ text = self.tr('None scheduled')
+
+ self.nextBackupDateTimeLabel.setText(text)
+ self.nextBackupDateTimeLabel.repaint()
+
+ def save_profile_attr(self, attr, new_value):
+ profile = self.profile()
+ setattr(profile, attr, new_value)
+ profile.save()
+
+ def save_repo_attr(self, attr, new_value):
+ repo = self.profile().repo
+ setattr(repo, attr, new_value)
+ repo.save()
diff --git a/src/vorta/views/schedule_tab.py b/src/vorta/views/schedule_tab.py
index 2eba60fc..3477a9c4 100644
--- a/src/vorta/views/schedule_tab.py
+++ b/src/vorta/views/schedule_tab.py
@@ -1,253 +1,55 @@
-from PyQt6 import QtCore, uic
-from PyQt6.QtCore import QDateTime, QLocale, Qt
-from PyQt6.QtWidgets import (
- QAbstractItemView,
- QApplication,
- QHeaderView,
- QListWidgetItem,
- QTableWidgetItem,
-)
+from PyQt6 import uic
+from PyQt6.QtWidgets import QApplication
-from vorta import application, config
-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 import application
+from vorta.store.models import BackupProfileMixin
+from vorta.utils import get_asset
+from vorta.views.log_page import LogPage
+from vorta.views.networks_page import NetworksPage
+from vorta.views.schedule_page import SchedulePage
+from vorta.views.shell_commands_page import ShellCommandsPage
from vorta.views.utils import get_colored_icon
uifile = get_asset('UI/scheduletab.ui')
ScheduleUI, ScheduleBase = uic.loadUiType(uifile)
-class LogTableColumn:
- Time = 0
- Category = 1
- Subcommand = 2
- Repository = 3
- ReturnCode = 4
-
-
class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(parent)
self.app: application.VortaApp = QApplication.instance()
self.toolBox.setCurrentIndex(0)
-
- self.schedulerRadioMapping = {
- 'off': self.scheduleOffRadio,
- 'interval': self.scheduleIntervalRadio,
- 'fixed': self.scheduleFixedRadio,
- }
-
- # Set up log table
- self.logTableWidget.setAlternatingRowColors(True)
- header = self.logTableWidget.horizontalHeader()
- self.logLink.setText(
- f'Click here for complete logs.'
- )
- header.setVisible(True)
- [header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents) for i in range(5)]
- header.setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
- self.logTableWidget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
- self.logTableWidget.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
-
- # Scheduler intervals we know
- self.scheduleIntervalUnit.addItem(self.tr('Minutes'), 'minutes')
- self.scheduleIntervalUnit.addItem(self.tr('Hours'), 'hours')
- self.scheduleIntervalUnit.addItem(self.tr('Days'), 'days')
- self.scheduleIntervalUnit.addItem(self.tr('Weeks'), 'weeks')
-
- # Enable/Disable entries on button state changed
- self.framePeriodic.setEnabled(False)
- self.frameDaily.setEnabled(False)
- self.frameValidation.setEnabled(False)
- self.frameCompaction.setEnabled(False)
-
- self.scheduleIntervalRadio.toggled.connect(self.framePeriodic.setEnabled)
- self.scheduleFixedRadio.toggled.connect(self.frameDaily.setEnabled)
- self.validationCheckBox.toggled.connect(self.frameValidation.setEnabled)
- self.compactionCheckBox.toggled.connect(self.frameCompaction.setEnabled)
-
- # POPULATE with data
- self.populate_from_profile()
self.set_icons()
+ self.init_log_page()
+ self.init_shell_commands_page()
+ self.init_networks_page()
+ self.init_schedule_page()
- # Connect events
- self.app.backup_finished_event.connect(self.populate_logs)
+ self.app.backup_finished_event.connect(self.logPage.populate_logs)
- # Scheduler events
- for label, obj in self.schedulerRadioMapping.items():
- obj.clicked.connect(self.on_scheduler_change)
- self.scheduleIntervalCount.valueChanged.connect(self.on_scheduler_change)
- self.scheduleIntervalUnit.currentIndexChanged.connect(self.on_scheduler_change)
- self.scheduleFixedTime.timeChanged.connect(self.on_scheduler_change)
+ def init_log_page(self):
+ self.logPage = LogPage(self)
+ self.logLayout.addWidget(self.logPage)
+ self.logPage.show()
- # Network and shell commands events
- self.meteredNetworksCheckBox.stateChanged.connect(
- lambda new_val, attr='dont_run_on_metered_networks': self.save_profile_attr(attr, not new_val)
- )
- self.postBackupCmdLineEdit.textEdited.connect(
- lambda new_val, attr='post_backup_cmd': self.save_profile_attr(attr, new_val)
- )
- self.preBackupCmdLineEdit.textEdited.connect(
- lambda new_val, attr='pre_backup_cmd': self.save_profile_attr(attr, new_val)
- )
- self.createCmdLineEdit.textEdited.connect(
- lambda new_val, attr='create_backup_cmd': self.save_repo_attr(attr, new_val)
- )
- self.missedBackupsCheckBox.stateChanged.connect(
- lambda new_val, attr='schedule_make_up_missed': self.save_profile_attr(attr, new_val)
- )
- self.pruneCheckBox.stateChanged.connect(lambda new_val, attr='prune_on': self.save_profile_attr(attr, new_val))
- self.validationCheckBox.stateChanged.connect(
- lambda new_val, attr='validation_on': self.save_profile_attr(attr, new_val)
- )
- self.validationWeeksCount.valueChanged.connect(
- lambda new_val, attr='validation_weeks': self.save_profile_attr(attr, new_val)
- )
- self.compactionCheckBox.stateChanged.connect(
- lambda new_val, attr='compaction_on': self.save_profile_attr(attr, new_val)
- )
- self.compactionWeeksCount.valueChanged.connect(
- lambda new_val, attr='compaction_weeks': self.save_profile_attr(attr, new_val)
- )
+ def init_shell_commands_page(self):
+ self.shellCommandsPage = ShellCommandsPage(self)
+ self.shellCommandsLayout.addWidget(self.shellCommandsPage)
+ self.shellCommandsPage.show()
- # Connect to schedule update
- self.app.scheduler.schedule_changed.connect(lambda pid: self.draw_next_scheduled_backup())
+ def init_networks_page(self):
+ self.networksPage = NetworksPage(self)
+ self.networksLayout.addWidget(self.networksPage)
+ self.networksPage.show()
- # Connect to palette change
- self.app.paletteChanged.connect(lambda p: self.set_icons())
-
- def on_scheduler_change(self, _):
- profile = self.profile()
- # Save scheduler settings, apply new scheduler and display next task for profile.
- for label, obj in self.schedulerRadioMapping.items():
- if obj.isChecked():
- profile.schedule_mode = label
- profile.schedule_interval_unit = self.scheduleIntervalUnit.currentData()
- profile.schedule_interval_count = self.scheduleIntervalCount.value()
- qtime = self.scheduleFixedTime.time()
- profile.schedule_fixed_hour, profile.schedule_fixed_minute = (
- qtime.hour(),
- qtime.minute(),
- )
- profile.save()
-
- self.app.scheduler.set_timer_for_profile(profile.id)
- self.draw_next_scheduled_backup()
+ def init_schedule_page(self):
+ self.schedulePage = SchedulePage(self)
+ self.scheduleLayout.addWidget(self.schedulePage)
+ self.schedulePage.show()
def set_icons(self):
self.toolBox.setItemIcon(0, get_colored_icon('clock-o'))
self.toolBox.setItemIcon(1, get_colored_icon('wifi'))
self.toolBox.setItemIcon(2, get_colored_icon('tasks'))
self.toolBox.setItemIcon(3, get_colored_icon('terminal'))
-
- def populate_from_profile(self):
- """Populate current view with data from selected profile."""
- profile = self.profile()
- self.schedulerRadioMapping[profile.schedule_mode].setChecked(True)
-
- # Set interval scheduler options
- self.scheduleIntervalUnit.setCurrentIndex(self.scheduleIntervalUnit.findData(profile.schedule_interval_unit))
- self.scheduleIntervalCount.setValue(profile.schedule_interval_count)
-
- # Set fixed daily time scheduler options
- self.scheduleFixedTime.setTime(QtCore.QTime(profile.schedule_fixed_hour, profile.schedule_fixed_minute))
-
- # Set borg-check options
- self.validationCheckBox.setCheckState(
- QtCore.Qt.CheckState.Checked if profile.validation_on else QtCore.Qt.CheckState.Unchecked
- )
- self.validationWeeksCount.setValue(profile.validation_weeks)
-
- # set borg compact options
- self.compactionCheckBox.setCheckState(
- QtCore.Qt.CheckState.Checked if profile.compaction_on else QtCore.Qt.CheckState.Unchecked
- )
- self.compactionWeeksCount.setValue(profile.compaction_weeks)
-
- # Other checkbox options
- self.pruneCheckBox.setCheckState(
- QtCore.Qt.CheckState.Checked if profile.prune_on else QtCore.Qt.CheckState.Unchecked
- )
- self.missedBackupsCheckBox.setCheckState(
- QtCore.Qt.CheckState.Checked if profile.schedule_make_up_missed else QtCore.Qt.CheckState.Unchecked
- )
- self.meteredNetworksCheckBox.setChecked(False if profile.dont_run_on_metered_networks else True)
-
- self.preBackupCmdLineEdit.setText(profile.pre_backup_cmd)
- self.postBackupCmdLineEdit.setText(profile.post_backup_cmd)
- if profile.repo:
- self.createCmdLineEdit.setText(profile.repo.create_backup_cmd)
- self.createCmdLineEdit.setEnabled(True)
- else:
- self.createCmdLineEdit.setEnabled(False)
-
- self.populate_wifi()
- self.populate_logs()
- self.draw_next_scheduled_backup()
-
- def draw_next_scheduled_backup(self):
- status = self.app.scheduler.next_job_for_profile(self.profile().id)
- if status.type in (
- ScheduleStatusType.SCHEDULED,
- ScheduleStatusType.TOO_FAR_AHEAD,
- ):
- time = QDateTime.fromMSecsSinceEpoch(int(status.time.timestamp() * 1000))
- text = get_locale().toString(time, QLocale.FormatType.LongFormat)
- elif status.type == ScheduleStatusType.NO_PREVIOUS_BACKUP:
- text = self.tr('Run a manual backup first')
- else:
- text = self.tr('None scheduled')
-
- self.nextBackupDateTimeLabel.setText(text)
- self.nextBackupDateTimeLabel.repaint()
-
- def populate_wifi(self):
- self.wifiListWidget.clear()
- for wifi in get_sorted_wifis(self.profile()):
- item = QListWidgetItem()
- item.setText(wifi.ssid)
- item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
- if wifi.allowed:
- item.setCheckState(QtCore.Qt.CheckState.Checked)
- else:
- item.setCheckState(QtCore.Qt.CheckState.Unchecked)
- self.wifiListWidget.addItem(item)
- self.wifiListWidget.itemChanged.connect(self.save_wifi_item)
-
- def save_wifi_item(self, item):
- db_item = WifiSettingModel.get(ssid=item.text(), profile=self.profile().id)
- db_item.allowed = item.checkState() == Qt.CheckState.Checked
- db_item.save()
-
- def save_profile_attr(self, attr, new_value):
- profile = self.profile()
- setattr(profile, attr, new_value)
- profile.save()
-
- def save_repo_attr(self, attr, new_value):
- repo = self.profile().repo
- setattr(repo, attr, new_value)
- repo.save()
-
- def populate_logs(self):
- event_logs = [s for s in EventLogModel.select().order_by(EventLogModel.start_time.desc())]
-
- sorting = self.logTableWidget.isSortingEnabled()
- self.logTableWidget.setSortingEnabled(False) # disable sorting while modifying the table.
- self.logTableWidget.setRowCount(len(event_logs)) # go ahead and set table length and then update the rows
- for row, log_line in enumerate(event_logs):
- formatted_time = log_line.start_time.strftime('%Y-%m-%d %H:%M')
- self.logTableWidget.setItem(row, LogTableColumn.Time, QTableWidgetItem(formatted_time))
- self.logTableWidget.setItem(row, LogTableColumn.Category, QTableWidgetItem(log_line.category))
- self.logTableWidget.setItem(row, LogTableColumn.Subcommand, QTableWidgetItem(log_line.subcommand))
- self.logTableWidget.setItem(row, LogTableColumn.Repository, QTableWidgetItem(log_line.repo_url))
- self.logTableWidget.setItem(
- row,
- LogTableColumn.ReturnCode,
- QTableWidgetItem(str(log_line.returncode)),
- )
- self.logTableWidget.setSortingEnabled(sorting) # restore sorting now that modifications are done
diff --git a/src/vorta/views/shell_commands_page.py b/src/vorta/views/shell_commands_page.py
new file mode 100644
index 00000000..ce468d91
--- /dev/null
+++ b/src/vorta/views/shell_commands_page.py
@@ -0,0 +1,45 @@
+from PyQt6 import uic
+from PyQt6.QtWidgets import QLineEdit, QWidget
+
+from vorta.store.models import BackupProfileMixin
+from vorta.utils import get_asset
+
+
+class ShellCommandsPage(QWidget, BackupProfileMixin):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ uifile = get_asset('UI/shellcommandspage.ui')
+ uic.loadUi(uifile, self)
+
+ self.preBackupCmdLineEdit: QLineEdit = self.findChild(QLineEdit, 'preBackupCmdLineEdit')
+ self.postBackupCmdLineEdit: QLineEdit = self.findChild(QLineEdit, 'postBackupCmdLineEdit')
+ self.createCmdLineEdit: QLineEdit = self.findChild(QLineEdit, 'createCmdLineEdit')
+ profile = self.profile()
+ if profile.repo:
+ self.createCmdLineEdit.setText(profile.repo.create_backup_cmd)
+ self.createCmdLineEdit.setEnabled(True)
+ else:
+ self.createCmdLineEdit.setEnabled(False)
+
+ self.setup_connections()
+
+ def setup_connections(self):
+ self.preBackupCmdLineEdit.textEdited.connect(
+ lambda new_val, attr='pre_backup_cmd': self.save_profile_attr(attr, new_val)
+ )
+ self.postBackupCmdLineEdit.textEdited.connect(
+ lambda new_val, attr='post_backup_cmd': self.save_profile_attr(attr, new_val)
+ )
+ self.createCmdLineEdit.textEdited.connect(
+ lambda new_val, attr='create_backup_cmd': self.save_repo_attr(attr, new_val)
+ )
+
+ def save_profile_attr(self, attr, new_value):
+ profile = self.profile()
+ setattr(profile, attr, new_value)
+ profile.save()
+
+ def save_repo_attr(self, attr, new_value):
+ repo = self.profile().repo
+ setattr(repo, attr, new_value)
+ repo.save()
diff --git a/tests/integration/test_repo.py b/tests/integration/test_repo.py
index e4751b91..277aace5 100644
--- a/tests/integration/test_repo.py
+++ b/tests/integration/test_repo.py
@@ -19,4 +19,4 @@ def test_create(qapp, qtbot, archive_env):
assert ArchiveModel.select().count() == 7
assert main.createStartBtn.isEnabled()
assert main.archiveTab.archiveTable.rowCount() == 7
- assert main.scheduleTab.logTableWidget.rowCount() == 2
+ assert main.scheduleTab.logPage.logPage.rowCount() == 2
diff --git a/tests/unit/test_repo.py b/tests/unit/test_repo.py
index e072119d..053834e9 100644
--- a/tests/unit/test_repo.py
+++ b/tests/unit/test_repo.py
@@ -251,7 +251,7 @@ def test_create(qapp, borg_json_output, mocker, qtbot):
assert RepoModel.get(id=1).unique_size == 15520474
assert main.createStartBtn.isEnabled()
assert main.archiveTab.archiveTable.rowCount() == 3
- assert main.scheduleTab.logTableWidget.rowCount() == 1
+ assert main.scheduleTab.logPage.logPage.rowCount() == 1
@pytest.mark.parametrize(
diff --git a/tests/unit/test_schedule.py b/tests/unit/test_schedule.py
index 0222a255..1f030a5a 100644
--- a/tests/unit/test_schedule.py
+++ b/tests/unit/test_schedule.py
@@ -21,7 +21,7 @@ def clockmock(monkeypatch):
def test_schedule_tab(qapp: VortaApp, qtbot, clockmock):
main = qapp.main_window
- tab = main.scheduleTab
+ tab = main.scheduleTab.schedulePage
# setup
time_now = dt(2020, 5, 6, 4, 30)