Skip to content

Commit 47c4a77

Browse files
Merge New/Existing repo dialogs into one (#1799)
Probes with borg info first, connects or offers to init accordingly. Closes #1799
1 parent f0ec8b8 commit 47c4a77

4 files changed

Lines changed: 217 additions & 85 deletions

File tree

src/vorta/views/dialogs/repo/repo_add.py

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
QDialogButtonBox,
88
QFormLayout,
99
QLabel,
10+
QMessageBox,
1011
QSizePolicy,
1112
)
1213

@@ -15,7 +16,7 @@
1516
from vorta.keyring.abc import VortaKeyring
1617
from vorta.store.models import RepoModel
1718
from vorta.utils import borg_compat, choose_file_dialog, get_asset, get_private_keys
18-
from vorta.views.partials.password_input import PasswordInput, PasswordLineEdit
19+
from vorta.views.partials.password_input import PasswordInput
1920
from vorta.views.utils import get_colored_icon
2021

2122
uifile = get_asset('UI/dialogs/repo/repo_add.ui')
@@ -131,7 +132,8 @@ def values(self):
131132
class AddRepoWindow(RepoWindow):
132133
def __init__(self, parent=None):
133134
super().__init__(parent)
134-
self.setWindowTitle("Add New Repository")
135+
self.setWindowTitle("Add Repository")
136+
self.title.setText(self.tr('Add Repository'))
135137

136138
self.passwordInput = PasswordInput()
137139
self.passwordInput.add_form_to_layout(self.repoDataFormLayout)
@@ -149,6 +151,9 @@ def __init__(self, parent=None):
149151
self.display_backend_warning()
150152
self.init_encryption()
151153

154+
# start in "connect" mode: hide init only widgets
155+
self._set_init_widgets_visible(False)
156+
152157
def set_password(self, URL):
153158
'''Autofill password from keyring only if current entry is empty'''
154159
password = VortaKeyring.get_keyring().get_password('vorta-repo', URL)
@@ -209,48 +214,74 @@ def display_backend_warning(self):
209214
if self.encryptionComboBox.currentData() != 'none':
210215
self.passwordInput.set_error_label(VortaKeyring.get_keyring().get_backend_warning())
211216

212-
def validate(self):
213-
return super().validate() and self.passwordInput.validate()
214-
215-
def run(self):
216-
if self.validate():
217-
params = BorgInitJob.prepare(self.values)
218-
if params['ok']:
219-
self.saveButton.setEnabled(False)
220-
job = BorgInitJob(params['cmd'], params)
221-
job.updated.connect(self._set_status)
222-
job.result.connect(self.run_result)
223-
QApplication.instance().jobs_manager.add_job(job)
224-
else:
225-
self._set_status(params['message'])
226-
227-
228-
class ExistingRepoWindow(RepoWindow):
229-
def __init__(self):
230-
super().__init__()
231-
self.title.setText(self.tr('Connect to existing Repository'))
232-
self.setWindowTitle("Add Existing Repository")
217+
def _set_init_widgets_visible(self, visible):
218+
self.passwordInput.confirmLineEdit.setVisible(visible)
219+
self.passwordInput._label_confirm.setVisible(visible)
220+
self.encryptionLabel.setVisible(visible)
221+
self.encryptionComboBox.setVisible(visible)
222+
if not visible:
223+
self.passwordInput.set_validation_enabled(False)
233224

234-
self.passwordLabel = QLabel(self.tr('Password:'))
235-
self.passwordInput = PasswordLineEdit(placeholder_text=self.tr("Enter the encryption passphrase"))
236-
self.repoDataFormLayout.addRow(self.passwordLabel, self.passwordInput)
225+
def _validate_repo_fields(self):
226+
return super().validate()
237227

238-
def set_password(self, URL):
239-
'''Autofill password from keyring only if current entry is empty'''
240-
password = VortaKeyring.get_keyring().get_password('vorta-repo', URL)
241-
if password and self.passwordInput.get_password() == "":
242-
self._set_status(self.tr("Autofilled password from password manager."))
243-
self.passwordInput.setText(password)
228+
def validate(self):
229+
return self._validate_repo_fields() and self.passwordInput.validate()
244230

245231
def run(self):
246-
if self.validate():
247-
params = BorgInfoRepoJob.prepare(self.values)
248-
if params['ok']:
249-
self.saveButton.setEnabled(False)
250-
job = BorgInfoRepoJob(params['cmd'], params)
251-
job.updated.connect(self._set_status)
252-
job.result.connect(self.run_result)
253-
self.thread = job # Keep reference for tests
254-
QApplication.instance().jobs_manager.add_job(job)
232+
if not self._validate_repo_fields():
233+
return
234+
235+
self.saveButton.setEnabled(False)
236+
self._set_status(self.tr('Checking repository…'))
237+
params = BorgInfoRepoJob.prepare(self.values)
238+
if params['ok']:
239+
job = BorgInfoRepoJob(params['cmd'], params)
240+
job.updated.connect(self._set_status)
241+
job.result.connect(self._probe_result)
242+
QApplication.instance().jobs_manager.add_job(job)
243+
else:
244+
self.saveButton.setEnabled(True)
245+
self._set_status(params['message'])
246+
247+
def _probe_result(self, result):
248+
if result['returncode'] == 0:
249+
self.saveButton.setEnabled(True)
250+
self.added_repo.emit(result)
251+
self.accept()
252+
else:
253+
error_msgs = ' '.join(msg for _, msg in result.get('errors', []))
254+
if 'does not exist' in error_msgs.lower() or 'is not a valid repository' in error_msgs.lower():
255+
reply = QMessageBox.question(
256+
self,
257+
self.tr('Repository not found'),
258+
self.tr('No repository found at this location. Initialize a new one?'),
259+
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
260+
QMessageBox.StandardButton.No,
261+
)
262+
if reply == QMessageBox.StandardButton.Yes:
263+
self._set_init_widgets_visible(True)
264+
self.passwordInput.set_validation_enabled(True)
265+
self._set_status(self.tr('Please confirm your password and choose encryption to initialize.'))
266+
if not self.passwordInput.validate():
267+
self.saveButton.setEnabled(True)
268+
return
269+
self._init_repo()
270+
else:
271+
self.saveButton.setEnabled(True)
272+
self._set_status(self.tr('Unable to add your repository.'))
255273
else:
256-
self._set_status(params['message'])
274+
self.saveButton.setEnabled(True)
275+
self._set_status(error_msgs if error_msgs else self.tr('Unable to add your repository.'))
276+
277+
def _init_repo(self):
278+
self._set_status(self.tr('Initializing new repository…'))
279+
params = BorgInitJob.prepare(self.values)
280+
if params['ok']:
281+
job = BorgInitJob(params['cmd'], params)
282+
job.updated.connect(self._set_status)
283+
job.result.connect(self.run_result)
284+
QApplication.instance().jobs_manager.add_job(job)
285+
else:
286+
self.saveButton.setEnabled(True)
287+
self._set_status(params['message'])

src/vorta/views/repo_tab.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from vorta.i18n.richtext import escape, format_richtext, link
1010
from vorta.store.models import ArchiveModel, RepoModel
1111
from vorta.utils import borg_compat, get_asset, get_private_keys, pretty_bytes
12-
from vorta.views.dialogs.repo.repo_add import AddRepoWindow, ExistingRepoWindow
12+
from vorta.views.dialogs.repo.repo_add import AddRepoWindow
1313
from vorta.views.dialogs.repo.repo_change_passphrase import ChangeBorgPassphraseWindow
1414
from vorta.views.dialogs.repo.ssh import SSHAddWindow
1515

@@ -35,13 +35,7 @@ def __init__(self, parent=None, profile_provider=None):
3535
# Populate dropdowns
3636
self.copyURLbutton.clicked.connect(self.copy_URL_action)
3737

38-
# init repo add button
39-
self.menuAddRepo = QMenu(self.bAddRepo)
40-
41-
self.menuAddRepo.addAction(self.tr("New Repository…"), self.new_repo)
42-
self.menuAddRepo.addAction(self.tr("Existing Repository…"), self.add_existing_repo)
43-
44-
self.bAddRepo.setMenu(self.menuAddRepo)
38+
self.bAddRepo.clicked.connect(self.add_repo)
4539

4640
# init repo util button
4741
self.menuRepoUtil = QMenu(self.bRepoUtil)
@@ -267,22 +261,11 @@ def ssh_copy_to_clipboard_action(self):
267261
def compression_select_action(self, index):
268262
self.save_profile_attr('compression', self.repoCompression.currentData())
269263

270-
def new_repo(self):
271-
"""Open a dialog to create a new repo and add it to vorta."""
264+
def add_repo(self):
272265
window = AddRepoWindow()
273266
self._window = window # For tests
274267
window.setParent(self, QtCore.Qt.WindowType.Sheet)
275268
window.added_repo.connect(self.process_new_repo)
276-
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
277-
window.open()
278-
279-
def add_existing_repo(self):
280-
"""Open a dialog to add a existing repo to vorta."""
281-
window = ExistingRepoWindow()
282-
self._window = window # For tests
283-
window.setParent(self, QtCore.Qt.WindowType.Sheet)
284-
window.added_repo.connect(self.process_new_repo)
285-
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
286269
window.open()
287270

288271
def repo_select_action(self):

tests/integration/test_init.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
def test_create_repo(qapp, qtbot, monkeypatch, choose_file_dialog, tmpdir):
2222
"""Test initializing a new repository"""
2323
main = qapp.main_window
24-
main.repoTab.new_repo()
24+
main.repoTab.add_repo()
2525
add_repo_window = main.repoTab._window
2626
main.show()
2727

@@ -44,6 +44,9 @@ def test_create_repo(qapp, qtbot, monkeypatch, choose_file_dialog, tmpdir):
4444
qtbot.keyClicks(add_repo_window.passwordInput.passwordLineEdit, LONG_PASSWORD)
4545
qtbot.keyClicks(add_repo_window.passwordInput.confirmLineEdit, LONG_PASSWORD)
4646

47+
# borg info fails for new/empty directories, triggering an init confirmation prompt
48+
monkeypatch.setattr(QMessageBox, "question", lambda *args, **kwargs: QMessageBox.StandardButton.Yes)
49+
4750
initial_count = main.repoTab.repoSelector.count()
4851
add_repo_window.run()
4952

@@ -88,7 +91,7 @@ def test_add_existing_repo(qapp, qtbot, monkeypatch, choose_file_dialog):
8891
)
8992

9093
# add existing repo again
91-
main.repoTab.add_existing_repo()
94+
main.repoTab.add_repo()
9295
add_repo_window = main.repoTab._window
9396

9497
monkeypatch.setattr(

0 commit comments

Comments
 (0)