Add a "Clear all" button to the Layout tab's widget canvas
Build and push server image / test (push) Successful in 23s
Build and push server image / build-and-push (push) Successful in 2m1s
Build and push server image / deploy (push) Successful in 54s

One request (DELETE /api/frames/{id}/widgets) removes every widget on
the frame in a single locked transaction, cascading their configs and
button-action bindings the same way single-widget delete already does.
Gated behind confirm() like the existing per-widget remove button, and
disabled when there's nothing to clear. Covered by the same owner/
unrelated-user/linked-but-not-controlling permission shape used
elsewhere (test_widget_placement.py).

Also fixes a real, pre-existing mobile bug this surfaced: the Layout
page's .layout grid used a bare `1fr` track on the <860px breakpoint
instead of `minmax(0, 1fr)` like the desktop rule already does, so a
wide enough descendant (previously nothing hit this; the new title-row
button did) would force the whole page into horizontal scroll on phone
widths. Verified before/after with the run-server driver's new
`viewport` command.
This commit is contained in:
Thomas Faour
2026-07-25 01:32:25 +00:00
parent 0e35735a2a
commit 9f3f4b6f62
6 changed files with 110 additions and 3 deletions
+13
View File
@@ -222,6 +222,19 @@ def api_widget_delete(
return {"status": "deleted"}
@router.delete("/api/frames/{frame_id}/widgets")
def api_widgets_clear(frame: Frame = Depends(require_frame_control), db: Session = Depends(get_db)):
"""The Layout tab's "Clear all" button -- same per-widget cascade as
api_widget_delete, just every widget on this frame in one locked
transaction instead of one request per widget."""
with frame_locked(db, frame.id):
widgets = db.scalars(select(Widget).where(Widget.frame_id == frame.id)).all()
for widget in widgets:
db.delete(widget)
db.commit()
return {"status": "cleared", "count": len(widgets)}
# --- Per-widget-type config save (the gear-icon dialog's Save button) --------
@router.post("/api/frames/{frame_id}/widgets/{widget_id}/config")