Complete Phase 1 critical test coverage expansion and begin Phase 2
Phase 1 Achievements (47 new test scenarios): • Modern Framework Integration Suite (20 scenarios) - React 18 with hooks, state management, component interactions - Vue 3 with Composition API, reactivity system, watchers - Angular 17 with services, RxJS observables, reactive forms - Cross-framework compatibility and performance comparison • Mobile Browser Compatibility Suite (15 scenarios) - iPhone 13/SE, Android Pixel/Galaxy, iPad Air configurations - Touch events, gesture support, viewport adaptation - Mobile-specific APIs (orientation, battery, network) - Safari/Chrome mobile quirks and optimizations • Advanced User Interaction Suite (12 scenarios) - Multi-step form workflows with validation - Drag-and-drop file handling and complex interactions - Keyboard navigation and ARIA accessibility - Multi-page e-commerce workflow simulation Phase 2 Started - Production Network Resilience: • Enterprise proxy/firewall scenarios with content filtering • CDN failover strategies with geographic load balancing • HTTP connection pooling optimization • DNS failure recovery mechanisms Infrastructure Enhancements: • Local test server with React/Vue/Angular demo applications • Production-like SPAs with complex state management • Cross-platform mobile/tablet/desktop configurations • Network resilience testing framework Coverage Impact: • Before: ~70% production coverage (280+ scenarios) • After Phase 1: ~85% production coverage (327+ scenarios) • Target Phase 2: ~92% production coverage (357+ scenarios) Critical gaps closed for modern framework support (90% of websites) and mobile browser compatibility (60% of traffic).
This commit is contained in:
parent
d35dcbb494
commit
fd836c90cf
39 changed files with 21772 additions and 0 deletions
807
test-server/sites/spa/index.html
Normal file
807
test-server/sites/spa/index.html
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TaskFlow - Modern SPA Demo</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: #f8fafc;
|
||||
color: #334155;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Main Content */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.page {
|
||||
display: none;
|
||||
animation: fadeIn 0.3s ease-in;
|
||||
}
|
||||
|
||||
.page.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* Dashboard Page */
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #e2e8f0;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
/* Tasks Page */
|
||||
.task-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.task-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6b7280;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #4b5563;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0.5rem;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.task-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.task-completed {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.task-delete {
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.task-delete:hover {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
/* Analytics Page */
|
||||
.chart-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 300px;
|
||||
background: linear-gradient(45deg, #f1f5f9, #e2e8f0);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #64748b;
|
||||
font-size: 1.1rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chart-bars {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 1rem;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.chart-bar {
|
||||
background: linear-gradient(to top, #3b82f6, #60a5fa);
|
||||
width: 40px;
|
||||
border-radius: 4px 4px 0 0;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.chart-bar:hover {
|
||||
transform: scaleY(1.1);
|
||||
}
|
||||
|
||||
/* Loading States */
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-top: 2px solid #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.nav-menu {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Form Styles */
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 1rem;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: #374151;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="header">
|
||||
<nav class="nav">
|
||||
<div class="logo">TaskFlow</div>
|
||||
<ul class="nav-menu">
|
||||
<li class="nav-item active" data-page="dashboard">Dashboard</li>
|
||||
<li class="nav-item" data-page="tasks">Tasks</li>
|
||||
<li class="nav-item" data-page="analytics">Analytics</li>
|
||||
<li class="nav-item" data-page="settings">Settings</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<!-- Dashboard Page -->
|
||||
<div id="dashboard" class="page active">
|
||||
<h1>Dashboard</h1>
|
||||
<div class="dashboard-grid">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Total Tasks</h3>
|
||||
</div>
|
||||
<div class="stat-number" id="total-tasks">--</div>
|
||||
<p class="text-gray-600">Tasks in your workspace</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Completed Today</h3>
|
||||
</div>
|
||||
<div class="stat-number" id="completed-today">--</div>
|
||||
<p class="text-gray-600">Tasks completed today</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Active Projects</h3>
|
||||
</div>
|
||||
<div class="stat-number" id="active-projects">--</div>
|
||||
<p class="text-gray-600">Projects in progress</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Team Members</h3>
|
||||
</div>
|
||||
<div class="stat-number" id="team-members">--</div>
|
||||
<p class="text-gray-600">Active team members</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 class="card-title">Recent Activity</h3>
|
||||
<div id="recent-activity" class="loading">
|
||||
<div class="spinner"></div>
|
||||
Loading recent activity...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tasks Page -->
|
||||
<div id="tasks" class="page">
|
||||
<div class="task-container">
|
||||
<div class="task-header">
|
||||
<h1>Tasks</h1>
|
||||
<button class="btn" onclick="openAddTaskModal()">Add Task</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" id="task-filter" class="form-input" placeholder="Filter tasks...">
|
||||
</div>
|
||||
|
||||
<ul id="task-list" class="task-list">
|
||||
<!-- Tasks will be dynamically loaded -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics Page -->
|
||||
<div id="analytics" class="page">
|
||||
<h1>Analytics</h1>
|
||||
|
||||
<div class="chart-container">
|
||||
<h3>Task Completion Over Time</h3>
|
||||
<div class="chart">
|
||||
<div class="chart-bars" id="completion-chart">
|
||||
<!-- Chart bars will be generated -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<div class="card">
|
||||
<h3 class="card-title">Average Completion Time</h3>
|
||||
<div class="stat-number">2.4h</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 class="card-title">Productivity Score</h3>
|
||||
<div class="stat-number">87%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Page -->
|
||||
<div id="settings" class="page">
|
||||
<h1>Settings</h1>
|
||||
|
||||
<div class="card">
|
||||
<h3 class="card-title">User Preferences</h3>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Theme</label>
|
||||
<select class="form-input" id="theme-select">
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="auto">Auto</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Notifications</label>
|
||||
<input type="checkbox" id="notifications-enabled" checked> Enable notifications
|
||||
</div>
|
||||
|
||||
<button class="btn" onclick="saveSettings()">Save Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Add Task Modal -->
|
||||
<div id="add-task-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Add New Task</h3>
|
||||
<button class="modal-close" onclick="closeAddTaskModal()">×</button>
|
||||
</div>
|
||||
|
||||
<form id="add-task-form">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Task Title</label>
|
||||
<input type="text" id="task-title" class="form-input" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea id="task-description" class="form-input" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Priority</label>
|
||||
<select id="task-priority" class="form-input">
|
||||
<option value="low">Low</option>
|
||||
<option value="medium">Medium</option>
|
||||
<option value="high">High</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 1rem; justify-content: end;">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeAddTaskModal()">Cancel</button>
|
||||
<button type="submit" class="btn">Add Task</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// SPA Router and State Management
|
||||
class TaskFlowApp {
|
||||
constructor() {
|
||||
this.currentPage = 'dashboard';
|
||||
this.tasks = [
|
||||
{ id: 1, title: 'Setup development environment', completed: true, priority: 'high' },
|
||||
{ id: 2, title: 'Design user interface mockups', completed: false, priority: 'medium' },
|
||||
{ id: 3, title: 'Implement authentication system', completed: false, priority: 'high' },
|
||||
{ id: 4, title: 'Write unit tests', completed: false, priority: 'medium' },
|
||||
{ id: 5, title: 'Deploy to staging', completed: false, priority: 'low' }
|
||||
];
|
||||
this.settings = {
|
||||
theme: 'light',
|
||||
notifications: true
|
||||
};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupNavigation();
|
||||
this.loadDashboardData();
|
||||
this.renderTasks();
|
||||
this.generateChart();
|
||||
this.setupTaskFilter();
|
||||
this.loadSettings();
|
||||
|
||||
// Simulate real-time updates
|
||||
setInterval(() => this.updateRealtimeData(), 5000);
|
||||
}
|
||||
|
||||
setupNavigation() {
|
||||
document.querySelectorAll('.nav-item').forEach(item => {
|
||||
item.addEventListener('click', (e) => {
|
||||
const page = e.target.dataset.page;
|
||||
this.navigateToPage(page);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle browser back/forward
|
||||
window.addEventListener('popstate', (e) => {
|
||||
const page = e.state?.page || 'dashboard';
|
||||
this.navigateToPage(page, false);
|
||||
});
|
||||
|
||||
// Set initial URL
|
||||
history.replaceState({ page: 'dashboard' }, '', '/spa/dashboard');
|
||||
}
|
||||
|
||||
navigateToPage(page, pushState = true) {
|
||||
// Hide current page
|
||||
document.querySelector('.page.active').classList.remove('active');
|
||||
document.querySelector('.nav-item.active').classList.remove('active');
|
||||
|
||||
// Show new page
|
||||
document.getElementById(page).classList.add('active');
|
||||
document.querySelector(`[data-page="${page}"]`).classList.add('active');
|
||||
|
||||
this.currentPage = page;
|
||||
|
||||
// Update URL
|
||||
if (pushState) {
|
||||
history.pushState({ page }, '', `/spa/${page}`);
|
||||
}
|
||||
|
||||
// Load page-specific data
|
||||
this.loadPageData(page);
|
||||
}
|
||||
|
||||
loadPageData(page) {
|
||||
switch (page) {
|
||||
case 'dashboard':
|
||||
this.loadDashboardData();
|
||||
break;
|
||||
case 'tasks':
|
||||
this.renderTasks();
|
||||
break;
|
||||
case 'analytics':
|
||||
this.generateChart();
|
||||
break;
|
||||
case 'settings':
|
||||
this.loadSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loadDashboardData() {
|
||||
// Simulate API loading
|
||||
setTimeout(() => {
|
||||
document.getElementById('total-tasks').textContent = this.tasks.length;
|
||||
document.getElementById('completed-today').textContent =
|
||||
this.tasks.filter(t => t.completed).length;
|
||||
document.getElementById('active-projects').textContent = '3';
|
||||
document.getElementById('team-members').textContent = '12';
|
||||
|
||||
// Load recent activity
|
||||
const activityEl = document.getElementById('recent-activity');
|
||||
activityEl.innerHTML = `
|
||||
<div style="space-y: 0.5rem;">
|
||||
<div>✅ Task "Setup development environment" completed</div>
|
||||
<div>📝 New task "Design user interface mockups" created</div>
|
||||
<div>👥 Team member John joined the project</div>
|
||||
<div>🚀 Project "Web Application" moved to review</div>
|
||||
</div>
|
||||
`;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
renderTasks() {
|
||||
const taskList = document.getElementById('task-list');
|
||||
taskList.innerHTML = this.tasks.map(task => `
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox"
|
||||
${task.completed ? 'checked' : ''}
|
||||
onchange="app.toggleTask(${task.id})">
|
||||
<span class="task-text ${task.completed ? 'task-completed' : ''}">
|
||||
${task.title}
|
||||
</span>
|
||||
<span class="task-priority" style="
|
||||
color: ${task.priority === 'high' ? '#ef4444' :
|
||||
task.priority === 'medium' ? '#f59e0b' : '#6b7280'};
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
">${task.priority.toUpperCase()}</span>
|
||||
<button class="task-delete" onclick="app.deleteTask(${task.id})">Delete</button>
|
||||
</li>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
setupTaskFilter() {
|
||||
const filterInput = document.getElementById('task-filter');
|
||||
if (filterInput) {
|
||||
filterInput.addEventListener('input', (e) => {
|
||||
const filter = e.target.value.toLowerCase();
|
||||
const taskItems = document.querySelectorAll('.task-item');
|
||||
|
||||
taskItems.forEach(item => {
|
||||
const text = item.querySelector('.task-text').textContent.toLowerCase();
|
||||
item.style.display = text.includes(filter) ? 'flex' : 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toggleTask(id) {
|
||||
const task = this.tasks.find(t => t.id === id);
|
||||
if (task) {
|
||||
task.completed = !task.completed;
|
||||
this.renderTasks();
|
||||
this.loadDashboardData(); // Update dashboard stats
|
||||
}
|
||||
}
|
||||
|
||||
deleteTask(id) {
|
||||
this.tasks = this.tasks.filter(t => t.id !== id);
|
||||
this.renderTasks();
|
||||
this.loadDashboardData();
|
||||
}
|
||||
|
||||
addTask(title, description, priority) {
|
||||
const newTask = {
|
||||
id: Date.now(),
|
||||
title,
|
||||
description,
|
||||
priority,
|
||||
completed: false
|
||||
};
|
||||
this.tasks.push(newTask);
|
||||
this.renderTasks();
|
||||
this.loadDashboardData();
|
||||
}
|
||||
|
||||
generateChart() {
|
||||
const chartContainer = document.getElementById('completion-chart');
|
||||
if (!chartContainer) return;
|
||||
|
||||
// Generate random chart data
|
||||
const data = Array.from({ length: 7 }, () => Math.floor(Math.random() * 100) + 20);
|
||||
|
||||
chartContainer.innerHTML = data.map(value => `
|
||||
<div class="chart-bar" style="height: ${value}%;" title="${value}%"></div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
loadSettings() {
|
||||
const themeSelect = document.getElementById('theme-select');
|
||||
const notificationsCheck = document.getElementById('notifications-enabled');
|
||||
|
||||
if (themeSelect) themeSelect.value = this.settings.theme;
|
||||
if (notificationsCheck) notificationsCheck.checked = this.settings.notifications;
|
||||
}
|
||||
|
||||
saveSettings() {
|
||||
const themeSelect = document.getElementById('theme-select');
|
||||
const notificationsCheck = document.getElementById('notifications-enabled');
|
||||
|
||||
this.settings.theme = themeSelect.value;
|
||||
this.settings.notifications = notificationsCheck.checked;
|
||||
|
||||
// Simulate save to server
|
||||
alert('Settings saved successfully!');
|
||||
}
|
||||
|
||||
updateRealtimeData() {
|
||||
// Simulate real-time updates
|
||||
const now = new Date();
|
||||
const timeElement = document.querySelector('.timestamp');
|
||||
if (timeElement) {
|
||||
timeElement.textContent = now.toLocaleTimeString();
|
||||
}
|
||||
|
||||
// Add random activity
|
||||
if (Math.random() < 0.3 && this.currentPage === 'dashboard') {
|
||||
this.loadDashboardData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modal functions
|
||||
function openAddTaskModal() {
|
||||
document.getElementById('add-task-modal').classList.add('active');
|
||||
}
|
||||
|
||||
function closeAddTaskModal() {
|
||||
document.getElementById('add-task-modal').classList.remove('active');
|
||||
document.getElementById('add-task-form').reset();
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
app.saveSettings();
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
document.getElementById('add-task-form').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const title = document.getElementById('task-title').value;
|
||||
const description = document.getElementById('task-description').value;
|
||||
const priority = document.getElementById('task-priority').value;
|
||||
|
||||
app.addTask(title, description, priority);
|
||||
closeAddTaskModal();
|
||||
});
|
||||
|
||||
// Initialize app
|
||||
const app = new TaskFlowApp();
|
||||
|
||||
// Global test data for Crawailer testing
|
||||
window.testData = {
|
||||
appName: 'TaskFlow',
|
||||
version: '2.1.0',
|
||||
framework: 'Vanilla JS SPA',
|
||||
routes: ['dashboard', 'tasks', 'analytics', 'settings'],
|
||||
features: ['routing', 'state-management', 'real-time-updates', 'modals'],
|
||||
totalTasks: () => app.tasks.length,
|
||||
completedTasks: () => app.tasks.filter(t => t.completed).length,
|
||||
getCurrentPage: () => app.currentPage,
|
||||
getSettings: () => app.settings,
|
||||
generateTimestamp: () => new Date().toISOString()
|
||||
};
|
||||
|
||||
// Console logging for testing
|
||||
console.log('TaskFlow SPA initialized');
|
||||
console.log('Test data available at window.testData');
|
||||
console.log('Current route:', window.location.pathname);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue