Adding delete job. Form not working yet.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, Request, Form, UploadFile, File
|
from fastapi import APIRouter, Depends, HTTPException, Request, Form, UploadFile, File, status
|
||||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||||
from typing import List, Optional, Union, Tuple, Dict, Any
|
from typing import List, Optional, Union, Tuple, Dict, Any
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -136,6 +136,39 @@ async def get_job_detail(
|
|||||||
|
|
||||||
return summaries
|
return summaries
|
||||||
|
|
||||||
|
@router.delete("/jobs/{job_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
async def delete_job(
|
||||||
|
job_id: int,
|
||||||
|
db: DbDependency,
|
||||||
|
current_user: HttpUser = Depends(get_current_http_user),
|
||||||
|
):
|
||||||
|
username = current_user.username.upper().strip()
|
||||||
|
|
||||||
|
with db.transaction() as conn:
|
||||||
|
root = conn.root
|
||||||
|
|
||||||
|
# 1. Check if job exists
|
||||||
|
if job_id not in root.jobs:
|
||||||
|
raise HTTPException(status_code=404, detail="Job not found")
|
||||||
|
|
||||||
|
job = root.jobs[job_id]
|
||||||
|
|
||||||
|
# 2. Ownership check
|
||||||
|
if job.owner.upper() != username:
|
||||||
|
raise HTTPException(status_code=403, detail="You do not own this job")
|
||||||
|
|
||||||
|
# 3. Remove from user's job list
|
||||||
|
if username in root.user_jobs:
|
||||||
|
user_job_list = root.user_jobs[username]
|
||||||
|
if job_id in user_job_list:
|
||||||
|
user_job_list.remove(job_id)
|
||||||
|
|
||||||
|
# 4. Delete the job itself
|
||||||
|
del root.jobs[job_id]
|
||||||
|
|
||||||
|
# No content to return on successful delete
|
||||||
|
return None
|
||||||
|
|
||||||
@dashboard_router.get("/jobs", response_class=HTMLResponse)
|
@dashboard_router.get("/jobs", response_class=HTMLResponse)
|
||||||
async def jobs_list_page(
|
async def jobs_list_page(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -5,6 +5,55 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Job #{{ job.id }}</h2>
|
<h2>Job #{{ job.id }}</h2>
|
||||||
|
|
||||||
|
<!-- New: Action buttons (Back + Delete) -->
|
||||||
|
<div class="mb-4 d-flex justify-content-between align-items-center">
|
||||||
|
<a href="/jobs" class="btn btn-outline-secondary">← Back to Jobs</a>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-danger"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#deleteJobModal">
|
||||||
|
Delete Job
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete Confirmation Modal -->
|
||||||
|
<div class="modal fade" id="deleteJobModal" tabindex="-1" aria-labelledby="deleteJobModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-danger text-white">
|
||||||
|
<h5 class="modal-title" id="deleteJobModalLabel">Confirm Job Deletion</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Are you sure you want to <strong>permanently delete</strong> Job #{{ job.id }}?</p>
|
||||||
|
<p class="mb-0">This will remove:</p>
|
||||||
|
<ul>
|
||||||
|
<li>All command output and errors</li>
|
||||||
|
<li>Any artifacts</li>
|
||||||
|
<li>Job metadata and history</li>
|
||||||
|
</ul>
|
||||||
|
<strong class="text-danger">This action cannot be undone.</strong>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-danger"
|
||||||
|
hx-delete="/api/v1/jobs/{{ job.id }}"
|
||||||
|
hx-target="body"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
hx-push-url="true"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
hx-on::after-request="if(event.detail.successful) document.body.innerHTML = '<div class=container mt-5><div class=alert alert-success text-center><h4>Job {{ job.id }} deleted successfully.</h4><a href=/dashboard/jobs class=btn btn-primary mt-3>Back to Jobs</a></div></div>'">
|
||||||
|
Yes, Delete Permanently
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
@@ -131,7 +180,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-4">
|
|
||||||
<a href="/jobs">← Back to Jobs</a>
|
|
||||||
</p>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -413,7 +413,7 @@ def handle_job_delete(req: Request, conn: PacketServerConnection, db: ZODB.DB):
|
|||||||
del storage.jobs[jid]
|
del storage.jobs[jid]
|
||||||
storage.user_jobs[username].remove(jid)
|
storage.user_jobs[username].remove(jid)
|
||||||
logging.debug(f"Deleted job {jid}")
|
logging.debug(f"Deleted job {jid}")
|
||||||
send_blank_response(conn, req, status_code=200, payload=f"Deleted job {jid}")
|
send_blank_response(conn, req, status_code=204, payload=f"Deleted job {jid}")
|
||||||
else:
|
else:
|
||||||
if jid in storage.jobs:
|
if jid in storage.jobs:
|
||||||
logging.error(f"Job with no owner detected: {jid}")
|
logging.error(f"Job with no owner detected: {jid}")
|
||||||
|
|||||||
Reference in New Issue
Block a user