diff --git a/daq/src/aaredaq/server.py b/daq/src/aaredaq/server.py index c8ce9bf1..fa8cc974 100644 --- a/daq/src/aaredaq/server.py +++ b/daq/src/aaredaq/server.py @@ -26,8 +26,6 @@ from aaredaq.daq import AareDAQ from aaredaq.camera_stat_thread import start_image_stats_receiver, stop_image_stats_receiver -from aaregui.panels.reference_tools_panel import ReferenceToolsModel - app = FastAPI() # OAuth2 setup @@ -246,6 +244,13 @@ def get_spreadsheet(data: TokenData) -> SampleShortInfoList: def get_reference_tools() -> SampleShortInfoList: return cfg.reference_tools +async def reference_tools_event_stream() -> AsyncGenerator[str, None]: + try: + while True: + yield get_reference_tools().model_dump_json() + await asyncio.sleep(10) + except asyncio.CancelledError: + return async def spreadsheet_event_stream(data: TokenData) -> AsyncGenerator[str, None]: try: @@ -270,6 +275,18 @@ async def spreadsheet_sse(token: str = Depends(oauth2_scheme)): } ) +@app.get("/sse/reference_tools") +async def reference_tools_sse(): + return StreamingResponse( + reference_tools_event_stream(), + media_type="text/event-stream", + headers={ + "Cache-Control": "no-cache", + "Connection": "keep-alive", + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Cache-Control" + } + ) @app.get("/sample/spreadsheet") async def spreadsheet(token: str = Depends(oauth2_scheme)) -> SampleShortInfoList: diff --git a/gui/src/aaregui/panels/reference_tools_panel.py b/gui/src/aaregui/panels/reference_tools_panel.py index 6f832a32..2787da3c 100644 --- a/gui/src/aaregui/panels/reference_tools_panel.py +++ b/gui/src/aaregui/panels/reference_tools_panel.py @@ -14,11 +14,14 @@ from PySide6.QtWidgets import ( ) from aaredaqlib.models import SampleShortInfoList, SampleShortInfo, BeamlineStateEnum - class ReferenceToolsModel(QAbstractTableModel): - def __init__(self, rows: Optional[List[SampleShortInfo]] = None, parent=None): + def __init__(self, rows: Optional[list[SampleShortInfo]] | None = None, parent=None, current_reference: int | None = None,): super().__init__(parent) - self._rows: List[SampleShortInfo] = rows or [] + self._rows: list[SampleShortInfo] = rows or [] + self.current_reference = current_reference + self.__sort_col = 1 + self.__sort_order = Qt.SortOrder.AscendingOrder + self._sort() def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: return len(self._rows) @@ -26,8 +29,8 @@ class ReferenceToolsModel(QAbstractTableModel): def columnCount(self, parent: QModelIndex = QModelIndex()) -> int: return 3 # position, sample_name, mount_count - def data(self, index: QModelIndex, role: int = Qt.DisplayRole): - if not index.isValid() or role != Qt.DisplayRole: + def data(self, index: QModelIndex, role=None): + if not index.isValid() or role != Qt.ItemDataRole.DisplayRole: return None s: SampleShortInfo = self._rows[index.row()] if index.column() == 0: @@ -39,22 +42,39 @@ class ReferenceToolsModel(QAbstractTableModel): return str(getattr(s, "mount_count", 0)) return None - def headerData(self, section: int, orientation, role: int = Qt.DisplayRole): - if role != Qt.DisplayRole: + def headerData(self, section: int, orientation, role=None): + if role != Qt.ItemDataRole.DisplayRole: return None - if orientation == Qt.Horizontal: + if orientation == Qt.Orientation.Horizontal: return ("position", "sample_name", "mount_count")[section] return str(section + 1) - def update_rows(self, rows: List[SampleShortInfo]): + def update_rows(self, rows: list[SampleShortInfo]): self.beginResetModel() self._rows = rows self.endResetModel() + def sort(self, column, order): + self.layoutAboutToBeChanged.emit() + self.__sort_order = order + self.__sort_col = column + self._sort() + self.layoutChanged.emit() + + def _sort(self): + self.__sorted_samples = sorted( + self._rows, + key=lambda row: row[0], + reverse=( + self.__sort_order == Qt.SortOrder.AscendingOrder + ), # Reverse for descending order + ) + def get_item(self, row: int) -> Optional[SampleShortInfo]: try: return self._rows[row] - except Exception: + except Exception as e: + print(e) return None class ReferenceToolsPanel(QFrame): @@ -81,12 +101,17 @@ class ReferenceToolsPanel(QFrame): layout.addWidget(QLabel("Reference tools", parent=self), 0, 0, 1, 2) self.table_view = QTableView(parent=self) + # initialize model with provided samples - self.table_model = ReferenceToolsModel(samples.s) + self.table_model = ReferenceToolsModel(rows=samples.s) self.table_view.setModel(self.table_model) + self.table_view.verticalHeader().setVisible(False) + header = self.table_view.horizontalHeader() header.setSectionResizeMode(QHeaderView.ResizeMode.Interactive) header.setStretchLastSection(True) + + self.table_view.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows) self.table_view.setSelectionMode(QTableView.SelectionMode.SingleSelection) self.table_view.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) @@ -98,10 +123,10 @@ class ReferenceToolsPanel(QFrame): layout.addWidget(self.unmount_button, 2, 0) self.unmount_button.clicked.connect(self._on_unmount_clicked) - self._timer = QTimer(self) - self._timer.setInterval(refresh_interval_ms) - self._timer.timeout.connect(self.request_refresh) # implement to call DAQ/adapter - self._timer.start() + # self._timer = QTimer(self) + # self._timer.setInterval(refresh_interval_ms) + # self._timer.timeout.connect() # implement to call DAQ/adapter + # self._timer.start() def _selected_item(self) -> Optional[SampleShortInfo]: idx = self.table_view.currentIndex() @@ -131,6 +156,6 @@ class ReferenceToolsPanel(QFrame): self.unmount.emit(item) @Slot(SampleShortInfoList) - def new_list(self, lst: SampleShortInfoList): + def new_list(self, samples: SampleShortInfoList): # signal from DAQWorker will call this with the model - self.table_model.update_rows(lst.s) \ No newline at end of file + self.table_model.update_rows(rows=samples.s) \ No newline at end of file