[fix](trx-frontend-http): reset scheduler step timing
Track the last applied scheduler entry so previous/next\ncycles correctly across active entries and resets the\ncountdown after manual entry changes.\n\nVerification: cargo test -p trx-frontend-http scheduler\nVerification: node --check assets/web/plugins/scheduler.js\n\nCo-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
let schedulerRole = null; // "control" | "rx" | null
|
let schedulerRole = null; // "control" | "rx" | null
|
||||||
let currentRigId = null;
|
let currentRigId = null;
|
||||||
let currentConfig = null;
|
let currentConfig = null;
|
||||||
|
let currentSchedulerStatus = null;
|
||||||
let bookmarkList = []; // [{id, name, freq_hz, mode}, ...]
|
let bookmarkList = []; // [{id, name, freq_hz, mode}, ...]
|
||||||
let statusInterval = null;
|
let statusInterval = null;
|
||||||
let interleaveTicker = null;
|
let interleaveTicker = null;
|
||||||
@@ -211,6 +212,30 @@
|
|||||||
if (!(cycleMin > 0)) {
|
if (!(cycleMin > 0)) {
|
||||||
return { activeEntries: active, currentIndex: 0, remainingSec: 0, cycleMin: 0 };
|
return { activeEntries: active, currentIndex: 0, remainingSec: 0, cycleMin: 0 };
|
||||||
}
|
}
|
||||||
|
const statusEntryId = currentSchedulerStatus && currentSchedulerStatus.last_entry_id
|
||||||
|
? String(currentSchedulerStatus.last_entry_id)
|
||||||
|
: "";
|
||||||
|
const statusIndex = statusEntryId
|
||||||
|
? active.findIndex(function (entry) { return String(entry && entry.id || "") === statusEntryId; })
|
||||||
|
: -1;
|
||||||
|
const statusAppliedUtc = currentSchedulerStatus && Number.isFinite(Number(currentSchedulerStatus.last_applied_utc))
|
||||||
|
? Number(currentSchedulerStatus.last_applied_utc)
|
||||||
|
: null;
|
||||||
|
if (statusIndex >= 0 && statusAppliedUtc != null) {
|
||||||
|
const manualDurationMin = durations[statusIndex];
|
||||||
|
const elapsedSec = Math.max(0, schedulerUtcSeconds() - statusAppliedUtc);
|
||||||
|
const remainingSec = (manualDurationMin > 0)
|
||||||
|
? Math.max(1, (manualDurationMin * 60) - elapsedSec)
|
||||||
|
: 0;
|
||||||
|
if (remainingSec > 0) {
|
||||||
|
return {
|
||||||
|
activeEntries: active,
|
||||||
|
currentIndex: statusIndex,
|
||||||
|
remainingSec: remainingSec,
|
||||||
|
cycleMin: cycleMin,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
const overlapStart = active.reduce(function (maxStart, entry) {
|
const overlapStart = active.reduce(function (maxStart, entry) {
|
||||||
return Math.max(maxStart, schedulerEntryCurrentWindowStart(entry, nowMin));
|
return Math.max(maxStart, schedulerEntryCurrentWindowStart(entry, nowMin));
|
||||||
}, Number.NEGATIVE_INFINITY);
|
}, Number.NEGATIVE_INFINITY);
|
||||||
@@ -285,7 +310,9 @@
|
|||||||
if (!rig) return;
|
if (!rig) return;
|
||||||
apiGetStatus(rig)
|
apiGetStatus(rig)
|
||||||
.then(function (st) {
|
.then(function (st) {
|
||||||
|
currentSchedulerStatus = st || null;
|
||||||
renderStatus(st);
|
renderStatus(st);
|
||||||
|
renderSchedulerInterleaveStatus();
|
||||||
})
|
})
|
||||||
.catch(function () {});
|
.catch(function () {});
|
||||||
}
|
}
|
||||||
@@ -297,7 +324,13 @@
|
|||||||
el.textContent = "No activity yet.";
|
el.textContent = "No activity yet.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const name = st.last_bookmark_name || st.last_bookmark_id || "—";
|
const statusEntryId = st.last_entry_id ? String(st.last_entry_id) : "";
|
||||||
|
const entry = statusEntryId && currentConfig && Array.isArray(currentConfig.entries)
|
||||||
|
? currentConfig.entries.find(function (item) { return String(item && item.id || "") === statusEntryId; })
|
||||||
|
: null;
|
||||||
|
const name = entry
|
||||||
|
? schedulerEntryDisplayName(entry)
|
||||||
|
: (st.last_bookmark_name || st.last_bookmark_id || "—");
|
||||||
let ts = "";
|
let ts = "";
|
||||||
if (st.last_applied_utc) {
|
if (st.last_applied_utc) {
|
||||||
const d = new Date(st.last_applied_utc * 1000);
|
const d = new Date(st.last_applied_utc * 1000);
|
||||||
@@ -489,6 +522,7 @@
|
|||||||
return apiActivateSchedulerEntry(currentRigId, target.id);
|
return apiActivateSchedulerEntry(currentRigId, target.id);
|
||||||
})
|
})
|
||||||
.then(function (status) {
|
.then(function (status) {
|
||||||
|
currentSchedulerStatus = status || null;
|
||||||
renderStatus(status);
|
renderStatus(status);
|
||||||
renderSchedulerInterleaveStatus();
|
renderSchedulerInterleaveStatus();
|
||||||
showSchedulerToast("Selected " + schedulerEntryDisplayName(target) + ".");
|
showSchedulerToast("Selected " + schedulerEntryDisplayName(target) + ".");
|
||||||
|
|||||||
@@ -398,6 +398,8 @@ fn utc_minutes_now() -> f64 {
|
|||||||
#[derive(Debug, Clone, Serialize, Default)]
|
#[derive(Debug, Clone, Serialize, Default)]
|
||||||
pub struct SchedulerStatus {
|
pub struct SchedulerStatus {
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub last_entry_id: Option<String>,
|
||||||
pub last_bookmark_id: Option<String>,
|
pub last_bookmark_id: Option<String>,
|
||||||
pub last_bookmark_name: Option<String>,
|
pub last_bookmark_name: Option<String>,
|
||||||
pub last_applied_utc: Option<i64>,
|
pub last_applied_utc: Option<i64>,
|
||||||
@@ -414,6 +416,7 @@ async fn apply_scheduler_target(
|
|||||||
rig_id: &str,
|
rig_id: &str,
|
||||||
status_map: &SchedulerStatusMap,
|
status_map: &SchedulerStatusMap,
|
||||||
bookmarks: &BookmarkStore,
|
bookmarks: &BookmarkStore,
|
||||||
|
entry_id: Option<&str>,
|
||||||
bookmark_id: &str,
|
bookmark_id: &str,
|
||||||
center_hz: Option<u64>,
|
center_hz: Option<u64>,
|
||||||
extra_bm_ids: &[String],
|
extra_bm_ids: &[String],
|
||||||
@@ -456,6 +459,7 @@ async fn apply_scheduler_target(
|
|||||||
|
|
||||||
let status = SchedulerStatus {
|
let status = SchedulerStatus {
|
||||||
active: true,
|
active: true,
|
||||||
|
last_entry_id: entry_id.map(str::to_string),
|
||||||
last_bookmark_id: Some(bookmark_id.to_string()),
|
last_bookmark_id: Some(bookmark_id.to_string()),
|
||||||
last_bookmark_name: Some(bookmark.name.clone()),
|
last_bookmark_name: Some(bookmark.name.clone()),
|
||||||
last_applied_utc: Some(
|
last_applied_utc: Some(
|
||||||
@@ -586,7 +590,7 @@ pub fn spawn_scheduler_task(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (bm_id, center_hz, extra_bm_ids) = match &config.mode {
|
let (entry_id, bm_id, center_hz, extra_bm_ids) = match &config.mode {
|
||||||
SchedulerMode::Disabled => continue,
|
SchedulerMode::Disabled => continue,
|
||||||
SchedulerMode::Grayline => {
|
SchedulerMode::Grayline => {
|
||||||
let Some(bm_id) = config
|
let Some(bm_id) = config
|
||||||
@@ -596,7 +600,7 @@ pub fn spawn_scheduler_task(
|
|||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
(bm_id, None, Vec::new())
|
(None, bm_id, None, Vec::new())
|
||||||
}
|
}
|
||||||
SchedulerMode::TimeSpan => {
|
SchedulerMode::TimeSpan => {
|
||||||
let Some(entry) =
|
let Some(entry) =
|
||||||
@@ -605,6 +609,7 @@ pub fn spawn_scheduler_task(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
|
Some(entry.id.clone()),
|
||||||
entry.bookmark_id.clone(),
|
entry.bookmark_id.clone(),
|
||||||
entry.center_hz,
|
entry.center_hz,
|
||||||
entry.bookmark_ids.clone(),
|
entry.bookmark_ids.clone(),
|
||||||
@@ -641,6 +646,7 @@ pub fn spawn_scheduler_task(
|
|||||||
&config.rig_id,
|
&config.rig_id,
|
||||||
&status_map,
|
&status_map,
|
||||||
&bookmarks,
|
&bookmarks,
|
||||||
|
entry_id.as_deref(),
|
||||||
&bm_id,
|
&bm_id,
|
||||||
center_hz,
|
center_hz,
|
||||||
&extra_bm_ids,
|
&extra_bm_ids,
|
||||||
@@ -731,6 +737,7 @@ async fn apply_last_scheduler_cycle(
|
|||||||
rig_id,
|
rig_id,
|
||||||
status_map,
|
status_map,
|
||||||
bookmarks,
|
bookmarks,
|
||||||
|
status.last_entry_id.as_deref(),
|
||||||
&bookmark_id,
|
&bookmark_id,
|
||||||
status.last_center_hz,
|
status.last_center_hz,
|
||||||
&status.last_bookmark_ids,
|
&status.last_bookmark_ids,
|
||||||
@@ -858,6 +865,7 @@ pub async fn put_scheduler_activate_entry(
|
|||||||
&rig_id,
|
&rig_id,
|
||||||
status_map.get_ref(),
|
status_map.get_ref(),
|
||||||
bookmarks.get_ref().as_ref(),
|
bookmarks.get_ref().as_ref(),
|
||||||
|
Some(&entry.id),
|
||||||
&entry.bookmark_id,
|
&entry.bookmark_id,
|
||||||
entry.center_hz,
|
entry.center_hz,
|
||||||
&entry.bookmark_ids,
|
&entry.bookmark_ids,
|
||||||
|
|||||||
Reference in New Issue
Block a user