From 235a5e4535c3271c1292e9a6a5db9fcd74f1c79e Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Thu, 30 Jul 2026 14:38:54 +0200 Subject: [PATCH 1/9] refactor(tests): update v4 scan names --- tests/tests_devices/test_pilatus.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/tests_devices/test_pilatus.py b/tests/tests_devices/test_pilatus.py index 2f1bb01..fc02311 100644 --- a/tests/tests_devices/test_pilatus.py +++ b/tests/tests_devices/test_pilatus.py @@ -6,23 +6,14 @@ from unittest import mock import ophyd import pytest from bec_lib.messages import ScanStatusMessage -from bec_server.scan_server.scan_worker import ScanWorker -from bec_server.scan_server.scans.scan_base import ScanInfo as ScanServerScanInfo from bec_server.scan_server.tests.scan_fixtures import * from bec_server.scan_server.tests.scan_fixtures import _MockDevice -from ophyd_devices import CompareStatus, DeviceStatus +from ophyd_devices import DeviceStatus from ophyd_devices.interfaces.base_classes.psi_device_base import DeviceStoppedError from ophyd_devices.tests.utils import MockPV, patch_dual_pvs from ophyd_devices.utils.psi_device_base_utils import TaskStatus -from debye_bec.devices.pilatus.pilatus import ( - ACQUIREMODE, - COMPRESSIONALGORITHM, - DETECTORSTATE, - FILEWRITEMODE, - TRIGGERMODE, - Pilatus, -) +from debye_bec.devices.pilatus.pilatus import ACQUIREMODE, DETECTORSTATE, Pilatus from debye_bec.devices.utils.utils import fetch_scan_info if TYPE_CHECKING: # pragma no cover @@ -38,8 +29,8 @@ if TYPE_CHECKING: # pragma no cover @pytest.fixture( scope="function", params=[ - (("samx", 0.1, 1, 5, "samy", 0, 1, 5), {"relative": True}, "_v4_hexagonal_scan"), - ((1, 0.2), {}, "_v4_time_scan"), + (("samx", 0.1, 1, 5, "samy", 0, 1, 5), {"relative": True}, "hexagonal_scan"), + ((1, 0.2), {}, "time_scan"), ((9000, 10000, 1, 20, 0.1, 9500), {}, "xas_advanced_scan"), ], ) From a2c0a3c20b5e419481445c988bb51de67fdb6fb1 Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Tue, 7 Jul 2026 14:19:28 +0200 Subject: [PATCH 2/9] Updating to template version 1.4.1 --- .copier-answers.yml | 2 +- .gitea/workflows/create_update_pr.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.copier-answers.yml b/.copier-answers.yml index 08016da..f46a724 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -2,7 +2,7 @@ # It is needed to track the repo template version, and editing may break things. # This file will be overwritten by copier on template updates. -_commit: v1.4.0 +_commit: v1.4.1 _src_path: https://github.com/bec-project/plugin_copier_template.git make_commit: false project_name: debye_bec diff --git a/.gitea/workflows/create_update_pr.yml b/.gitea/workflows/create_update_pr.yml index 335858b..6b4ceb0 100644 --- a/.gitea/workflows/create_update_pr.yml +++ b/.gitea/workflows/create_update_pr.yml @@ -16,14 +16,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: "3.12" - name: Checkout uses: actions/checkout@v4 - name: Create virtualenv - run: | - python -m virtualenv .venv + run: | + python -m virtualenv .venv - name: Install tools run: | From 5339694d90ac41dcddebd7266fd6018c0763f6b4 Mon Sep 17 00:00:00 2001 From: appel_c Date: Mon, 1 Jun 2026 13:13:34 +0200 Subject: [PATCH 3/9] feat(falcon): Minimal integration of the Falcon, forwarding array data. --- debye_bec/devices/falcon/__init__.py | 0 debye_bec/devices/falcon/falcon.py | 124 +++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 debye_bec/devices/falcon/__init__.py create mode 100644 debye_bec/devices/falcon/falcon.py diff --git a/debye_bec/devices/falcon/__init__.py b/debye_bec/devices/falcon/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/debye_bec/devices/falcon/falcon.py b/debye_bec/devices/falcon/falcon.py new file mode 100644 index 0000000..0ff60b0 --- /dev/null +++ b/debye_bec/devices/falcon/falcon.py @@ -0,0 +1,124 @@ +"""FALCON device implementation for SuperXAS""" + +from __future__ import annotations + +import enum +import traceback +from typing import TYPE_CHECKING + +from bec_lib.logger import bec_logger +from ophyd import Component as Cpt +from ophyd_devices import AsyncSignal, CompareStatus, DeviceStatus, StatusBase +from ophyd_devices.devices.areadetector.plugins import ImagePlugin_V35 as ImagePlugin +from ophyd_devices.devices.dxp import EpicsDXPFalcon, EpicsMCARecord, Falcon +from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase + +if TYPE_CHECKING: + from bec_lib.devicemanager import ScanInfo + +logger = bec_logger.logger + + +class FalconAcquiringStatus(int, enum.Enum): + """Status of Falcon""" + + DONE = 0 + ACQUIRING = 1 + + +class FalconControl(Falcon): + """Falcon Control class at SuperXAS. prefix: 'X10DA-SITORO:'""" + + # DXP parameters + dxp1 = Cpt(EpicsDXPFalcon, "dxp1:") + # MCA record with spectrum data + mca1 = Cpt(EpicsMCARecord, "mca1") + # Image record + image = Cpt(ImagePlugin, "image1:") + + +class FalconSuperXAS(PSIDeviceBase, FalconControl): + """Falcon implementierung at SuperXAS. prefix: 'X10DA-SITORO:'""" + + data = Cpt( + AsyncSignal, + name="data", + ndim=1, + max_size=1000, + doc="1D Waveform data from Falcon detector.", + ) + + ######################################## + # Beamline Specific Implementations # + ######################################## + + def on_init(self) -> None: + """ + Called when the device is initialized. + + No signals are connected at this point. If you like to + set default values on signals, please use on_connected instead. + """ + self._pv_timeout = 1 + self._falcon_energy_channels = None + + def on_connected(self) -> None: + """ + Called after the device is connected and its signals are connected. + Default values for signals should be set here. + """ + # Reset array counter on connect + self.cam.array_counter.set(0).wait(timeout=self._pv_timeout) + self.image.unique_id.subscribe(self._on_new_data_received, run=False) + + def on_stage(self) -> CompareStatus: + """ + Called while staging the device. + + Information about the upcoming scan can be accessed from the scan_info (self.scan_info.msg) object. + """ + + def on_unstage(self) -> CompareStatus: + """Called while unstaging the device.""" + + def on_pre_scan(self) -> DeviceStatus | StatusBase | None: + """Called right before the scan starts on all devices automatically.""" + + def on_trigger(self) -> DeviceStatus | StatusBase | None: + """Called when the device is triggered.""" + + def on_complete(self) -> DeviceStatus | StatusBase | None: + """Called to inquire if a device has completed a scans.""" + + def on_kickoff(self) -> DeviceStatus | StatusBase | None: + """Called to kickoff a device for a fly scan. Has to be called explicitly.""" + + def on_stop(self) -> None: + """Called when the device is stopped.""" + + ######################################## + # Custom Methods # + ######################################## + + def _on_new_data_received(self, value: int, old_value: int, **kwargs): + """Callback for image unique ID updates to trigger preview update.""" + if value == old_value: + return # No new image, or counter reset + try: + # Get new image data + array_data = self.image.array_data.get() + if array_data is None: + logger.info(f"No image data available for preview of {self.name}") + return + if self._falcon_energy_channels is None: + # Initialize energy channels based on the first received data + self._falcon_energy_channels = len(array_data) + logger.info(f"Initialized Falcon energy channels to {self._falcon_energy_channels}") + # Geometry correction for the image + self.data.put( + array_data, + async_update={"type": "add", "max_shape": [None, self._falcon_energy_channels]}, + ) + except Exception: # pylint: disable=broad-except + content = traceback.format_exc() + logger.error(f"Error while updating preview for {self.name} on image update: {content}") From 8a816c6dc6433856df92ff512b15bc92b9d8bb7e Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Wed, 15 Jul 2026 13:52:29 +0200 Subject: [PATCH 4/9] fix(devices): mo1_bragg add failure_value to CompareStatus to not hang forever and report error --- debye_bec/devices/mo1_bragg/mo1_bragg.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debye_bec/devices/mo1_bragg/mo1_bragg.py b/debye_bec/devices/mo1_bragg/mo1_bragg.py index ae8702f..54a813f 100644 --- a/debye_bec/devices/mo1_bragg/mo1_bragg.py +++ b/debye_bec/devices/mo1_bragg/mo1_bragg.py @@ -291,7 +291,11 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): time.sleep(1) logger.info(f"Device {self.name}, done sleeping") # Load the scan parameters to the controller - status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.SUCCESS) + status = CompareStatus( + self.scan_control.scan_msg, + ScanControlLoadMessage.SUCCESS, + failure_value=[m for m in ScanControlLoadMessage if m.name.startswith("ERR_")], + ) self.cancel_on_stop(status) self.scan_control.scan_load.put(1) # Wait for params to be checked from controller From 093426d4aaaeb16cfa5f7f3c1510bec6794eeb50 Mon Sep 17 00:00:00 2001 From: appel_c Date: Thu, 16 Jul 2026 10:01:17 +0200 Subject: [PATCH 5/9] fix(nidaq): fix on_kickoff call not using set --- debye_bec/devices/nidaq/nidaq.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/debye_bec/devices/nidaq/nidaq.py b/debye_bec/devices/nidaq/nidaq.py index 2a15fa7..be52d92 100644 --- a/debye_bec/devices/nidaq/nidaq.py +++ b/debye_bec/devices/nidaq/nidaq.py @@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, Literal from bec_lib.logger import bec_logger from bec_server.scan_server.scans.scan_base import ScanInfo as ScanServerScanInfo from ophyd import Component as Cpt -from ophyd import Device, DeviceStatus, EpicsSignal, EpicsSignalRO, Kind, StatusBase +from ophyd import Device, DeviceStatus, EpicsSignal, EpicsSignalRO, Kind from ophyd.status import WaitTimeoutError -from ophyd_devices import CompareStatus, ProgressSignal, TransitionStatus +from ophyd_devices import CompareStatus, ProgressSignal, StatusBase, TransitionStatus from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from ophyd_devices.sim.sim_signals import SetableSignal @@ -433,13 +433,18 @@ class Nidaq(PSIDeviceBase, NidaqControl): status.wait(timeout=self.timeout_wait_for_signal) if self.scan_parameters.scan_name != "nidaq_continuous_scan": status = self.on_kickoff() - self.cancel_on_stop(status) - status.wait(timeout=self._timeout_wait_for_pv) + status.wait() logger.info(f"Device {self.name} was staged: {NidaqState(self.state.get())}") def on_kickoff(self) -> DeviceStatus | StatusBase: """Kickoff the Nidaq""" - status = self.kickoff_call.set(1) + status = CompareStatus( + self.state, + NidaqState.KICKOFF.value, + timeout=self._timeout_wait_for_pv, + description="Waiting for NIDAQ to enter KICKOFF state", + ) + self.kickoff_call.put(1) self.cancel_on_stop(status) return status From 3ae5258a1525e5114cc9a30c017d9bdc8ef27bbc Mon Sep 17 00:00:00 2001 From: x01da Date: Thu, 30 Jul 2026 10:51:25 +0200 Subject: [PATCH 6/9] fix(hutch cam): do not override internal ophyd name --- debye_bec/devices/cameras/hutch_cam.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debye_bec/devices/cameras/hutch_cam.py b/debye_bec/devices/cameras/hutch_cam.py index 376845d..6479ed1 100644 --- a/debye_bec/devices/cameras/hutch_cam.py +++ b/debye_bec/devices/cameras/hutch_cam.py @@ -39,7 +39,7 @@ class HutchCam(PSIDeviceBase): super().__init__(name=name, scan_info=scan_info, **kwargs) self.scan_parameters: ScanServerScanInfo = None self.hostname = prefix - self.name = "" + self.camera_name = "" # pylint: disable=E1101 def on_connected(self) -> None: @@ -49,12 +49,14 @@ class HutchCam(PSIDeviceBase): info_url = f"http://{CAM_USERNAME}:{CAM_PASSWORD}@{self.hostname}.psi.ch/-wvhttp-01-/info.cgi?item=c.1.name" response = requests.get(info_url, timeout=5) response.raise_for_status() - self.name = response.content.decode("utf-8").split("c.1.name.utf8:=")[-1].strip().lower() + self.camera_name = ( + response.content.decode("utf-8").split("c.1.name.utf8:=")[-1].strip().lower() + ) def on_stage(self) -> DeviceStatus: """Called while staging the device.""" self.scan_parameters = fetch_scan_info(self.scan_info) - file_path = get_full_path(self.scan_info.msg, name=self.name).removesuffix("h5") + file_path = get_full_path(self.scan_info.msg, name=self.camera_name).removesuffix("h5") thread = threading.Thread( target=self.acquire_and_save_from_video, args=(file_path,), daemon=True From 81e43f60200f4c384842046cb2bbaf1fabe69402 Mon Sep 17 00:00:00 2001 From: x01da Date: Thu, 30 Jul 2026 11:26:03 +0200 Subject: [PATCH 7/9] fix(widgets): fix init parameters after new bec version --- debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py | 2 +- debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py index e1c930d..b745ffc 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py @@ -35,7 +35,7 @@ class DataViewer(BECWidget, QWidget): ICON_NAME = "find_in_page" def __init__(self, *arg, parent=None, **kwargs): - super().__init__(parent=parent, theme_update=True, *arg, **kwargs) + super().__init__(parent=parent, *arg, **kwargs) self.get_bec_shortcuts() central = QWidget() diff --git a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py index bf44cbe..b8ff05f 100644 --- a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py +++ b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py @@ -76,7 +76,7 @@ class DigitalTwin(BECWidget, QWidget): ICON_NAME = "lightbulb" def __init__(self, *arg, parent=None, **kwargs): - super().__init__(parent=parent, theme_update=True, *arg, **kwargs) + super().__init__(parent=parent, *arg, **kwargs) self.get_bec_shortcuts() self.beamline = get_beamline_id() From af34992259fc5e7fc345a13471ac3fec27138f98 Mon Sep 17 00:00:00 2001 From: x01da Date: Mon, 3 Aug 2026 09:21:39 +0200 Subject: [PATCH 8/9] fix comment/sample name issue. Add open from file manager button. --- .../widgets/data_viewer/data_viewer.py | 71 ++++++++++++------- .../widgets/data_viewer/panels/input_panel.py | 14 +++- .../widgets/data_viewer/panels/scan_view.py | 4 +- .../widgets/data_viewer/widgets/qt_widgets.py | 6 +- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py index b745ffc..46325ef 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py @@ -16,7 +16,7 @@ from bec_widgets.utils.colors import apply_theme, get_accent_colors from bec_widgets.utils.error_popups import SafeSlot # pylint: disable=E0611 -from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget +from qtpy.QtWidgets import QApplication, QFileDialog, QVBoxLayout, QWidget from .panels.input_panel import InputPanel from .panels.scan_view import ScanViewer @@ -55,8 +55,9 @@ class DataViewer(BECWidget, QWidget): self.current_row = 0 self.input.scan_sel.currentItemChanged_connect(self.scan_sel_changed) - self.input.load_button.clicked_connect(self.load_scan) - self.input.unload_button.clicked_connect(self.unload_all_scans) + self.input.load_button.clicked_connect(self.load_scan_from_history) + self.input.load_from_folder_button.clicked_connect(self.load_scan_from_folder) + self.viewer.unload_button.clicked_connect(self.unload_all_scans) self.input.open_fm_button.clicked_connect(self.open_in_file_manager) def apply_theme(self, theme: Literal["dark", "light"]): @@ -89,7 +90,7 @@ class DataViewer(BECWidget, QWidget): ) @SafeSlot() - def load_scan(self, *_): + def load_scan_from_history(self, *_): """ Loads a scan. Find all files within the scan folder, sort them and then load the files in the scan view @@ -97,23 +98,37 @@ class DataViewer(BECWidget, QWidget): if len(self.history) > 0: scan = self.history[self.current_row] base_filepath = scan["file_components"][0].decode().rsplit("/", 1)[0] - filenames = [ - f - for f in os.listdir(base_filepath) - if os.path.isfile(os.path.join(base_filepath, f)) - ] + self.load_scan(base_filepath) - def sort_priority(name): - if "master" in name: - return 0 - if name.endswith(".h5"): - return 1 - return 2 + @SafeSlot() + def load_scan_from_folder(self, *_): + """ + Loads a scan from a folder. Find all files within the scan folder, sort them and + then load the files in the scan view + """ + base_filepath = QFileDialog.getExistingDirectory(self, "Open Scan Folder", "/sls") - sorted_files = [ - f"{base_filepath}/{name}" for name in sorted(filenames, key=sort_priority) - ] - self.viewer.load_files(sorted_files) + if base_filepath != "": + self.load_scan(base_filepath) + + def load_scan(self, base_filepath): + """ + Loads a scan from a base_filepath. Find all files within the scan folder, sort them and + then load the files in the scan view + """ + filenames = [ + f for f in os.listdir(base_filepath) if os.path.isfile(os.path.join(base_filepath, f)) + ] + + def sort_priority(name): + if "master" in name: + return 0 + if name.endswith(".h5"): + return 1 + return 2 + + sorted_files = [f"{base_filepath}/{name}" for name in sorted(filenames, key=sort_priority)] + self.viewer.load_files(sorted_files) @SafeSlot() def unload_all_scans(self, *_): @@ -176,13 +191,21 @@ class DataViewer(BECWidget, QWidget): start_time = self.client.history[-n].metadata["start_time"] # type: ignore end_time = self.client.history[-n].metadata["end_time"] # type: ignore scan_data = self.client.history[-n].metadata["bec"] # type: ignore + # logger.info(f"scan_data: {scan_data}") scan_number = scan_data["scan_number"] scan_name = scan_data["scan_name"] - if "metadata" in scan_data: - comment = scan_data["metadata"]["user_metadata"]["comment"] - sample_name = scan_data["metadata"]["user_metadata"]["sample_name"] - else: - comment, sample_name = "", "" + + comment, sample_name = "", "" + user_metadata = scan_data.get("user_metadata", {}) + comment = user_metadata.get("comment", comment) + sample_name = user_metadata.get("sample_name", sample_name) + if comment == "": + metadata_user = scan_data.get("metadata", {}).get("user_metadata", {}) + comment = metadata_user.get("comment", comment) + if sample_name == "": + metadata_user = scan_data.get("metadata", {}).get("user_metadata", {}) + sample_name = metadata_user.get("sample_name", sample_name) + status = scan_data["status"] self.history.append( { diff --git a/debye_bec/bec_widgets/widgets/data_viewer/panels/input_panel.py b/debye_bec/bec_widgets/widgets/data_viewer/panels/input_panel.py index f249b94..3d2088e 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/panels/input_panel.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/panels/input_panel.py @@ -1,5 +1,5 @@ # pylint: disable=E0611 -from qtpy.QtWidgets import QHBoxLayout, QVBoxLayout, QWidget +from qtpy.QtWidgets import QFrame, QHBoxLayout, QVBoxLayout, QWidget # pylint: disable=E0402 from ..widgets.qt_widgets import Button, Group, ListWidget @@ -15,13 +15,21 @@ class InputPanel(QWidget): # Scan selection self.scan_sel = ListWidget("scan_sel") self.load_button = Button(label_button="Load Dataset", enabled=True) - self.unload_button = Button(label_button="Unload all", enabled=True) self.open_fm_button = Button(label_button="Open in File Manager", enabled=True) + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + + self.load_from_folder_button = Button( + label_button="Load Dataset from File Manager", enabled=True + ) + self._button_layout = QVBoxLayout() self._button_layout.addWidget(self.load_button) - self._button_layout.addWidget(self.unload_button) self._button_layout.addWidget(self.open_fm_button) + self._button_layout.addWidget(line) + self._button_layout.addWidget(self.load_from_folder_button) self._button_layout.addStretch() # Assemble complete scan selection group diff --git a/debye_bec/bec_widgets/widgets/data_viewer/panels/scan_view.py b/debye_bec/bec_widgets/widgets/data_viewer/panels/scan_view.py index aa3ebe7..9c730b1 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/panels/scan_view.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/panels/scan_view.py @@ -27,7 +27,7 @@ from qtpy.QtWidgets import ( # pylint: disable=E0402 from ..loaders import BaseFileLoader, registry -from ..widgets.qt_widgets import Group +from ..widgets.qt_widgets import Button, Group from .data_view import DataView logger = bec_logger.logger @@ -59,6 +59,7 @@ class ScanViewer(QMainWindow): left_pane = QWidget() left_layout = QVBoxLayout(left_pane) + self.unload_button = Button(label_button="Unload all", enabled=True) self.tree = QTreeWidget() self.tree.setMinimumWidth(250) self.tree.setHeaderLabels(["Name", "Type", "Shape"]) @@ -68,6 +69,7 @@ class ScanViewer(QMainWindow): self.tree.header().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents) self.tree.itemClicked.connect(self._on_item_clicked) + left_layout.addWidget(self.unload_button) left_layout.addWidget(self.tree, 1) self.data_panel = DataView() diff --git a/debye_bec/bec_widgets/widgets/data_viewer/widgets/qt_widgets.py b/debye_bec/bec_widgets/widgets/data_viewer/widgets/qt_widgets.py index 187157e..7242c1e 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/widgets/qt_widgets.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/widgets/qt_widgets.py @@ -45,15 +45,13 @@ class Button(QWidget): def __init__(self, label=None, label_button: str = "", enabled=False): super().__init__() layout = QHBoxLayout(self) - layout.setContentsMargins(10, 0, 0, 0) + layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) if label is not None: self.label = QLabel(label) - self.label.setFixedWidth(140) + self.label.setFixedWidth(160) layout.addWidget(self.label) self.button = QPushButton(label_button) - if label is not None: - self.button.setFixedWidth(160) self.enable_button(enabled) layout.addWidget(self.button) From 6ec8ef182bfe225e68e2ee04c054fbb60e4084c6 Mon Sep 17 00:00:00 2001 From: x01da Date: Tue, 4 Aug 2026 12:30:35 +0200 Subject: [PATCH 9/9] feat(dataviewer): open file manager at raw folder of current p-group --- .../bec_widgets/widgets/data_viewer/data_viewer.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py index 46325ef..9dc185e 100644 --- a/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py +++ b/debye_bec/bec_widgets/widgets/data_viewer/data_viewer.py @@ -106,7 +106,16 @@ class DataViewer(BECWidget, QWidget): Loads a scan from a folder. Find all files within the scan folder, sort them and then load the files in the scan view """ - base_filepath = QFileDialog.getExistingDirectory(self, "Open Scan Folder", "/sls") + + hostname = self.client._hostname + start = hostname.find("x") + if start != -1: + beamline = hostname[start : start + 5] + active_account = self.client.active_account + start_folder = f"/sls/{beamline}/data/{active_account}/raw" + else: + start_folder = "/sls" + base_filepath = QFileDialog.getExistingDirectory(self, "Open Scan Folder", start_folder) if base_filepath != "": self.load_scan(base_filepath)