update DB table

This commit is contained in:
2025-12-28 03:36:29 +01:00
parent 393e78defc
commit de08431e53
3 changed files with 111 additions and 40 deletions

View File

@@ -1,14 +1,8 @@
import os import os
import sys import sys
import json import json
import subprocess
from scenario_exe_parser import parse_test_scenario from scenario_exe_parser import parse_test_scenario
import subprocess
import os
import sys
import json
import subprocess
# Assuming parse_test_scenario is imported correctly
# from scenario_exe_parser import parse_test_scenario
# --- Global Paths --- # --- Global Paths ---
current_directory = os.path.dirname(os.path.abspath(__file__)) current_directory = os.path.dirname(os.path.abspath(__file__))
@@ -81,14 +75,26 @@ def run_test_suite(tasks):
for task in tasks: for task in tasks:
print(f"--- Starting Task: {task['id']} ---") print(f"--- Starting Task: {task['id']} ---")
result = subprocess.run(
# Use Popen to stream output in real-time
process = subprocess.Popen(
[shell_script, task['id'], task['cmd'], task['path'], REPO_PATH], [shell_script, task['id'], task['cmd'], task['path'], REPO_PATH],
capture_output=True, text=True stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True
) )
print(result.stdout)
full_output = ""
for line in process.stdout:
print(line, end="")
full_output += line
process.wait()
json_found = False json_found = False
for line in result.stdout.splitlines(): for line in full_output.splitlines():
if line.startswith("FINAL_JSON_OUTPUT:"): if line.startswith("FINAL_JSON_OUTPUT:"):
json_string = line.replace("FINAL_JSON_OUTPUT:", "").strip() json_string = line.replace("FINAL_JSON_OUTPUT:", "").strip()
try: try:

View File

@@ -138,6 +138,26 @@ async def list_queues(db: Session = Depends(database.get_db)):
queues = db.query(models.Queue).order_by(models.Queue.created_at.desc()).all() queues = db.query(models.Queue).order_by(models.Queue.created_at.desc()).all()
return queues return queues
@app.delete("/api/delete/{id}")
async def delete_queue(id: str, db: Session = Depends(database.get_db)):
# 1. Delete from database
queue = db.query(models.Queue).filter(models.Queue.id == id).first()
if queue:
# Delete associated tasks first
db.query(models.Task).filter(models.Task.queue_id == id).delete()
db.delete(queue)
db.commit()
# 2. Delete folder
queue_dir = os.path.join(BASE_DATA_DIR, id)
if os.path.exists(queue_dir):
import shutil
shutil.rmtree(queue_dir)
return {"id": id, "status": "Deleted"}
raise HTTPException(status_code=404, detail="ID not found")
@app.get("/") @app.get("/")
async def root(): async def root():
return FileResponse(os.path.join(static_dir, "index.html")) return FileResponse(os.path.join(static_dir, "index.html"))

View File

@@ -295,21 +295,27 @@
<div class="grid"> <div class="grid">
<div class="card"> <div class="card">
<h2> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" <h2>
stroke-linecap="round" stroke-linejoin="round"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" /> stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="9" x2="21" y2="9" /> <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
<line x1="9" y1="21" x2="9" y2="9" /> <line x1="3" y1="9" x2="21" y2="9" />
</svg> <line x1="9" y1="21" x2="9" y2="9" />
Queue Monitor </svg>
</h2> Queue Monitor
</h2>
<div style="position: relative; width: 300px;">
<input type="text" id="search-input" placeholder="Search Queue ID..."
style="width: 100%; padding: 0.6rem 1rem; border-radius: 0.75rem; background: var(--glass); border: 1px solid var(--glass-border); color: var(--text); font-family: inherit;">
</div>
</div>
<table id="queue-table"> <table id="queue-table">
<thead> <thead>
<tr> <tr>
<th>Queue ID</th> <th onclick="sortTable(0)" style="cursor: pointer;">Queue ID</th>
<th>Environment</th> <th onclick="sortTable(1)" style="cursor: pointer;">Environment</th>
<th>Status</th> <th onclick="sortTable(2)" style="cursor: pointer;">Status</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
@@ -338,26 +344,14 @@
</div> </div>
<script> <script>
let currentQueues = [];
let sortDirection = [true, true, true];
async function fetchStatus() { async function fetchStatus() {
try { try {
const response = await fetch('/api/queues'); const response = await fetch('/api/queues');
const queues = await response.json(); currentQueues = await response.json();
renderTable();
const tbody = document.querySelector('#queue-table tbody');
tbody.innerHTML = '';
queues.forEach(q => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td style="font-weight: 600;">${q.id}</td>
<td><span style="opacity: 0.8;">${q.environment}</span></td>
<td><span class="status-pill status-${q.status.toLowerCase()}">${q.status}</span></td>
<td>
<button class="btn-abort" onclick="abortQueue('${q.id}')">Abort</button>
</td>
`;
tbody.appendChild(tr);
});
const badge = document.getElementById('connection-status'); const badge = document.getElementById('connection-status');
badge.querySelector('.dot').classList.add('online'); badge.querySelector('.dot').classList.add('online');
@@ -369,6 +363,45 @@
} }
} }
function renderTable() {
const searchTerm = document.getElementById('search-input').value.toLowerCase();
const tbody = document.querySelector('#queue-table tbody');
tbody.innerHTML = '';
const filteredQueues = currentQueues.filter(q => q.id.toLowerCase().includes(searchTerm));
filteredQueues.forEach(q => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td style="font-weight: 600;">${q.id}</td>
<td><span style="opacity: 0.8;">${q.environment}</span></td>
<td><span class="status-pill status-${q.status.toLowerCase()}">${q.status}</span></td>
<td style="display: flex; gap: 0.5rem;">
<button class="btn-abort" onclick="abortQueue('${q.id}')">Abort</button>
<button class="btn-abort" style="background: rgba(239, 68, 68, 0.2); border-color: var(--danger);" onclick="deleteQueue('${q.id}')">Delete</button>
</td>
`;
tbody.appendChild(tr);
});
}
function sortTable(n) {
sortDirection[n] = !sortDirection[n];
const keys = ['id', 'environment', 'status'];
const key = keys[n];
currentQueues.sort((a, b) => {
let valA = a[key].toLowerCase();
let valB = b[key].toLowerCase();
if (valA < valB) return sortDirection[n] ? -1 : 1;
if (valA > valB) return sortDirection[n] ? 1 : -1;
return 0;
});
renderTable();
}
document.getElementById('search-input').addEventListener('input', renderTable);
async function abortQueue(id) { async function abortQueue(id) {
if (confirm(`Are you sure you want to abort queue ${id}?`)) { if (confirm(`Are you sure you want to abort queue ${id}?`)) {
try { try {
@@ -381,6 +414,18 @@
} }
} }
async function deleteQueue(id) {
if (confirm(`Are you sure you want to DELETE queue ${id}? This will remove all files and database records.`)) {
try {
await fetch(`/api/delete/${id}`, { method: 'DELETE' });
addLog(`Deleted queue: ${id}`, 'danger');
fetchStatus();
} catch (e) {
addLog(`Failed to delete queue: ${id}`, 'danger');
}
}
}
function addLog(msg, type = 'info') { function addLog(msg, type = 'info') {
const logs = document.getElementById('logs'); const logs = document.getElementById('logs');
const entry = document.createElement('div'); const entry = document.createElement('div');