update DB table
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|||||||
@@ -295,6 +295,7 @@
|
|||||||
|
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
|
||||||
<h2>
|
<h2>
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -304,12 +305,17 @@
|
|||||||
</svg>
|
</svg>
|
||||||
Queue Monitor
|
Queue Monitor
|
||||||
</h2>
|
</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');
|
||||||
|
|||||||
Reference in New Issue
Block a user