diff --git a/bec_widgets/utils/forms_from_types/items.py b/bec_widgets/utils/forms_from_types/items.py index 389aaccb..73e702b3 100644 --- a/bec_widgets/utils/forms_from_types/items.py +++ b/bec_widgets/utils/forms_from_types/items.py @@ -390,17 +390,29 @@ class ListFormItem(DynamicFormItem): def _add_buttons(self): self._button_holder = QWidget() + self._button_holder.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._buttons = QVBoxLayout() + self._buttons.setContentsMargins(0, 0, 0, 0) self._button_holder.setLayout(self._buttons) self._layout.addWidget(self._button_holder) + + self._add_remove_button_holder = QWidget() + self._add_remove_button_layout = QHBoxLayout() + self._add_remove_button_layout.setContentsMargins(0, 0, 0, 0) + self._add_remove_button_holder.setLayout(self._add_remove_button_layout) + self._add_button = QPushButton("+") + self._add_button.setMinimumHeight(15) self._add_button.setToolTip("add a new row") self._remove_button = QPushButton("-") + self._remove_button.setMinimumHeight(15) self._remove_button.setToolTip("delete the focused row (if any)") self._add_button.clicked.connect(self._add_row) self._remove_button.clicked.connect(self._delete_row) - self._buttons.addWidget(self._add_button) - self._buttons.addWidget(self._remove_button) + + self._buttons.addWidget(self._add_remove_button_holder) + self._add_remove_button_layout.addWidget(self._add_button) + self._add_remove_button_layout.addWidget(self._remove_button) def _set_pretty_display(self): super()._set_pretty_display() diff --git a/bec_widgets/widgets/services/device_browser/device_item/device_config_dialog.py b/bec_widgets/widgets/services/device_browser/device_item/device_config_dialog.py index 54d6d42a..7c393f6d 100644 --- a/bec_widgets/widgets/services/device_browser/device_item/device_config_dialog.py +++ b/bec_widgets/widgets/services/device_browser/device_item/device_config_dialog.py @@ -30,6 +30,15 @@ from bec_widgets.widgets.utility.spinner.spinner import SpinnerWidget logger = bec_logger.logger +def _try_literal_eval(value: str): + if value == "": + return "" + try: + return literal_eval(value) + except SyntaxError as e: + raise ValueError(f"Entered config value {value} is not a valid python value!") from e + + class DeviceConfigDialog(BECWidget, QDialog): RPC = False applied = Signal() @@ -93,6 +102,10 @@ class DeviceConfigDialog(BECWidget, QDialog): @field_validator("name") @staticmethod def _validate_name(value: str, *_): + if not value.isidentifier(): + raise ValueError( + f"Invalid device name: {value}. Device names must be valid Python identifiers." + ) if value in self.dev: raise ValueError(f"A device with name {value} already exists!") return value @@ -160,7 +173,7 @@ class DeviceConfigDialog(BECWidget, QDialog): diff["deviceConfig"].pop("device_access", None) # TODO: replace when https://github.com/bec-project/bec/issues/528 is resolved diff["deviceConfig"] = { - k: literal_eval(str(v)) for k, v in diff["deviceConfig"].items() + k: _try_literal_eval(str(v)) for k, v in diff["deviceConfig"].items() if k != "" } return diff @@ -213,6 +226,10 @@ class DeviceConfigDialog(BECWidget, QDialog): @SafeSlot(Exception, popup_error=True) def update_error(self, e: Exception): + self._stop_waiting_display() + if self._action == "update": + self._fetch_config() + self._fill_form() raise RuntimeError("Failed to update device configuration") from e def _start_waiting_display(self):