feat: Add button deletion and GPIO pin modification to webapp
- Add DELETE endpoint for buttons with confirmation dialog - Add editable GPIO pin input fields in button list - Update PUT endpoint to handle both recipe and GPIO pin changes - Enhanced button management UI with delete buttons and inline editing - All changes use HTMX for seamless UI updates 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
21405819f0
commit
fb82972e98
@ -260,26 +260,76 @@ async def create_button(
|
|||||||
logger.error(f"Full traceback: {traceback.format_exc()}")
|
logger.error(f"Full traceback: {traceback.format_exc()}")
|
||||||
raise HTTPException(status_code=400, detail="Failed to create button")
|
raise HTTPException(status_code=400, detail="Failed to create button")
|
||||||
|
|
||||||
@app.put("/buttons/{button_id}")
|
@app.put("/buttons/{button_id}", response_class=HTMLResponse)
|
||||||
async def update_button(
|
async def update_button(
|
||||||
|
request: Request,
|
||||||
button_id: int,
|
button_id: int,
|
||||||
recipe_id: str = Form(""),
|
recipe_id: str = Form(""),
|
||||||
|
gpio_pin: Optional[int] = Form(None),
|
||||||
db: DatabaseManager = Depends(get_db)
|
db: DatabaseManager = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""Update button recipe mapping"""
|
"""Update button recipe mapping and/or GPIO pin"""
|
||||||
try:
|
try:
|
||||||
# Convert empty string to None, otherwise convert to int
|
# Convert empty string to None, otherwise convert to int
|
||||||
recipe_id_value = None if recipe_id == "" else int(recipe_id)
|
recipe_id_value = None if recipe_id == "" else int(recipe_id)
|
||||||
|
|
||||||
|
if gpio_pin is not None:
|
||||||
|
# Update both recipe and GPIO pin
|
||||||
|
db.execute_update(
|
||||||
|
"UPDATE buttons SET recipe_id = ?, gpio_pin = ? WHERE id = ?",
|
||||||
|
(recipe_id_value, gpio_pin, button_id)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Update only recipe
|
||||||
db.execute_update(
|
db.execute_update(
|
||||||
"UPDATE buttons SET recipe_id = ? WHERE id = ?",
|
"UPDATE buttons SET recipe_id = ? WHERE id = ?",
|
||||||
(recipe_id_value, button_id)
|
(recipe_id_value, button_id)
|
||||||
)
|
)
|
||||||
return {"status": "success"}
|
|
||||||
|
# Return updated button list
|
||||||
|
buttons = db.execute_query("""
|
||||||
|
SELECT b.*, r.name as recipe_name
|
||||||
|
FROM buttons b
|
||||||
|
LEFT JOIN recipes r ON b.recipe_id = r.id
|
||||||
|
ORDER BY b.name
|
||||||
|
""")
|
||||||
|
recipes = db.execute_query("SELECT * FROM recipes ORDER BY name")
|
||||||
|
return templates.TemplateResponse("partials/button_list.html", {
|
||||||
|
"request": request,
|
||||||
|
"buttons": buttons,
|
||||||
|
"recipes": recipes
|
||||||
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error updating button: {e}")
|
logger.error(f"Error updating button: {e}")
|
||||||
raise HTTPException(status_code=400, detail="Failed to update button")
|
raise HTTPException(status_code=400, detail="Failed to update button")
|
||||||
|
|
||||||
|
@app.delete("/buttons/{button_id}", response_class=HTMLResponse)
|
||||||
|
async def delete_button(
|
||||||
|
request: Request,
|
||||||
|
button_id: int,
|
||||||
|
db: DatabaseManager = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""Delete a button"""
|
||||||
|
try:
|
||||||
|
db.execute_update("DELETE FROM buttons WHERE id = ?", (button_id,))
|
||||||
|
|
||||||
|
# Return updated button list
|
||||||
|
buttons = db.execute_query("""
|
||||||
|
SELECT b.*, r.name as recipe_name
|
||||||
|
FROM buttons b
|
||||||
|
LEFT JOIN recipes r ON b.recipe_id = r.id
|
||||||
|
ORDER BY b.name
|
||||||
|
""")
|
||||||
|
recipes = db.execute_query("SELECT * FROM recipes ORDER BY name")
|
||||||
|
return templates.TemplateResponse("partials/button_list.html", {
|
||||||
|
"request": request,
|
||||||
|
"buttons": buttons,
|
||||||
|
"recipes": recipes
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deleting button: {e}")
|
||||||
|
raise HTTPException(status_code=400, detail="Failed to delete button")
|
||||||
|
|
||||||
# Shot history routes
|
# Shot history routes
|
||||||
@app.get("/shots", response_class=HTMLResponse)
|
@app.get("/shots", response_class=HTMLResponse)
|
||||||
async def list_shots(request: Request, db: DatabaseManager = Depends(get_db)):
|
async def list_shots(request: Request, db: DatabaseManager = Depends(get_db)):
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>GPIO Pin</th>
|
<th>GPIO Pin</th>
|
||||||
<th>Recipe</th>
|
<th>Recipe</th>
|
||||||
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -12,7 +13,17 @@
|
|||||||
{% for button in buttons %}
|
{% for button in buttons %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ button.name }}</td>
|
<td>{{ button.name }}</td>
|
||||||
<td>GPIO {{ button.gpio_pin }}</td>
|
<td>
|
||||||
|
<div class="input-group input-group-sm" style="width: 120px;">
|
||||||
|
<span class="input-group-text">GPIO</span>
|
||||||
|
<input type="number" class="form-control"
|
||||||
|
value="{{ button.gpio_pin }}"
|
||||||
|
min="0" max="40"
|
||||||
|
hx-put="/buttons/{{ button.id }}"
|
||||||
|
hx-trigger="change"
|
||||||
|
name="gpio_pin">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="form-select form-select-sm"
|
<select class="form-select form-select-sm"
|
||||||
hx-put="/buttons/{{ button.id }}"
|
hx-put="/buttons/{{ button.id }}"
|
||||||
@ -32,6 +43,16 @@
|
|||||||
{{ 'Configured' if button.recipe_name else 'Not Configured' }}
|
{{ 'Configured' if button.recipe_name else 'Not Configured' }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger btn-sm"
|
||||||
|
hx-delete="/buttons/{{ button.id }}"
|
||||||
|
hx-target="#button-list"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
hx-confirm="Are you sure you want to delete this button?"
|
||||||
|
title="Delete Button">
|
||||||
|
<i class="bi bi-trash"></i> Delete
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user