Added delete permantly button
This commit is contained in:
@@ -52,6 +52,8 @@
|
|||||||
8. **Task Reopening:** Added a "Reopen task" button to restore accidentally closed tasks back to the queue.
|
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.
|
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.
|
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
|
### Phase 3: Advanced Features
|
||||||
- **Real-time Notifications:** Explore WebSockets for task assignments.
|
- **Real-time Notifications:** Explore WebSockets for task assignments.
|
||||||
|
|||||||
@@ -118,6 +118,14 @@ class ApiService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteTask(id) {
|
||||||
|
const data = await this.request(`/tasks/${id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
this.notify();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
async addAudit(auditData) {
|
async addAudit(auditData) {
|
||||||
const data = await this.request('/audit', {
|
const data = await this.request('/audit', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -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 dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id));
|
||||||
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
|
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
|
||||||
|
|
||||||
@@ -223,7 +235,7 @@ function App() {
|
|||||||
|
|
||||||
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} />
|
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} />
|
||||||
{mappedOpenTask && (
|
{mappedOpenTask && (
|
||||||
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} />
|
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => 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 && (
|
{showLogs && (
|
||||||
<Modal title="Audit log" onClose={() => setShowLogs(false)} wide>
|
<Modal title="Audit log" onClose={() => setShowLogs(false)} wide>
|
||||||
|
|||||||
@@ -127,6 +127,15 @@ def update_task(task_id: str, task_update: schemas.TaskUpdate, db: Session = Dep
|
|||||||
db.refresh(db_task)
|
db.refresh(db_task)
|
||||||
return 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])
|
@app.get("/audit", response_model=List[schemas.AuditLog])
|
||||||
def read_audit(db: Session = Depends(get_db)):
|
def read_audit(db: Session = Depends(get_db)):
|
||||||
return db.query(models.AuditLog).order_by(models.AuditLog.at.desc()).all()
|
return db.query(models.AuditLog).order_by(models.AuditLog.at.desc()).all()
|
||||||
|
|||||||
+11
-1
@@ -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 [editingDesc, setEditingDesc] = React.useState(false);
|
||||||
const [descValue, setDescValue] = React.useState(task ? task.description || '' : '');
|
const [descValue, setDescValue] = React.useState(task ? task.description || '' : '');
|
||||||
|
|
||||||
@@ -557,6 +557,16 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
|
|||||||
<Field label="Reminder">
|
<Field label="Reminder">
|
||||||
<div className="meta-row">Thu, May 7 · 4:00 pm</div>
|
<div className="meta-row">Thu, May 7 · 4:00 pm</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
<div style={{ marginTop: '2rem', paddingTop: '1.5rem', borderTop: '1px solid var(--border-subtle)' }}>
|
||||||
|
<button
|
||||||
|
className="btn btn--ghost btn--full"
|
||||||
|
style={{ color: 'var(--prio-high-dot)', borderColor: 'transparent' }}
|
||||||
|
onClick={() => { if (confirm('Are you sure you want to permanently delete this task?')) onDeleteTask(); }}
|
||||||
|
>
|
||||||
|
<Icon.Close /> Delete task permanently
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Reference in New Issue
Block a user