This commit is contained in:
firestar5683
2026-07-16 14:33:52 -05:00
parent 5a7ec6b154
commit c6708e716f
4 changed files with 110 additions and 1 deletions
@@ -36,6 +36,7 @@ const state = reactive({
fetched: false,
activeSectionSlug: "",
numericUpdating: {},
actionUpdating: {},
favoriteLoading: false,
favoriteSaving: false,
favoriteOptions: [],
@@ -860,6 +861,35 @@ async function resetNumericParam(param) {
})
}
async function runSettingAction(param) {
const key = String(param?.key || "")
const endpoint = String(param?.action_endpoint || "")
if (!key || !endpoint || state.actionUpdating[key]) return
const confirmation = String(param?.confirm_message || `Run ${param?.label || key}?`)
if (!window.confirm(confirmation)) return
state.actionUpdating = { ...state.actionUpdating, [key]: true }
try {
const response = await fetch(endpoint, { method: "POST" })
const payload = await response.json()
if (!response.ok) {
throw new Error(payload.error || response.statusText || "Action failed")
}
const updated = payload.updated && typeof payload.updated === "object" ? payload.updated : {}
state.values = { ...state.values, ...updated }
showParamSnackbar(payload.message || `${param?.label || key} completed.`)
scheduleSyncInputs()
} catch (error) {
showParamSnackbar(error?.message || `${param?.label || key} failed.`, "error")
} finally {
const next = { ...state.actionUpdating }
delete next[key]
state.actionUpdating = next
}
}
async function updateParam(key, elType) {
if (String(key).toLowerCase() === "starpilotfavoriteslots") {
await saveFavoriteSlots(state.favoriteSlots)
@@ -1230,6 +1260,7 @@ function renderSettingRow(p) {
const isNumeric = p.ui_type === "numeric"
const isColor = p.ui_type === "color"
const isAction = p.ui_type === "action"
const isGroup = isGroupParam(p)
const isChild = p.parent_key ? "ds-child-modifier" : ""
const lockReason = () => getSettingLockReason(p)
@@ -1238,7 +1269,16 @@ function renderSettingRow(p) {
const flmTrialSummary = p.key === "AdvancedLateralTune" ? getFlmTrialSummary() : null
let rowControl = ""
if (isNumeric) {
if (isAction) {
rowControl = html`
<button
class="ds-reset-btn"
disabled="${() => isLocked() || !!state.actionUpdating[p.key]}"
@click="${() => runSettingAction(p)}">
${() => state.actionUpdating[p.key] ? "Resetting..." : (p.action_label || "Run")}
</button>
`
} else if (isNumeric) {
rowControl = html`
<div class="ds-stepper-container">
${(() => {
@@ -626,6 +626,16 @@
"ui_type": "toggle",
"parent_key": "CurveSpeedController"
},
{
"key": "ResetCurveData",
"label": "Reset Curve Data",
"description": "Clear learned Curve Speed Controller data and begin training again from the default lateral acceleration.",
"ui_type": "action",
"action_label": "Reset",
"action_endpoint": "/api/curve_speed_controller/reset",
"confirm_message": "Reset all learned Curve Speed Controller data? Training will restart from the default value.",
"parent_key": "CurveSpeedController"
},
{
"key": "CustomPersonalities",
"label": "Driving Personalities",
@@ -47,6 +47,7 @@ class WritableFakeParams:
def __init__(self, values=None):
self.values = dict(values or {})
self.writes = []
self.removals = []
def get(self, key, encoding=None, default=None, block=False):
del encoding, block
@@ -66,6 +67,10 @@ class WritableFakeParams:
self.writes.append((key, bool(value)))
self.values[key] = bool(value)
def remove(self, key):
self.removals.append(key)
self.values.pop(key, None)
def _params_client(monkeypatch, values, device_type):
fake_params = WritableFakeParams(values)
@@ -236,3 +241,40 @@ def test_legacy_try_raylib_ui_payload_updates_use_old_ui(monkeypatch):
assert fake_params.values["UseOldUI"] is False
assert fake_params.values["TryRaylibUI"] is True
assert fake_params.writes == [("UseOldUI", False), ("TryRaylibUI", True)]
def test_curve_speed_controller_reset_clears_learned_data_offroad(monkeypatch):
client, fake_params = _params_client(monkeypatch, {
"IsOnroad": False,
"CalibratedLateralAcceleration": 2.73,
"CalibrationProgress": 48.0,
"CurvatureData": {"0.01": {"average": 2.73, "count": 12}},
}, "tici")
response = client.post("/api/curve_speed_controller/reset")
assert response.status_code == 200
assert response.get_json()["updated"] == {
"CalibratedLateralAcceleration": 2.0,
"CalibrationProgress": 0.0,
}
assert fake_params.values["CalibratedLateralAcceleration"] == 2.0
assert "CalibrationProgress" not in fake_params.values
assert "CurvatureData" not in fake_params.values
assert fake_params.removals == ["CalibrationProgress", "CurvatureData"]
def test_curve_speed_controller_reset_rejected_onroad(monkeypatch):
client, fake_params = _params_client(monkeypatch, {
"IsOnroad": True,
"CalibratedLateralAcceleration": 2.73,
"CalibrationProgress": 48.0,
"CurvatureData": {"0.01": {"average": 2.73, "count": 12}},
}, "tici")
response = client.post("/api/curve_speed_controller/reset")
assert response.status_code == 403
assert response.get_json()["error"] == "Curve Speed Controller data can only be reset while parked."
assert fake_params.writes == []
assert fake_params.removals == []
+17
View File
@@ -4539,6 +4539,23 @@ def setup(app):
return canonical_model_key(str(value).strip()), 200
return value, 200
@app.route("/api/curve_speed_controller/reset", methods=["POST"])
def reset_curve_speed_controller_data():
if params.get_bool("IsOnroad"):
return jsonify({"error": "Curve Speed Controller data can only be reset while parked."}), 403
params.put("CalibratedLateralAcceleration", 2.0)
params.remove("CalibrationProgress")
params.remove("CurvatureData")
return jsonify({
"message": "Curve Speed Controller data reset. Training will restart on the next drive.",
"updated": {
"CalibratedLateralAcceleration": 2.0,
"CalibrationProgress": 0.0,
},
}), 200
@app.route("/api/params/all", methods=["GET"])
def get_all_params():
migrate_cancel_button_controls(params)