wip
This commit is contained in:
@@ -46,7 +46,7 @@ def index_of(items: list[ScheduleItem], item_id: str | None) -> int | None:
|
||||
|
||||
|
||||
def pick_next_runnable(
|
||||
items: list[ScheduleItem], repeat_aborted_item
|
||||
items: list[ScheduleItem], repeat_aborted_item, first_item: int = 0
|
||||
) -> ScheduleItem | Literal["stop"] | None:
|
||||
"""
|
||||
What the execution loop should do next: always re-derived from scratch
|
||||
@@ -57,9 +57,13 @@ def pick_next_runnable(
|
||||
earlier item failed/was aborted (execution stays parked there until the
|
||||
operator intervenes), or `None` if every item is COMPLETED.
|
||||
"""
|
||||
logger.info(f"pick next runnable, repeat abort item is {repeat_aborted_item}")
|
||||
for item in items:
|
||||
logger.info(
|
||||
f"pick next runnable, repeat abort item is {repeat_aborted_item} and first item is {first_item}"
|
||||
)
|
||||
for idx, item in enumerate(items):
|
||||
logger.info(f"item: {item}")
|
||||
if idx < first_item:
|
||||
continue
|
||||
if item.status == ScheduleItemStatus.COMPLETED:
|
||||
continue
|
||||
if item.status == ScheduleItemStatus.ABORTED:
|
||||
|
||||
@@ -460,14 +460,16 @@ class Scheduler(BECWidget, QWidget):
|
||||
|
||||
run_row = QHBoxLayout()
|
||||
self.run_btn = MyButton("Run / Continue", "success")
|
||||
self.abort_btn = MyButton("Abort", "emergency")
|
||||
self.reset_btn = MyButton("Reset", "warning")
|
||||
for button in (self.run_btn, self.abort_btn, self.reset_btn):
|
||||
self.run_from_current_btn = MyButton("Run / Continue from current selection", "success")
|
||||
self.abort_btn = MyButton("Pause after current item", "emergency")
|
||||
self.reset_btn = MyButton("Reset Schedule Status", "warning")
|
||||
for button in (self.run_btn, self.run_from_current_btn, self.abort_btn, self.reset_btn):
|
||||
run_row.addWidget(button)
|
||||
run_row.addStretch()
|
||||
control_layout.addLayout(run_row)
|
||||
|
||||
self.run_btn.clicked.connect(self.run_schedule)
|
||||
self.run_from_current_btn.connect(self.run_schedule_from_selection)
|
||||
self.abort_btn.clicked.connect(self.abort_schedule)
|
||||
self.reset_btn.clicked.connect(self.reset_schedule)
|
||||
|
||||
@@ -660,8 +662,10 @@ class Scheduler(BECWidget, QWidget):
|
||||
row = self._table_model.row_of(self._selected_item_id)
|
||||
if row is not None:
|
||||
self.table_view.selectRow(row)
|
||||
self.run_from_current_btn.setEnabled(True)
|
||||
else:
|
||||
self._selected_item_id = None
|
||||
self.run_from_current_btn.setEnabled(False)
|
||||
|
||||
selection_model.blockSignals(False)
|
||||
|
||||
@@ -722,6 +726,13 @@ class Scheduler(BECWidget, QWidget):
|
||||
self.copy_btn.setEnabled(selected_item is not None)
|
||||
self.paste_btn.setEnabled(self._clipboard_item is not None)
|
||||
|
||||
# Update execution control buttons
|
||||
state = self._current_report is None # True if schedule is not running
|
||||
self.run_btn.setEnabled(state)
|
||||
self.run_from_current_btn.setEnabled(state)
|
||||
self.abort_btn.setEnabled(not state)
|
||||
self.reset_btn.setEnabled(state)
|
||||
|
||||
@SafeSlot()
|
||||
def _on_schedule_name_change(self):
|
||||
name = self.schedule_name_input.text()
|
||||
@@ -1103,7 +1114,7 @@ class Scheduler(BECWidget, QWidget):
|
||||
# RPC-exposed actions (USER_ACCESS)
|
||||
# ------------------------------------------------------------------ #
|
||||
@SafeSlot()
|
||||
def run_schedule(self):
|
||||
def run_schedule(self, first_item: int = 0):
|
||||
"""Run the schedule, continuing from wherever it last left off."""
|
||||
with self._lock:
|
||||
if self.schedule.is_running:
|
||||
@@ -1126,9 +1137,21 @@ class Scheduler(BECWidget, QWidget):
|
||||
self.submit_task(
|
||||
self._run_all,
|
||||
repeat_aborted_item,
|
||||
first_item,
|
||||
on_complete=self._on_run_finished,
|
||||
on_failed=self._on_run_failed,
|
||||
)
|
||||
self._refresh_ui()
|
||||
|
||||
@SafeSlot()
|
||||
def run_schedule_from_selection(self):
|
||||
"""Run the schedule, starting from the current selected item."""
|
||||
if self._selected_item_id is None:
|
||||
return
|
||||
with self._lock:
|
||||
idx = self._index_of_locked(self._selected_item_id)
|
||||
if idx is not None:
|
||||
self.run_schedule(idx)
|
||||
|
||||
@SafeSlot()
|
||||
def abort_schedule(self):
|
||||
@@ -1314,9 +1337,9 @@ class Scheduler(BECWidget, QWidget):
|
||||
# the `schedule_changed` Qt signal so they are marshalled back onto
|
||||
# the GUI thread instead of touching widgets directly)
|
||||
# ------------------------------------------------------------------ #
|
||||
def _pick_next_runnable_locked(self, repeat_aborted_item):
|
||||
def _pick_next_runnable_locked(self, repeat_aborted_item, first_item):
|
||||
"""Must be called while holding `self._lock`; see `schedule_logic.pick_next_runnable`."""
|
||||
return pick_next_runnable(self.schedule.items, repeat_aborted_item)
|
||||
return pick_next_runnable(self.schedule.items, repeat_aborted_item, first_item)
|
||||
|
||||
@SafeSlot()
|
||||
def _on_run_finished(self):
|
||||
@@ -1356,7 +1379,7 @@ class Scheduler(BECWidget, QWidget):
|
||||
|
||||
super().cleanup()
|
||||
|
||||
def _run_all(self, repeat_aborted_item):
|
||||
def _run_all(self, repeat_aborted_item, first_item):
|
||||
notify_schedule_state(
|
||||
self.client, self.schedule.notifications, self.schedule.schedule_name, "started"
|
||||
)
|
||||
@@ -1369,7 +1392,7 @@ class Scheduler(BECWidget, QWidget):
|
||||
}
|
||||
while not self._abort_requested and not self._closing.is_set():
|
||||
with self._lock:
|
||||
next_item = self._pick_next_runnable_locked(repeat_aborted_item)
|
||||
next_item = self._pick_next_runnable_locked(repeat_aborted_item, first_item)
|
||||
if next_item is None or next_item == "stop":
|
||||
logger.info("Next item is None or stop")
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user