From df2157b6b957815432a2967a7ea9bea24c343112 Mon Sep 17 00:00:00 2001 From: NPS Agent Date: Mon, 11 May 2026 16:11:20 +0930 Subject: [PATCH] Added delete permantly button --- PROGRESS.md | 2 ++ api.js | 8 ++++++++ app.jsx | 14 +++++++++++++- backend/main.py | 13 +++++++++++-- dashy.db | Bin 61440 -> 69632 bytes screens.jsx | 12 +++++++++++- 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index c772762..b853887 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -52,6 +52,8 @@ 8. **Task Reopening:** Added a "Reopen task" button to restore accidentally closed tasks back to the queue. 9. **User Management (Settings):** Built backend API endpoints (`POST`, `PATCH`, `DELETE` for `/users`) and wired up the `WorkspaceTab` allowing Admins to manage the team from the UI. 10. **Task Editing:** Implemented inline editing for task descriptions using an active text box state with "Save/Cancel" actions. +11. **UI Cleanup:** Removed hardcoded, prototype placeholder notes from the `TaskDetail` modal to prepare for future dynamic notes integration. +12. **Permanent Deletion:** Added a "Delete task permanently" button to the `TaskDetail` sidebar with a confirmation dialog, backed by a new `DELETE /tasks/{id}` API endpoint. ### Phase 3: Advanced Features - **Real-time Notifications:** Explore WebSockets for task assignments. diff --git a/api.js b/api.js index b3a9744..355e77c 100644 --- a/api.js +++ b/api.js @@ -118,6 +118,14 @@ class ApiService { return data; } + async deleteTask(id) { + const data = await this.request(`/tasks/${id}`, { + method: 'DELETE', + }); + this.notify(); + return data; + } + async addAudit(auditData) { const data = await this.request('/audit', { method: 'POST', diff --git a/app.jsx b/app.jsx index 987bf82..26bff3a 100644 --- a/app.jsx +++ b/app.jsx @@ -166,6 +166,18 @@ function App() { } }; + const deleteTask = async (taskId) => { + try { + const t = tasks.find(x => x.id === taskId); + await api.deleteTask(taskId); + await api.addAudit({ actor: meId, action: 'task_deleted', summary: 'Deleted task' + (t ? ': ' + t.title : ''), target: taskId }); + setOpenTaskId(null); + } catch(e) { + console.error(e); + alert("Failed to delete task: " + e.message); + } + }; + const dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id)); const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); }; @@ -223,7 +235,7 @@ function App() { setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} /> {mappedOpenTask && ( - setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} /> + setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} onDeleteTask={() => deleteTask(mappedOpenTask.id)} /> )} {showLogs && ( setShowLogs(false)} wide> diff --git a/backend/main.py b/backend/main.py index c4bd706..f176752 100644 --- a/backend/main.py +++ b/backend/main.py @@ -118,15 +118,24 @@ def update_task(task_id: str, task_update: schemas.TaskUpdate, db: Session = Dep db_task = db.query(models.Task).filter(models.Task.id == task_id).first() if not db_task: raise HTTPException(status_code=404, detail="Task not found") - + update_data = task_update.dict(exclude_unset=True) for key, value in update_data.items(): setattr(db_task, key, value) - + db.commit() db.refresh(db_task) return db_task +@app.delete("/tasks/{task_id}") +def delete_task(task_id: str, db: Session = Depends(get_db)): + db_task = db.query(models.Task).filter(models.Task.id == task_id).first() + if not db_task: + raise HTTPException(status_code=404, detail="Task not found") + + db.delete(db_task) + db.commit() + return {"message": "Task deleted"} @app.get("/audit", response_model=List[schemas.AuditLog]) def read_audit(db: Session = Depends(get_db)): return db.query(models.AuditLog).order_by(models.AuditLog.at.desc()).all() diff --git a/dashy.db b/dashy.db index 5efd1e3047200c479bb5aa11f80569a5fa5ec538..3ddbe1a8e4065558ef03370becdd1697ecefe6f1 100644 GIT binary patch delta 979 zcmZ9LPiPZC6vii}*=UlT*Qg=13hvfQtR=F$+08#FwxSi0QUgUPNR#bmTS{zF)6iCG zLKQp|DsI?=LJ{jhs1*-wE?N}9i;99C#1;{eqMif~>ZQFnW15t7V0U>t-#3r=M{$1K`nVy+w8NN9l#@Lbc{4IOe^LwzgV;~&J?)#mXjXuo`weVTH&<$;L2`iFe(J2 zlHl5pJ{OCtW^R1mS->t{9HcUjd3d7FJTvLSqR0sfl`3JvqI7p+%+`j-k&BX|tEb+@ zd;DJN2_TeeVp%|u%*!0}%_jo=nc!#7xkSMV6-VV)#6s;m4U6zA(I^9{~YxAcv8Qp=k(->@`t1U wqMW%f=J$zR@)nWJVXr+(A|obKB1d&imNY>P^aiR#Di>m#MUE;Fb3LZ~1IP*cF#rGn delta 576 zcmXYuKWGzC9LMj>|K#rdn${4CmAcKHoQdzqPir_QlaW z=8AJ12Q7S&k8dX1Gaiv0&+`kG=f|zh)-Z1`{Je{%{Jl#t$-!Uv1>fN-sAvNng+265 zOd=OL3ArP*%4aptesS!9T^dZIB>6c+$)er zT`}dM!cIW(@A*r<1K(xuno#r(p|Tz6Gu-|4o4gn#brK#39S==&9F>;O0DtZQF)2>x zWi3apUNEtujTRKckPSVPS8{npC8jCoh_yZ6hbChe#$wUvX!LL_ zT3#3G916G*u_CljaFGB+k c;3K?&ZCGdYELe^A1tH)JhS}GL^jZ`D11`$4F#rGn diff --git a/screens.jsx b/screens.jsx index 50c1409..c90b559 100644 --- a/screens.jsx +++ b/screens.jsx @@ -407,7 +407,7 @@ function Modal({ children, onClose, title, eyebrow, wide = false }) { ); } -function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen, onEditDesc }) { +function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen, onEditDesc, onDeleteTask }) { const [editingDesc, setEditingDesc] = React.useState(false); const [descValue, setDescValue] = React.useState(task ? task.description || '' : ''); @@ -557,6 +557,16 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
Thu, May 7 ยท 4:00 pm
+ +
+ +