364 lines
13 KiB
HTML
364 lines
13 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Shot Table View Test</title>
|
||
<style>
|
||
body {
|
||
font-family: Arial, sans-serif;
|
||
max-width: 1200px;
|
||
margin: 20px auto;
|
||
padding: 20px;
|
||
}
|
||
.test-section {
|
||
margin-bottom: 30px;
|
||
padding: 20px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 8px;
|
||
}
|
||
.test-section h2 {
|
||
margin-top: 0;
|
||
color: #333;
|
||
}
|
||
.success {
|
||
color: green;
|
||
font-weight: bold;
|
||
}
|
||
.error {
|
||
color: red;
|
||
font-weight: bold;
|
||
}
|
||
.info {
|
||
color: blue;
|
||
}
|
||
pre {
|
||
background: #f5f5f5;
|
||
padding: 10px;
|
||
border-radius: 4px;
|
||
overflow-x: auto;
|
||
}
|
||
button {
|
||
background: #007bff;
|
||
color: white;
|
||
border: none;
|
||
padding: 10px 20px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
margin-right: 10px;
|
||
}
|
||
button:hover {
|
||
background: #0056b3;
|
||
}
|
||
.result {
|
||
margin-top: 10px;
|
||
padding: 10px;
|
||
background: #f9f9f9;
|
||
border-left: 4px solid #007bff;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>Shot Table View - Implementation Test</h1>
|
||
<p class="info">This page tests the shot table view implementation with task status display.</p>
|
||
|
||
<div class="test-section">
|
||
<h2>Test 1: Backend API - Get Shots with Task Status</h2>
|
||
<button onclick="testGetShots()">Run Test</button>
|
||
<div id="test1-result" class="result" style="display:none;"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>Test 2: Backend API - Filter by Task Status</h2>
|
||
<button onclick="testFilterByTaskStatus()">Run Test</button>
|
||
<div id="test2-result" class="result" style="display:none;"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>Test 3: Backend API - Sort by Task Status</h2>
|
||
<button onclick="testSortByTaskStatus()">Run Test</button>
|
||
<div id="test3-result" class="result" style="display:none;"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>Test 4: Backend API - Sort by Name</h2>
|
||
<button onclick="testSortByName()">Run Test</button>
|
||
<div id="test4-result" class="result" style="display:none;"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>Test 5: Custom Task Types Support</h2>
|
||
<button onclick="testCustomTaskTypes()">Run Test</button>
|
||
<div id="test5-result" class="result" style="display:none;"></div>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = 'http://localhost:8000';
|
||
let authToken = null;
|
||
|
||
// Login first
|
||
async function login() {
|
||
if (authToken) return authToken;
|
||
|
||
try {
|
||
const response = await fetch(`${API_BASE}/auth/login`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
email: 'admin@vfx.com',
|
||
password: 'admin123'
|
||
})
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error('Login failed');
|
||
}
|
||
|
||
const data = await response.json();
|
||
authToken = data.access_token;
|
||
return authToken;
|
||
} catch (error) {
|
||
console.error('Login error:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
async function testGetShots() {
|
||
const resultDiv = document.getElementById('test1-result');
|
||
resultDiv.style.display = 'block';
|
||
resultDiv.innerHTML = '<p>Running test...</p>';
|
||
|
||
try {
|
||
const token = await login();
|
||
const response = await fetch(`${API_BASE}/shots/`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const shots = await response.json();
|
||
|
||
let html = `<p class="success">✓ Test Passed</p>`;
|
||
html += `<p>Found ${shots.length} shots</p>`;
|
||
|
||
if (shots.length > 0) {
|
||
const shot = shots[0];
|
||
html += `<p><strong>First Shot:</strong></p>`;
|
||
html += `<pre>${JSON.stringify({
|
||
id: shot.id,
|
||
name: shot.name,
|
||
episode_id: shot.episode_id,
|
||
frame_range: `${shot.frame_start}-${shot.frame_end}`,
|
||
task_count: shot.task_count,
|
||
task_status: shot.task_status,
|
||
task_details_count: shot.task_details?.length || 0
|
||
}, null, 2)}</pre>`;
|
||
|
||
if (shot.task_status) {
|
||
html += `<p class="success">✓ Task status included</p>`;
|
||
} else {
|
||
html += `<p class="error">✗ Task status missing</p>`;
|
||
}
|
||
|
||
if (shot.task_details && shot.task_details.length > 0) {
|
||
html += `<p class="success">✓ Task details included (${shot.task_details.length} tasks)</p>`;
|
||
} else {
|
||
html += `<p class="error">✗ Task details missing</p>`;
|
||
}
|
||
}
|
||
|
||
resultDiv.innerHTML = html;
|
||
} catch (error) {
|
||
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
|
||
}
|
||
}
|
||
|
||
async function testFilterByTaskStatus() {
|
||
const resultDiv = document.getElementById('test2-result');
|
||
resultDiv.style.display = 'block';
|
||
resultDiv.innerHTML = '<p>Running test...</p>';
|
||
|
||
try {
|
||
const token = await login();
|
||
const response = await fetch(`${API_BASE}/shots/?task_status_filter=layout:not_started`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const shots = await response.json();
|
||
|
||
let html = `<p class="success">✓ Test Passed</p>`;
|
||
html += `<p>Found ${shots.length} shots with layout task not started</p>`;
|
||
|
||
if (shots.length > 0) {
|
||
const allMatch = shots.every(shot =>
|
||
shot.task_status && shot.task_status.layout === 'not_started'
|
||
);
|
||
|
||
if (allMatch) {
|
||
html += `<p class="success">✓ All shots match filter criteria</p>`;
|
||
} else {
|
||
html += `<p class="error">✗ Some shots don't match filter</p>`;
|
||
}
|
||
}
|
||
|
||
resultDiv.innerHTML = html;
|
||
} catch (error) {
|
||
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
|
||
}
|
||
}
|
||
|
||
async function testSortByTaskStatus() {
|
||
const resultDiv = document.getElementById('test3-result');
|
||
resultDiv.style.display = 'block';
|
||
resultDiv.innerHTML = '<p>Running test...</p>';
|
||
|
||
try {
|
||
const token = await login();
|
||
const response = await fetch(`${API_BASE}/shots/?sort_by=layout_status&sort_direction=asc`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const shots = await response.json();
|
||
|
||
let html = `<p class="success">✓ Test Passed</p>`;
|
||
html += `<p>Sorted ${shots.length} shots by layout task status</p>`;
|
||
|
||
if (shots.length > 0) {
|
||
html += `<p><strong>First 5 shots (sorted by layout status):</strong></p>`;
|
||
html += '<ul>';
|
||
shots.slice(0, 5).forEach(shot => {
|
||
html += `<li>${shot.name}: ${shot.task_status?.layout || 'N/A'}</li>`;
|
||
});
|
||
html += '</ul>';
|
||
}
|
||
|
||
resultDiv.innerHTML = html;
|
||
} catch (error) {
|
||
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
|
||
}
|
||
}
|
||
|
||
async function testSortByName() {
|
||
const resultDiv = document.getElementById('test4-result');
|
||
resultDiv.style.display = 'block';
|
||
resultDiv.innerHTML = '<p>Running test...</p>';
|
||
|
||
try {
|
||
const token = await login();
|
||
const response = await fetch(`${API_BASE}/shots/?sort_by=name&sort_direction=asc`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const shots = await response.json();
|
||
|
||
let html = `<p class="success">✓ Test Passed</p>`;
|
||
html += `<p>Sorted ${shots.length} shots by name</p>`;
|
||
|
||
if (shots.length > 0) {
|
||
html += `<p><strong>First 5 shots (sorted by name):</strong></p>`;
|
||
html += '<ul>';
|
||
shots.slice(0, 5).forEach(shot => {
|
||
html += `<li>${shot.name}</li>`;
|
||
});
|
||
html += '</ul>';
|
||
|
||
// Check if sorted
|
||
const names = shots.map(s => s.name);
|
||
const sortedNames = [...names].sort();
|
||
const isSorted = JSON.stringify(names) === JSON.stringify(sortedNames);
|
||
|
||
if (isSorted) {
|
||
html += `<p class="success">✓ Shots are correctly sorted</p>`;
|
||
} else {
|
||
html += `<p class="error">✗ Shots are not correctly sorted</p>`;
|
||
}
|
||
}
|
||
|
||
resultDiv.innerHTML = html;
|
||
} catch (error) {
|
||
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
|
||
}
|
||
}
|
||
|
||
async function testCustomTaskTypes() {
|
||
const resultDiv = document.getElementById('test5-result');
|
||
resultDiv.style.display = 'block';
|
||
resultDiv.innerHTML = '<p>Running test...</p>';
|
||
|
||
try {
|
||
const token = await login();
|
||
const response = await fetch(`${API_BASE}/shots/`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const shots = await response.json();
|
||
|
||
let html = `<p class="success">✓ Test Passed</p>`;
|
||
|
||
if (shots.length > 0) {
|
||
const shot = shots[0];
|
||
const taskTypes = Object.keys(shot.task_status || {});
|
||
|
||
html += `<p>Found ${taskTypes.length} task types in shot data</p>`;
|
||
html += `<p><strong>Task Types:</strong></p>`;
|
||
html += '<ul>';
|
||
taskTypes.forEach(type => {
|
||
html += `<li>${type}</li>`;
|
||
});
|
||
html += '</ul>';
|
||
|
||
// Check for custom task types (non-standard)
|
||
const standardTypes = ['layout', 'animation', 'simulation', 'lighting', 'compositing'];
|
||
const customTypes = taskTypes.filter(t => !standardTypes.includes(t));
|
||
|
||
if (customTypes.length > 0) {
|
||
html += `<p class="success">✓ Custom task types found: ${customTypes.join(', ')}</p>`;
|
||
} else {
|
||
html += `<p class="info">ℹ No custom task types in this project (only standard types)</p>`;
|
||
}
|
||
}
|
||
|
||
resultDiv.innerHTML = html;
|
||
} catch (error) {
|
||
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
|
||
}
|
||
}
|
||
|
||
// Auto-run first test on page load
|
||
window.addEventListener('load', () => {
|
||
console.log('Page loaded. Ready to run tests.');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|