mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-03-04 16:02:51 +01:00
feat: allow setting config in redis
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
import PySide6QtAds as QtAds
|
||||
import yaml
|
||||
from bec_lib import config_helper
|
||||
from bec_lib.bec_yaml_loader import yaml_load
|
||||
from bec_lib.file_utils import DeviceConfigWriter
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.plugin_helper import plugin_package_name, plugin_repo_path
|
||||
from bec_qthemes import apply_theme
|
||||
from PySide6QtAds import CDockManager, CDockWidget
|
||||
from qtpy.QtCore import Qt, QTimer
|
||||
from qtpy.QtCore import Qt, QThreadPool, QTimer
|
||||
from qtpy.QtWidgets import QFileDialog, QMessageBox, QSplitter, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets import BECWidget
|
||||
@@ -29,13 +31,21 @@ from bec_widgets.widgets.control.device_manager.components._util import SharedSe
|
||||
from bec_widgets.widgets.control.device_manager.components.available_device_resources.available_device_resources import (
|
||||
AvailableDeviceResources,
|
||||
)
|
||||
from bec_widgets.widgets.services.device_browser.device_item.config_communicator import (
|
||||
CommunicateConfigAction,
|
||||
)
|
||||
from bec_widgets.widgets.services.device_browser.device_item.device_config_dialog import (
|
||||
DeviceConfigDialog,
|
||||
PresetClassDeviceConfigDialog,
|
||||
)
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
_yes_no_question = partial(
|
||||
QMessageBox.question,
|
||||
buttons=QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
defaultButton=QMessageBox.StandardButton.No,
|
||||
)
|
||||
|
||||
|
||||
def set_splitter_weights(splitter: QSplitter, weights: List[float]) -> None:
|
||||
"""
|
||||
@@ -78,6 +88,7 @@ class DeviceManagerView(BECWidget, QWidget):
|
||||
def __init__(self, parent=None, *args, **kwargs):
|
||||
super().__init__(parent=parent, client=None, *args, **kwargs)
|
||||
|
||||
self._config_helper = config_helper.ConfigHelper(self.client.connector)
|
||||
self._shared_selection = SharedSelectionSignal()
|
||||
|
||||
# Top-level layout hosting a toolbar and the dock manager
|
||||
@@ -326,12 +337,10 @@ class DeviceManagerView(BECWidget, QWidget):
|
||||
@SafeSlot()
|
||||
def _load_redis_action(self):
|
||||
"""Action for the 'load_redis' action to load the current config from Redis for the io_bundle of the toolbar."""
|
||||
reply = QMessageBox.question(
|
||||
reply = _yes_no_question(
|
||||
self,
|
||||
"Load currently active config",
|
||||
"Do you really want to discard the current config and reload?",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if reply == QMessageBox.StandardButton.Yes and self.client.device_manager is not None:
|
||||
self.device_table_view.set_device_config(
|
||||
@@ -340,6 +349,32 @@ class DeviceManagerView(BECWidget, QWidget):
|
||||
else:
|
||||
return
|
||||
|
||||
@SafeSlot()
|
||||
def _update_redis_action(self):
|
||||
"""Action to push the current composition to Redis"""
|
||||
reply = _yes_no_question(
|
||||
self,
|
||||
"Push composition to Redis",
|
||||
"Do you really want to replace the active configuration in the BEC server with the current composition? ",
|
||||
)
|
||||
if reply != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
if self.device_table_view.table.contains_invalid_devices():
|
||||
return QMessageBox.warning(
|
||||
self, "Validation has errors!", "Please resolve before proceeding."
|
||||
)
|
||||
if self.ophyd_test_view.validation_running():
|
||||
return QMessageBox.warning(
|
||||
self, "Validation has not completed.", "Please wait for the validation to finish."
|
||||
)
|
||||
self._push_compositiion_to_redis()
|
||||
|
||||
def _push_compositiion_to_redis(self):
|
||||
config = {cfg.pop("name"): cfg for cfg in self.device_table_view.table.all_configs()}
|
||||
threadpool = QThreadPool.globalInstance()
|
||||
comm = CommunicateConfigAction(self._config_helper, None, config, "set")
|
||||
threadpool.start(comm)
|
||||
|
||||
@SafeSlot()
|
||||
def _save_to_disk_action(self):
|
||||
"""Action for the 'safe_to_disk' action to save the current config to disk."""
|
||||
@@ -360,24 +395,15 @@ class DeviceManagerView(BECWidget, QWidget):
|
||||
with open(file_path, "w") as file:
|
||||
file.write(yaml.dump(config))
|
||||
|
||||
# TODO add here logic, should be asyncronous, but probably block UI, and show a loading spinner. If failed, it should report..
|
||||
@SafeSlot()
|
||||
def _update_redis_action(self):
|
||||
"""Action for the 'update_redis' action to update the current config in Redis."""
|
||||
config = self.device_table_view.get_device_config()
|
||||
reply = self._coming_soon()
|
||||
|
||||
# Table actions
|
||||
|
||||
@SafeSlot()
|
||||
def _reset_composed_view(self):
|
||||
"""Action for the 'reset_composed_view' action to reset the composed view."""
|
||||
reply = QMessageBox.question(
|
||||
reply = _yes_no_question(
|
||||
self,
|
||||
"Clear View",
|
||||
"You are about to clear the current composed config view, please confirm...",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if reply == QMessageBox.StandardButton.Yes:
|
||||
self.device_table_view.clear_device_configs()
|
||||
|
||||
@@ -313,7 +313,7 @@ class DeviceTableModel(QtCore.QAbstractTableModel):
|
||||
|
||||
def get_device_config(self) -> list[dict[str, Any]]:
|
||||
"""Method to get the device configuration."""
|
||||
return self._device_config
|
||||
return copy.deepcopy(self._device_config)
|
||||
|
||||
def device_names(self, configs: _DeviceCfgIter | None = None) -> set[str]:
|
||||
_configs = self._device_config if configs is None else configs
|
||||
@@ -431,6 +431,9 @@ class DeviceTableModel(QtCore.QAbstractTableModel):
|
||||
index = self.index(row, 0)
|
||||
self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole])
|
||||
|
||||
def validation_statuses(self):
|
||||
return copy.deepcopy(self._validation_status)
|
||||
|
||||
|
||||
class BECTableView(QtWidgets.QTableView):
|
||||
"""Table View with custom keyPressEvent to delete rows with backspace or delete key"""
|
||||
@@ -455,6 +458,12 @@ class BECTableView(QtWidgets.QTableView):
|
||||
return self.delete_selected()
|
||||
return super().keyPressEvent(event)
|
||||
|
||||
def contains_invalid_devices(self):
|
||||
return ValidationStatus.FAILED in self.model().sourceModel().validation_statuses().values()
|
||||
|
||||
def all_configs(self):
|
||||
return self.model().sourceModel().get_device_config()
|
||||
|
||||
def selected_configs(self):
|
||||
return self.model().get_row_data(self.selectionModel().selectedRows())
|
||||
|
||||
|
||||
@@ -373,6 +373,9 @@ class DMOphydTest(BECWidget, QtWidgets.QWidget):
|
||||
)
|
||||
return html
|
||||
|
||||
def validation_running(self):
|
||||
return self._device_list_items != {}
|
||||
|
||||
@SafeSlot()
|
||||
def clear_list(self):
|
||||
"""Clear the device list."""
|
||||
|
||||
@@ -34,7 +34,11 @@ class CommunicateConfigAction(QRunnable):
|
||||
@SafeSlot()
|
||||
def run(self):
|
||||
try:
|
||||
if self.action in ["add", "update", "remove"]:
|
||||
if self.action == "set":
|
||||
self._process(
|
||||
{"action": self.action, "config": self.config, "wait_for_response": False}
|
||||
)
|
||||
elif self.action in ["add", "update", "remove"]:
|
||||
if (dev_name := self.device or self.config.get("name")) is None:
|
||||
raise ValueError(
|
||||
"Must be updating a device or be supplied a name for a new device"
|
||||
@@ -57,6 +61,9 @@ class CommunicateConfigAction(QRunnable):
|
||||
"config": {dev_name: self.config},
|
||||
"wait_for_response": False,
|
||||
}
|
||||
self._process(req_args)
|
||||
|
||||
def _process(self, req_args: dict):
|
||||
timeout = (
|
||||
self.config_helper.suggested_timeout_s(self.config) if self.config is not None else 20
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user