Init Repo
This commit is contained in:
@@ -0,0 +1,450 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TasksStore Optimization Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.test-section {
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.success { background-color: #d4edda; border-color: #c3e6cb; }
|
||||
.error { background-color: #f8d7da; border-color: #f5c6cb; }
|
||||
.info { background-color: #d1ecf1; border-color: #bee5eb; }
|
||||
pre {
|
||||
background-color: #f8f9fa;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.task-item {
|
||||
padding: 8px;
|
||||
margin: 4px 0;
|
||||
background-color: #f8f9fa;
|
||||
border-left: 4px solid #007bff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TasksStore Optimization Test</h1>
|
||||
<p>Testing the optimized TasksStore that uses embedded task data from shots/assets.</p>
|
||||
|
||||
<div class="test-section info">
|
||||
<h3>Test Configuration</h3>
|
||||
<p>This test verifies that the TasksStore correctly:</p>
|
||||
<ul>
|
||||
<li>Uses embedded task data from shots and assets when projectId is provided</li>
|
||||
<li>Combines task data from both shots and assets into a single array</li>
|
||||
<li>Maintains existing store interface and computed properties</li>
|
||||
<li>Applies filters correctly to the combined task data</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="test-section">
|
||||
<h3>Test Controls</h3>
|
||||
<button onclick="testOptimizedFetch()">Test Optimized Fetch (with projectId)</button>
|
||||
<button onclick="testLegacyFetch()">Test Legacy Fetch (without projectId)</button>
|
||||
<button onclick="testFiltering()">Test Task Filtering</button>
|
||||
<button onclick="testComputedProperties()">Test Computed Properties</button>
|
||||
<button onclick="clearResults()">Clear Results</button>
|
||||
</div>
|
||||
|
||||
<div id="results"></div>
|
||||
|
||||
<script type="module">
|
||||
// Mock the services for testing
|
||||
const mockShotService = {
|
||||
getShotsByProject: async (projectId) => {
|
||||
console.log('Mock: Fetching shots for project', projectId);
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
name: 'SH010',
|
||||
project_id: projectId,
|
||||
project_name: 'Test Project',
|
||||
episode_id: 1,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
task_details: [
|
||||
{
|
||||
task_id: 101,
|
||||
task_type: 'layout',
|
||||
status: 'in_progress',
|
||||
assigned_user_id: 1
|
||||
},
|
||||
{
|
||||
task_id: 102,
|
||||
task_type: 'animation',
|
||||
status: 'not_started',
|
||||
assigned_user_id: null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'SH020',
|
||||
project_id: projectId,
|
||||
project_name: 'Test Project',
|
||||
episode_id: 1,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
task_details: [
|
||||
{
|
||||
task_id: 103,
|
||||
task_type: 'layout',
|
||||
status: 'approved',
|
||||
assigned_user_id: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const mockAssetService = {
|
||||
getAssets: async (projectId) => {
|
||||
console.log('Mock: Fetching assets for project', projectId);
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Character_Hero',
|
||||
project_id: projectId,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
task_details: [
|
||||
{
|
||||
task_id: 201,
|
||||
task_type: 'modeling',
|
||||
status: 'approved',
|
||||
assigned_user_id: 1
|
||||
},
|
||||
{
|
||||
task_id: 202,
|
||||
task_type: 'rigging',
|
||||
status: 'in_progress',
|
||||
assigned_user_id: 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Prop_Sword',
|
||||
project_id: projectId,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
task_details: [
|
||||
{
|
||||
task_id: 203,
|
||||
task_type: 'modeling',
|
||||
status: 'not_started',
|
||||
assigned_user_id: null
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const mockTaskService = {
|
||||
getTasks: async (filters) => {
|
||||
console.log('Mock: Legacy task service called with filters', filters);
|
||||
return [
|
||||
{
|
||||
id: 301,
|
||||
name: 'Legacy Task 1',
|
||||
task_type: 'compositing',
|
||||
status: 'in_progress',
|
||||
project_id: 1,
|
||||
project_name: 'Legacy Project',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z'
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
// Mock the optimized TasksStore logic
|
||||
class MockTasksStore {
|
||||
constructor() {
|
||||
this.tasks = [];
|
||||
this.loading = false;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
get myTasks() {
|
||||
return this.tasks;
|
||||
}
|
||||
|
||||
get tasksByStatus() {
|
||||
return this.tasks.reduce((acc, task) => {
|
||||
if (!acc[task.status]) {
|
||||
acc[task.status] = [];
|
||||
}
|
||||
acc[task.status].push(task);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
get overdueTasks() {
|
||||
const now = new Date();
|
||||
return this.tasks.filter(task => {
|
||||
if (!task.deadline) return false;
|
||||
const deadline = new Date(task.deadline);
|
||||
return deadline < now && task.status !== 'approved';
|
||||
});
|
||||
}
|
||||
|
||||
async fetchTasks(filters = {}) {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
if (filters.projectId) {
|
||||
// Use optimized approach: get both shots and assets with embedded task data
|
||||
const [shots, assets] = await Promise.all([
|
||||
mockShotService.getShotsByProject(filters.projectId),
|
||||
mockAssetService.getAssets(filters.projectId)
|
||||
]);
|
||||
|
||||
// Extract tasks from embedded data
|
||||
const shotTasks = this.extractTasksFromShots(shots);
|
||||
const assetTasks = this.extractTasksFromAssets(assets);
|
||||
|
||||
// Combine all tasks
|
||||
let allTasks = [...shotTasks, ...assetTasks];
|
||||
|
||||
// Apply additional filters
|
||||
if (filters.assignedUserId) {
|
||||
allTasks = allTasks.filter(task => task.assigned_user_id === filters.assignedUserId);
|
||||
}
|
||||
if (filters.status) {
|
||||
allTasks = allTasks.filter(task => task.status === filters.status);
|
||||
}
|
||||
if (filters.taskType) {
|
||||
allTasks = allTasks.filter(task => task.task_type === filters.taskType);
|
||||
}
|
||||
|
||||
this.tasks = allTasks;
|
||||
} else {
|
||||
// Fallback to original task service
|
||||
const response = await mockTaskService.getTasks(filters);
|
||||
this.tasks = response;
|
||||
}
|
||||
} catch (err) {
|
||||
this.error = err.message || 'Failed to fetch tasks';
|
||||
console.error('Error fetching tasks:', err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
extractTasksFromShots(shots) {
|
||||
const tasks = [];
|
||||
|
||||
for (const shot of shots) {
|
||||
if (!shot.task_details || shot.task_details.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const taskDetail of shot.task_details) {
|
||||
if (!taskDetail.task_type || !taskDetail.status) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tasks.push({
|
||||
id: taskDetail.task_id || 0,
|
||||
name: `${shot.name} - ${this.formatTaskType(taskDetail.task_type)}`,
|
||||
task_type: taskDetail.task_type,
|
||||
status: taskDetail.status,
|
||||
project_id: shot.project_id,
|
||||
project_name: shot.project_name || '',
|
||||
episode_id: shot.episode_id,
|
||||
shot_id: shot.id,
|
||||
shot_name: shot.name,
|
||||
assigned_user_id: taskDetail.assigned_user_id,
|
||||
created_at: shot.created_at,
|
||||
updated_at: shot.updated_at
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
extractTasksFromAssets(assets) {
|
||||
const tasks = [];
|
||||
|
||||
for (const asset of assets) {
|
||||
if (!asset.task_details || asset.task_details.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const taskDetail of asset.task_details) {
|
||||
if (!taskDetail.task_type || !taskDetail.status) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tasks.push({
|
||||
id: taskDetail.task_id || 0,
|
||||
name: `${asset.name} - ${this.formatTaskType(taskDetail.task_type)}`,
|
||||
task_type: taskDetail.task_type,
|
||||
status: taskDetail.status,
|
||||
project_id: asset.project_id,
|
||||
project_name: '',
|
||||
asset_id: asset.id,
|
||||
asset_name: asset.name,
|
||||
assigned_user_id: taskDetail.assigned_user_id,
|
||||
created_at: asset.created_at,
|
||||
updated_at: asset.updated_at
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
formatTaskType(taskType) {
|
||||
return taskType.charAt(0).toUpperCase() + taskType.slice(1).replace('_', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Create store instance for testing
|
||||
const tasksStore = new MockTasksStore();
|
||||
|
||||
// Test functions
|
||||
window.testOptimizedFetch = async function() {
|
||||
addResult('info', 'Testing optimized fetch with projectId...');
|
||||
|
||||
try {
|
||||
await tasksStore.fetchTasks({ projectId: 1 });
|
||||
|
||||
const results = {
|
||||
totalTasks: tasksStore.tasks.length,
|
||||
shotTasks: tasksStore.tasks.filter(t => t.shot_id).length,
|
||||
assetTasks: tasksStore.tasks.filter(t => t.asset_id).length,
|
||||
tasks: tasksStore.tasks
|
||||
};
|
||||
|
||||
addResult('success', `✅ Optimized fetch successful!
|
||||
Total tasks: ${results.totalTasks}
|
||||
Shot tasks: ${results.shotTasks}
|
||||
Asset tasks: ${results.assetTasks}
|
||||
|
||||
Tasks combined from both shots and assets:`, JSON.stringify(results.tasks, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
addResult('error', `❌ Optimized fetch failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
window.testLegacyFetch = async function() {
|
||||
addResult('info', 'Testing legacy fetch without projectId...');
|
||||
|
||||
try {
|
||||
await tasksStore.fetchTasks({ status: 'in_progress' });
|
||||
|
||||
addResult('success', `✅ Legacy fetch successful!
|
||||
Total tasks: ${tasksStore.tasks.length}
|
||||
|
||||
Legacy tasks:`, JSON.stringify(tasksStore.tasks, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
addResult('error', `❌ Legacy fetch failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
window.testFiltering = async function() {
|
||||
addResult('info', 'Testing task filtering...');
|
||||
|
||||
try {
|
||||
// First fetch all tasks
|
||||
await tasksStore.fetchTasks({ projectId: 1 });
|
||||
const allTasks = tasksStore.tasks.length;
|
||||
|
||||
// Test status filtering
|
||||
await tasksStore.fetchTasks({ projectId: 1, status: 'in_progress' });
|
||||
const inProgressTasks = tasksStore.tasks.length;
|
||||
|
||||
// Test user filtering
|
||||
await tasksStore.fetchTasks({ projectId: 1, assignedUserId: 1 });
|
||||
const userTasks = tasksStore.tasks.length;
|
||||
|
||||
addResult('success', `✅ Filtering tests successful!
|
||||
All tasks: ${allTasks}
|
||||
In progress tasks: ${inProgressTasks}
|
||||
User 1 tasks: ${userTasks}`);
|
||||
|
||||
} catch (error) {
|
||||
addResult('error', `❌ Filtering test failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
window.testComputedProperties = async function() {
|
||||
addResult('info', 'Testing computed properties...');
|
||||
|
||||
try {
|
||||
await tasksStore.fetchTasks({ projectId: 1 });
|
||||
|
||||
const myTasks = tasksStore.myTasks;
|
||||
const tasksByStatus = tasksStore.tasksByStatus;
|
||||
const overdueTasks = tasksStore.overdueTasks;
|
||||
|
||||
addResult('success', `✅ Computed properties working!
|
||||
My tasks count: ${myTasks.length}
|
||||
Tasks by status: ${JSON.stringify(Object.keys(tasksByStatus).reduce((acc, status) => {
|
||||
acc[status] = tasksByStatus[status].length;
|
||||
return acc;
|
||||
}, {}), null, 2)}
|
||||
Overdue tasks: ${overdueTasks.length}`);
|
||||
|
||||
} catch (error) {
|
||||
addResult('error', `❌ Computed properties test failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
window.clearResults = function() {
|
||||
document.getElementById('results').innerHTML = '';
|
||||
};
|
||||
|
||||
function addResult(type, title, details = '') {
|
||||
const resultsDiv = document.getElementById('results');
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.className = `test-section ${type}`;
|
||||
|
||||
let content = `<h4>${title}</h4>`;
|
||||
if (details) {
|
||||
content += `<pre>${details}</pre>`;
|
||||
}
|
||||
|
||||
resultDiv.innerHTML = content;
|
||||
resultsDiv.appendChild(resultDiv);
|
||||
}
|
||||
|
||||
// Auto-run initial test
|
||||
setTimeout(() => {
|
||||
addResult('info', 'TasksStore Optimization Test Ready', 'Click the test buttons above to verify the optimized functionality.');
|
||||
}, 100);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user