LinkDesk/frontend/test-task-status.html

316 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task Status Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.test-section {
margin: 20px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.success {
color: green;
}
.error {
color: red;
}
.info {
color: blue;
}
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
}
th,
td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
.status-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
}
.status-not-started {
background-color: #f3f4f6;
color: #374151;
}
.status-in-progress {
background-color: #dbeafe;
color: #1e40af;
}
.status-submitted {
background-color: #fef3c7;
color: #92400e;
}
.status-approved {
background-color: #d1fae5;
color: #065f46;
}
.status-retake {
background-color: #fee2e2;
color: #991b1b;
}
</style>
</head>
<body>
<h1>VFX Project Management - Task Status Test</h1>
<div class="test-section">
<h2>API Connection Test</h2>
<div id="connection-status">Testing connection...</div>
</div>
<div class="test-section">
<h2>Asset List with Task Status</h2>
<div id="asset-status">Loading assets...</div>
<div id="asset-table"></div>
</div>
<div class="test-section">
<h2>Task Status Filtering Test</h2>
<div>
<label>Filter by task status:</label>
<select id="status-filter">
<option value="">All Tasks</option>
<option value="modeling:not_started">Modeling - Not Started</option>
<option value="modeling:in_progress">Modeling - In Progress</option>
<option value="surfacing:not_started">Surfacing - Not Started</option>
<option value="rigging:not_started">Rigging - Not Started</option>
</select>
<button onclick="applyFilter()">Apply Filter</button>
</div>
<div id="filtered-results"></div>
</div>
<div class="test-section">
<h2>Task Status Sorting Test</h2>
<div>
<label>Sort by:</label>
<select id="sort-field">
<option value="name">Name</option>
<option value="category">Category</option>
<option value="modeling_status">Modeling Status</option>
<option value="surfacing_status">Surfacing Status</option>
<option value="rigging_status">Rigging Status</option>
</select>
<select id="sort-direction">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
<button onclick="applySorting()">Apply Sorting</button>
</div>
<div id="sorted-results"></div>
</div>
<script>
const BASE_URL = 'http://localhost:8000';
let authToken = '';
let currentProjectId = null;
let allAssets = [];
// Test API connection and login
async function testConnection() {
try {
// Login
const loginResponse = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@vfx.com',
password: 'admin123'
})
});
if (!loginResponse.ok) {
throw new Error(`Login failed: ${loginResponse.status}`);
}
const loginData = await loginResponse.json();
authToken = loginData.access_token;
// Get projects
const projectsResponse = await fetch(`${BASE_URL}/projects/`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
if (!projectsResponse.ok) {
throw new Error(`Projects fetch failed: ${projectsResponse.status}`);
}
const projects = await projectsResponse.json();
if (projects.length === 0) {
throw new Error('No projects found');
}
currentProjectId = projects[0].id;
document.getElementById('connection-status').innerHTML =
`<span class="success">✅ Connected successfully! Using project: ${projects[0].name} (ID: ${currentProjectId})</span>`;
// Load assets
await loadAssets();
} catch (error) {
document.getElementById('connection-status').innerHTML =
`<span class="error">❌ Connection failed: ${error.message}</span>`;
}
}
// Load assets with task status
async function loadAssets(options = {}) {
try {
const params = new URLSearchParams({
project_id: currentProjectId.toString(),
...options
});
const response = await fetch(`${BASE_URL}/assets/?${params}`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
if (!response.ok) {
throw new Error(`Assets fetch failed: ${response.status}`);
}
const assets = await response.json();
allAssets = assets;
document.getElementById('asset-status').innerHTML =
`<span class="success">✅ Loaded ${assets.length} assets with task status</span>`;
displayAssetsTable(assets);
} catch (error) {
document.getElementById('asset-status').innerHTML =
`<span class="error">❌ Failed to load assets: ${error.message}</span>`;
}
}
// Display assets in a table
function displayAssetsTable(assets) {
if (assets.length === 0) {
document.getElementById('asset-table').innerHTML = '<p>No assets found</p>';
return;
}
let tableHTML = `
<table>
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Task Count</th>
<th>Modeling</th>
<th>Surfacing</th>
<th>Rigging</th>
</tr>
</thead>
<tbody>
`;
assets.forEach(asset => {
const modelingStatus = asset.task_status?.modeling || 'not_started';
const surfacingStatus = asset.task_status?.surfacing || 'not_started';
const riggingStatus = asset.task_status?.rigging || 'not_started';
tableHTML += `
<tr>
<td>${asset.name}</td>
<td>${asset.category}</td>
<td>${asset.task_count}</td>
<td><span class="status-badge status-${modelingStatus.replace('_', '-')}">${formatStatus(modelingStatus)}</span></td>
<td><span class="status-badge status-${surfacingStatus.replace('_', '-')}">${formatStatus(surfacingStatus)}</span></td>
<td>${isRiggingApplicable(asset.category) ?
`<span class="status-badge status-${riggingStatus.replace('_', '-')}">${formatStatus(riggingStatus)}</span>` :
'<span class="info">N/A</span>'}</td>
</tr>
`;
});
tableHTML += '</tbody></table>';
document.getElementById('asset-table').innerHTML = tableHTML;
}
// Apply task status filter
async function applyFilter() {
const filter = document.getElementById('status-filter').value;
const options = {};
if (filter) {
options.task_status_filter = filter;
}
await loadAssets(options);
document.getElementById('filtered-results').innerHTML =
`<span class="info">Applied filter: ${filter || 'None'}</span>`;
}
// Apply sorting
async function applySorting() {
const sortField = document.getElementById('sort-field').value;
const sortDirection = document.getElementById('sort-direction').value;
const options = {
sort_by: sortField,
sort_direction: sortDirection
};
await loadAssets(options);
document.getElementById('sorted-results').innerHTML =
`<span class="info">Sorted by: ${sortField} (${sortDirection})</span>`;
}
// Helper functions
function formatStatus(status) {
return status.split('_').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' ');
}
function isRiggingApplicable(category) {
return category === 'characters' || category === 'vehicles';
}
// Initialize
testConnection();
</script>
</body>
</html>""