From 6ba40ce25dd42aa0d193451fd4128beed0ec9677 Mon Sep 17 00:00:00 2001 From: claudi Date: Fri, 20 Feb 2026 08:45:41 +0100 Subject: [PATCH] Add web source configuration tab and URL mapping management to settings dialog --- src/webdrop_bridge/ui/settings_dialog.py | 163 +++++++++++++++++++++-- 1 file changed, 155 insertions(+), 8 deletions(-) diff --git a/src/webdrop_bridge/ui/settings_dialog.py b/src/webdrop_bridge/ui/settings_dialog.py index 0530b38..ac8fb06 100644 --- a/src/webdrop_bridge/ui/settings_dialog.py +++ b/src/webdrop_bridge/ui/settings_dialog.py @@ -17,6 +17,8 @@ from PySide6.QtWidgets import ( QPushButton, QSpinBox, QTabWidget, + QTableWidget, + QTableWidgetItem, QVBoxLayout, QWidget, ) @@ -62,6 +64,7 @@ class SettingsDialog(QDialog): self.tabs = QTabWidget() # Add tabs + self.tabs.addTab(self._create_web_source_tab(), "Web Source") self.tabs.addTab(self._create_paths_tab(), "Paths") self.tabs.addTab(self._create_urls_tab(), "URLs") self.tabs.addTab(self._create_logging_tab(), "Logging") @@ -91,13 +94,15 @@ class SettingsDialog(QDialog): # Get updated configuration data from UI config_data = self.get_config_data() - # Preserve URL mappings from original config (not editable in UI yet) - config_data["url_mappings"] = [ - { - "url_prefix": m.url_prefix, - "local_path": m.local_path - } - for m in self.config.url_mappings + # Convert URL mappings from dict to URLMapping objects + from webdrop_bridge.config import URLMapping + + url_mappings = [ + URLMapping( + url_prefix=m["url_prefix"], + local_path=m["local_path"] + ) + for m in config_data["url_mappings"] ] # Update the config object with new values @@ -106,6 +111,8 @@ class SettingsDialog(QDialog): self.config.log_file = Path(config_data["log_file"]) if config_data["log_file"] else None self.config.allowed_roots = [Path(r).resolve() for r in config_data["allowed_roots"]] self.config.allowed_urls = config_data["allowed_urls"] + self.config.webapp_url = config_data["webapp_url"] + self.config.url_mappings = url_mappings self.config.window_width = config_data["window_width"] self.config.window_height = config_data["window_height"] @@ -137,6 +144,139 @@ class SettingsDialog(QDialog): logger.error(f"Failed to save configuration: {e}", exc_info=True) self._show_error(f"Failed to save configuration:\n\n{e}") + def _create_web_source_tab(self) -> QWidget: + """Create web source configuration tab.""" + from PySide6.QtWidgets import QTableWidget, QTableWidgetItem + + widget = QWidget() + layout = QVBoxLayout() + + # Webapp URL configuration + layout.addWidget(QLabel("Web Application URL:")) + url_layout = QHBoxLayout() + + self.webapp_url_input = QLineEdit() + self.webapp_url_input.setText(self.config.webapp_url) + self.webapp_url_input.setPlaceholderText("e.g., http://localhost:8080 or file:///./webapp/index.html") + url_layout.addWidget(self.webapp_url_input) + + open_btn = QPushButton("Open") + open_btn.clicked.connect(self._open_webapp_url) + url_layout.addWidget(open_btn) + + layout.addLayout(url_layout) + + # URL Mappings (Azure Blob URL → Local Path) + layout.addWidget(QLabel("URL Mappings (Azure Blob Storage → Local Paths):")) + + # Create table for URL mappings + self.url_mappings_table = QTableWidget() + self.url_mappings_table.setColumnCount(2) + self.url_mappings_table.setHorizontalHeaderLabels(["URL Prefix", "Local Path"]) + self.url_mappings_table.horizontalHeader().setStretchLastSection(True) + + # Populate from config + for mapping in self.config.url_mappings: + row = self.url_mappings_table.rowCount() + self.url_mappings_table.insertRow(row) + self.url_mappings_table.setItem(row, 0, QTableWidgetItem(mapping.url_prefix)) + self.url_mappings_table.setItem(row, 1, QTableWidgetItem(mapping.local_path)) + + layout.addWidget(self.url_mappings_table) + + # Buttons for URL mapping management + button_layout = QHBoxLayout() + + add_mapping_btn = QPushButton("Add Mapping") + add_mapping_btn.clicked.connect(self._add_url_mapping) + button_layout.addWidget(add_mapping_btn) + + edit_mapping_btn = QPushButton("Edit Selected") + edit_mapping_btn.clicked.connect(self._edit_url_mapping) + button_layout.addWidget(edit_mapping_btn) + + remove_mapping_btn = QPushButton("Remove Selected") + remove_mapping_btn.clicked.connect(self._remove_url_mapping) + button_layout.addWidget(remove_mapping_btn) + + layout.addLayout(button_layout) + layout.addStretch() + + widget.setLayout(layout) + return widget + + def _open_webapp_url(self) -> None: + """Open the webapp URL in the default browser.""" + import webbrowser + url = self.webapp_url_input.text().strip() + if url: + # Handle file:// URLs + try: + webbrowser.open(url) + except Exception as e: + logger.error(f"Failed to open URL: {e}") + self._show_error(f"Failed to open URL:\n\n{e}") + + def _add_url_mapping(self) -> None: + """Add new URL mapping.""" + from PySide6.QtWidgets import QInputDialog + + url_prefix, ok1 = QInputDialog.getText( + self, + "Add URL Mapping", + "Enter Azure Blob Storage URL prefix:\n(e.g., https://myblob.blob.core.windows.net/container/)" + ) + + if ok1 and url_prefix: + local_path, ok2 = QInputDialog.getText( + self, + "Add URL Mapping", + "Enter local file system path:\n(e.g., C:\\Share or /mnt/share)" + ) + + if ok2 and local_path: + row = self.url_mappings_table.rowCount() + self.url_mappings_table.insertRow(row) + self.url_mappings_table.setItem(row, 0, QTableWidgetItem(url_prefix)) + self.url_mappings_table.setItem(row, 1, QTableWidgetItem(local_path)) + + def _edit_url_mapping(self) -> None: + """Edit selected URL mapping.""" + from PySide6.QtWidgets import QInputDialog + + current_row = self.url_mappings_table.currentRow() + if current_row < 0: + self._show_error("Please select a mapping to edit") + return + + url_prefix = self.url_mappings_table.item(current_row, 0).text() + local_path = self.url_mappings_table.item(current_row, 1).text() + + new_url_prefix, ok1 = QInputDialog.getText( + self, + "Edit URL Mapping", + "Enter Azure Blob Storage URL prefix:", + text=url_prefix + ) + + if ok1 and new_url_prefix: + new_local_path, ok2 = QInputDialog.getText( + self, + "Edit URL Mapping", + "Enter local file system path:", + text=local_path + ) + + if ok2 and new_local_path: + self.url_mappings_table.setItem(current_row, 0, QTableWidgetItem(new_url_prefix)) + self.url_mappings_table.setItem(current_row, 1, QTableWidgetItem(new_local_path)) + + def _remove_url_mapping(self) -> None: + """Remove selected URL mapping.""" + current_row = self.url_mappings_table.currentRow() + if current_row >= 0: + self.url_mappings_table.removeRow(current_row) + def _create_paths_tab(self) -> QWidget: """Create paths configuration tab.""" widget = QWidget() @@ -475,7 +615,14 @@ class SettingsDialog(QDialog): "log_file": self.log_file_input.text() or None, "allowed_roots": [self.paths_list.item(i).text() for i in range(self.paths_list.count())], "allowed_urls": [self.urls_list.item(i).text() for i in range(self.urls_list.count())], - "webapp_url": self.config.webapp_url, + "webapp_url": self.webapp_url_input.text().strip(), + "url_mappings": [ + { + "url_prefix": self.url_mappings_table.item(i, 0).text(), + "local_path": self.url_mappings_table.item(i, 1).text() + } + for i in range(self.url_mappings_table.rowCount()) + ], "window_width": self.width_spin.value(), "window_height": self.height_spin.value(), "enable_logging": self.config.enable_logging,