365 lines
14 KiB
HTML
365 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Test Custom Task Columns in Asset Browser</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.container {
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
margin-bottom: 20px;
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
border-bottom: 2px solid #4CAF50;
|
|
padding-bottom: 10px;
|
|
}
|
|
h2 {
|
|
color: #555;
|
|
margin-top: 20px;
|
|
}
|
|
.test-section {
|
|
margin: 20px 0;
|
|
padding: 15px;
|
|
background: #f9f9f9;
|
|
border-left: 4px solid #4CAF50;
|
|
}
|
|
.success {
|
|
color: #4CAF50;
|
|
font-weight: bold;
|
|
}
|
|
.error {
|
|
color: #f44336;
|
|
font-weight: bold;
|
|
}
|
|
.info {
|
|
color: #2196F3;
|
|
}
|
|
button {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
button:hover {
|
|
background-color: #45a049;
|
|
}
|
|
button:disabled {
|
|
background-color: #cccccc;
|
|
cursor: not-allowed;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 10px 0;
|
|
}
|
|
th, td {
|
|
border: 1px solid #ddd;
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
th {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
}
|
|
tr:nth-child(even) {
|
|
background-color: #f2f2f2;
|
|
}
|
|
.column-toggle {
|
|
margin: 10px 0;
|
|
padding: 10px;
|
|
background: #e3f2fd;
|
|
border-radius: 4px;
|
|
}
|
|
.column-toggle label {
|
|
display: inline-block;
|
|
margin-right: 15px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>🎬 Custom Task Columns Test</h1>
|
|
<p>This page tests the custom task type columns in the asset browser</p>
|
|
|
|
<div class="test-section">
|
|
<h2>Authentication</h2>
|
|
<div id="auth-status">Not logged in</div>
|
|
<button onclick="login()">Login as Admin</button>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Test 1: Load Project Custom Task Types</h2>
|
|
<button onclick="loadCustomTaskTypes()" id="test1-btn" disabled>Load Custom Task Types</button>
|
|
<div id="test1-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Test 2: Column Visibility Control</h2>
|
|
<div class="column-toggle" id="column-controls">
|
|
<button onclick="toggleAllTaskColumns()" id="toggle-all-btn" disabled>
|
|
Show/Hide All Task Columns
|
|
</button>
|
|
<div id="column-checkboxes" style="margin-top: 10px;"></div>
|
|
</div>
|
|
<div id="test2-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Test 3: Asset Table with Custom Columns</h2>
|
|
<button onclick="loadAssetsWithCustomColumns()" id="test3-btn" disabled>Load Assets</button>
|
|
<div id="test3-results"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const API_BASE = 'http://localhost:8000';
|
|
let token = null;
|
|
let projectId = null;
|
|
let customTaskTypes = [];
|
|
let visibleColumns = {
|
|
name: true,
|
|
category: true,
|
|
status: true,
|
|
modeling: true,
|
|
surfacing: true,
|
|
rigging: true,
|
|
description: true
|
|
};
|
|
let savedTaskColumnStates = {};
|
|
|
|
async function login() {
|
|
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) {
|
|
const data = await response.json();
|
|
token = data.access_token;
|
|
document.getElementById('auth-status').innerHTML = '<span class="success">✅ Logged in successfully</span>';
|
|
|
|
// Get project
|
|
await getProject();
|
|
|
|
// Enable test buttons
|
|
document.getElementById('test1-btn').disabled = false;
|
|
document.getElementById('test2-btn').disabled = false;
|
|
document.getElementById('test3-btn').disabled = false;
|
|
document.getElementById('toggle-all-btn').disabled = false;
|
|
} else {
|
|
document.getElementById('auth-status').innerHTML = '<span class="error">❌ Login failed</span>';
|
|
}
|
|
} catch (error) {
|
|
document.getElementById('auth-status').innerHTML = `<span class="error">❌ Error: ${error.message}</span>`;
|
|
}
|
|
}
|
|
|
|
async function getProject() {
|
|
const response = await fetch(`${API_BASE}/projects/`, {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
const projects = await response.json();
|
|
if (projects.length > 0) {
|
|
projectId = projects[0].id;
|
|
document.getElementById('auth-status').innerHTML += `<br><span class="info">Using project: ${projects[0].name} (ID: ${projectId})</span>`;
|
|
}
|
|
}
|
|
|
|
async function loadCustomTaskTypes() {
|
|
const resultsDiv = document.getElementById('test1-results');
|
|
resultsDiv.innerHTML = '<p>Loading custom task types...</p>';
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/projects/${projectId}`, {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.ok) {
|
|
const project = await response.json();
|
|
customTaskTypes = project.custom_asset_task_types || [];
|
|
|
|
let results = `<p class="success">✅ Loaded ${customTaskTypes.length} custom task types</p>`;
|
|
|
|
if (customTaskTypes.length > 0) {
|
|
results += '<p><strong>Custom Task Types:</strong></p><ul>';
|
|
customTaskTypes.forEach(type => {
|
|
results += `<li>${type}</li>`;
|
|
// Initialize visibility for custom types
|
|
if (!(type in visibleColumns)) {
|
|
visibleColumns[type] = true;
|
|
}
|
|
});
|
|
results += '</ul>';
|
|
} else {
|
|
results += '<p class="info">No custom task types defined for this project</p>';
|
|
}
|
|
|
|
resultsDiv.innerHTML = results;
|
|
updateColumnCheckboxes();
|
|
} else {
|
|
resultsDiv.innerHTML = '<p class="error">❌ Failed to load project</p>';
|
|
}
|
|
} catch (error) {
|
|
resultsDiv.innerHTML = `<p class="error">❌ Error: ${error.message}</p>`;
|
|
}
|
|
}
|
|
|
|
function updateColumnCheckboxes() {
|
|
const checkboxesDiv = document.getElementById('column-checkboxes');
|
|
const standardTypes = ['modeling', 'surfacing', 'rigging'];
|
|
const allTypes = [...standardTypes, ...customTaskTypes];
|
|
|
|
let html = '<strong>Task Columns:</strong><br>';
|
|
allTypes.forEach(type => {
|
|
const checked = visibleColumns[type] ? 'checked' : '';
|
|
const label = type.split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
html += `
|
|
<label>
|
|
<input type="checkbox" ${checked} onchange="toggleColumn('${type}')" />
|
|
${label}
|
|
</label>
|
|
`;
|
|
});
|
|
|
|
checkboxesDiv.innerHTML = html;
|
|
}
|
|
|
|
function toggleColumn(column) {
|
|
visibleColumns[column] = !visibleColumns[column];
|
|
updateColumnCheckboxes();
|
|
|
|
const resultsDiv = document.getElementById('test2-results');
|
|
resultsDiv.innerHTML = `<p class="info">Column "${column}" is now ${visibleColumns[column] ? 'visible' : 'hidden'}</p>`;
|
|
}
|
|
|
|
function toggleAllTaskColumns() {
|
|
const standardTypes = ['modeling', 'surfacing', 'rigging'];
|
|
const allTypes = [...standardTypes, ...customTaskTypes];
|
|
|
|
// Check if all are visible
|
|
const allVisible = allTypes.every(type => visibleColumns[type]);
|
|
|
|
if (allVisible) {
|
|
// Hide all and save states
|
|
savedTaskColumnStates = {};
|
|
allTypes.forEach(type => {
|
|
savedTaskColumnStates[type] = visibleColumns[type];
|
|
visibleColumns[type] = false;
|
|
});
|
|
} else {
|
|
// Restore saved states or show all
|
|
allTypes.forEach(type => {
|
|
if (type in savedTaskColumnStates) {
|
|
visibleColumns[type] = savedTaskColumnStates[type];
|
|
} else {
|
|
visibleColumns[type] = true;
|
|
}
|
|
});
|
|
savedTaskColumnStates = {};
|
|
}
|
|
|
|
updateColumnCheckboxes();
|
|
|
|
const resultsDiv = document.getElementById('test2-results');
|
|
resultsDiv.innerHTML = `<p class="success">✅ ${allVisible ? 'Hidden' : 'Shown'} all task columns</p>`;
|
|
}
|
|
|
|
async function loadAssetsWithCustomColumns() {
|
|
const resultsDiv = document.getElementById('test3-results');
|
|
resultsDiv.innerHTML = '<p>Loading assets...</p>';
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/assets/?project_id=${projectId}`, {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.ok) {
|
|
const assets = await response.json();
|
|
|
|
if (assets.length === 0) {
|
|
resultsDiv.innerHTML = '<p class="info">No assets found</p>';
|
|
return;
|
|
}
|
|
|
|
// Build table with dynamic columns
|
|
const standardTypes = ['modeling', 'surfacing', 'rigging'];
|
|
const allTaskTypes = [...standardTypes, ...customTaskTypes];
|
|
|
|
let html = `<p class="success">✅ Loaded ${assets.length} assets</p>`;
|
|
html += '<table><thead><tr>';
|
|
|
|
// Basic columns
|
|
if (visibleColumns.name) html += '<th>Name</th>';
|
|
if (visibleColumns.category) html += '<th>Category</th>';
|
|
if (visibleColumns.status) html += '<th>Status</th>';
|
|
|
|
// Task columns
|
|
allTaskTypes.forEach(type => {
|
|
if (visibleColumns[type]) {
|
|
const label = type.split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
html += `<th>${label}</th>`;
|
|
}
|
|
});
|
|
|
|
if (visibleColumns.description) html += '<th>Description</th>';
|
|
|
|
html += '</tr></thead><tbody>';
|
|
|
|
// Asset rows
|
|
assets.slice(0, 10).forEach(asset => {
|
|
html += '<tr>';
|
|
|
|
if (visibleColumns.name) html += `<td>${asset.name}</td>`;
|
|
if (visibleColumns.category) html += `<td>${asset.category}</td>`;
|
|
if (visibleColumns.status) html += `<td>${asset.status}</td>`;
|
|
|
|
// Task status cells
|
|
allTaskTypes.forEach(type => {
|
|
if (visibleColumns[type]) {
|
|
const status = asset.task_status?.[type] || 'not_started';
|
|
html += `<td>${status}</td>`;
|
|
}
|
|
});
|
|
|
|
if (visibleColumns.description) html += `<td>${asset.description || '-'}</td>`;
|
|
|
|
html += '</tr>';
|
|
});
|
|
|
|
html += '</tbody></table>';
|
|
|
|
if (assets.length > 10) {
|
|
html += `<p class="info">Showing first 10 of ${assets.length} assets</p>`;
|
|
}
|
|
|
|
resultsDiv.innerHTML = html;
|
|
} else {
|
|
resultsDiv.innerHTML = '<p class="error">❌ Failed to load assets</p>';
|
|
}
|
|
} catch (error) {
|
|
resultsDiv.innerHTML = `<p class="error">❌ Error: ${error.message}</p>`;
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|