emile 1 month ago
parent a1ebd69efc
commit 64a831f2be

@ -2,12 +2,12 @@
{% load static %}
{% block content %}
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/js/tom-select.complete.min.js"></script>
<div class="h-fit w-full flex flex-col items gap-5 rounded-xl bg-gray-50 shadow-md p-5">
<div class="flex flex-row gap-3 justify-between items-center">
<h1 class="text-2xl text-secondosiblue text-center font-semibold">Projects Dashboard</h1>
<h1 class="font-semibold text-xl text-primary">Projects Dashboard</h1>
</div>
<form method="get" id="filter-form">
@ -17,20 +17,20 @@
<p>From:</p>
<input name="start_date" id="start-date" type="date"
value="{{ start_date }}"
class="w-full border rounded-md outline-none focus:border-primary p-2" />
class="w-full border rounded-md outline-none focus:border-primary p-2">
</div>
<div class="w-full max-w-[300px] flex flex-row gap-2 items-center">
<p>To:</p>
<input name="end_date" id="end-date" type="date"
value="{{ end_date }}"
class="w-full border rounded-md outline-none focus:border-primary p-2" />
class="w-full border rounded-md outline-none focus:border-primary p-2">
</div>
</div>
<div class="w-full flex flex-row flex-wrap gap-5">
<div class="w-full flex flex-1 flex-col items-center">
<p class="font-medium text-secondary">Projects</p>
<select name="projects" id="projects" class="w-full h-full rounded-md z-10 confirm-exit-input" multiple>
<select name="projects" id="projects" class="w-full h-full rounded-md z-10" multiple>
{% for project in projects %}
<option value="{{ project.id }}"
{% if project.id in selected_projects %}selected{% endif %}>
@ -42,11 +42,11 @@
<div class="w-full flex-1 flex flex-col items-center">
<p class="font-medium text-secondary">Staff</p>
<select name="staff" id="staff" class="w-full h-full rounded-md z-10 confirm-exit-input" multiple>
<select name="staff" id="staff" class="w-full h-full rounded-md z-10" multiple>
{% for staff in staffs %}
<option value="{{ staff.id }}"
{% if staff.id in selected_staff %}selected{% endif %}>
{{ staff.user.first_name }} {{ staff.user.last_name }}
{{ staff.name }}
</option>
{% endfor %}
</select>
@ -59,23 +59,53 @@
</div>
</form>
<div class="w-full flex flex-col gap-10 justify-center items-center">
<table class="table-auto w-full">
<thead>
<div class="w-full overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Project</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Status</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Date</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Staff</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Project</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Task</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Point</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Assigned To</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time Spent</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Activity</th>
</tr>
</thead>
<tbody id="status-table-body">
{% for task in tasks %}
<tbody class="bg-white divide-y divide-gray-200">
{% for point in points %}
<tr>
<td class="px-6 py-4 whitespace-nowrap">{{ point.task.project.name }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ point.task.name }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ point.text }}</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
{% if point.status == 'Completed' %}bg-green-100 text-green-800
{% elif point.status == 'Working On' %}bg-blue-100 text-blue-800
{% elif point.status == 'Paused' %}bg-yellow-100 text-yellow-800
{% else %}bg-red-100 text-red-800{% endif %}">
{{ point.status }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">{{ point.task.assigned_to.name }}</td>
<td class="px-6 py-4 whitespace-nowrap">
{% with point.total_activity_time as time %}
{{ time.0 }}h {{ time.1 }}m {{ time.2 }}s
{% endwith %}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{% with point.pointactivity_set.last as last_activity %}
{% if last_activity %}
{{ last_activity.end_time|date:"Y-m-d H:i" }}
{% else %}
No activity
{% endif %}
{% endwith %}
</td>
</tr>
{% empty %}
<tr>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.project.name }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.status }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.start_date }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.assigned_to.user.first_name }} {{ task.assigned_to.user.last_name }}</td>
<td colspan="7" class="px-6 py-4 text-center">No points found with the current filters</td>
</tr>
{% endfor %}
</tbody>

@ -911,7 +911,6 @@ def prospecting_lists(request):
from django.utils.dateparse import parse_date
from django.shortcuts import render
@staff_login_required
def projects_dashboard(request):
# Get all projects and staff for the dropdowns
@ -935,22 +934,24 @@ def projects_dashboard(request):
start_date = parse_date(start_date_str) if start_date_str else None
end_date = parse_date(end_date_str) if end_date_str else None
# Filter tasks based on parameters
tasks = Task.objects.all()
# Filter points based on parameters
points = Point.objects.select_related('task__project', 'task__assigned_to').prefetch_related('pointactivity_set')
if selected_project_ids:
tasks = tasks.filter(project__id__in=selected_project_ids)
points = points.filter(task__project__id__in=selected_project_ids)
if selected_staff_ids:
tasks = tasks.filter(assigned_to__id__in=selected_staff_ids)
points = points.filter(task__assigned_to__id__in=selected_staff_ids)
if start_date and end_date:
tasks = tasks.filter(end_date__range=[start_date, end_date])
points = points.filter(
pointactivity__end_time__date__range=[start_date, end_date]
).distinct()
context = {
'projects': all_projects,
'staffs': all_staff, # Changed from 'staff' to match your template
'tasks': tasks,
'staffs': all_staff,
'points': points,
'selected_projects': [int(id) for id in selected_project_ids if id],
'selected_staff': [int(id) for id in selected_staff_ids if id],
'start_date': start_date_str if start_date else '',

@ -1,61 +1,61 @@
document.addEventListener('DOMContentLoaded', function () {
// Initialize TomSelect for Projects
new TomSelect('#projects', {
create: false, // Disable creating new options
sortField: 'text',
onChange: function(values) {
updateTasks(); // Update tasks on value change
}
});
// Initialize TomSelect for Staff
new TomSelect('#staff', {
create: false,
sortField: 'text',
onChange: function(values) {
updateTasks(); // Update tasks on value change
}
});
// Update tasks based on filters
function updateTasks() {
const projectIds = Array.from(document.getElementById('projects').selectedOptions).map(option => option.value);
const staffIds = Array.from(document.getElementById('staff').selectedOptions).map(option => option.value);
const startDate = document.getElementById('start-date').value;
const endDate = document.getElementById('end-date').value;
// Construct the query parameters without brackets around the projectIds
let queryParams = `?projects=${projectIds.join(',')}&staff=${staffIds.join(',')}&start_date=${startDate}&end_date=${endDate}`;
// Perform AJAX request
fetch(`/projects-dashboard/${queryParams}`, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
})
.then(response => response.json())
.then(data => {
// Update table body with new data
const tbody = document.getElementById('status-table-body');
tbody.innerHTML = ''; // Clear the existing table rows
data.tasks_data.forEach(task => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${task.project_name}</td>
<td>${task.status}</td>
<td>${task.start_date}</td>
<td>${task.staff}</td>
`;
tbody.appendChild(tr);
});
})
.catch(error => {
console.error('Error updating tasks:', error);
});
}
// Trigger update when date range changes
document.getElementById('start-date').addEventListener('change', updateTasks);
document.getElementById('end-date').addEventListener('change', updateTasks);
});
// document.addEventListener('DOMContentLoaded', function () {
// // Initialize TomSelect for Projects
// new TomSelect('#projects', {
// create: false, // Disable creating new options
// sortField: 'text',
// onChange: function(values) {
// updateTasks(); // Update tasks on value change
// }
// });
//
// // Initialize TomSelect for Staff
// new TomSelect('#staff', {
// create: false,
// sortField: 'text',
// onChange: function(values) {
// updateTasks(); // Update tasks on value change
// }
// });
//
// // Update tasks based on filters
// function updateTasks() {
// const projectIds = Array.from(document.getElementById('projects').selectedOptions).map(option => option.value);
// const staffIds = Array.from(document.getElementById('staff').selectedOptions).map(option => option.value);
// const startDate = document.getElementById('start-date').value;
// const endDate = document.getElementById('end-date').value;
//
// // Construct the query parameters without brackets around the projectIds
// let queryParams = `?projects=${projectIds.join(',')}&staff=${staffIds.join(',')}&start_date=${startDate}&end_date=${endDate}`;
//
// // Perform AJAX request
// fetch(`/projects-dashboard/${queryParams}`, {
// method: 'GET',
// headers: {
// 'X-Requested-With': 'XMLHttpRequest',
// },
// })
// .then(response => response.json())
// .then(data => {
// // Update table body with new data
// const tbody = document.getElementById('status-table-body');
// tbody.innerHTML = ''; // Clear the existing table rows
// data.tasks_data.forEach(task => {
// const tr = document.createElement('tr');
// tr.innerHTML = `
// <td>${task.project_name}</td>
// <td>${task.status}</td>
// <td>${task.start_date}</td>
// <td>${task.staff}</td>
// `;
// tbody.appendChild(tr);
// });
// })
// .catch(error => {
// console.error('Error updating tasks:', error);
// });
// }
//
// // Trigger update when date range changes
// document.getElementById('start-date').addEventListener('change', updateTasks);
// document.getElementById('end-date').addEventListener('change', updateTasks);
// });

Loading…
Cancel
Save