diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index d41890e5..ee6afeeb 100644 Binary files a/osinaweb/db.sqlite3 and b/osinaweb/db.sqlite3 differ diff --git a/osinaweb/osinacore/__pycache__/urls.cpython-313.pyc b/osinaweb/osinacore/__pycache__/urls.cpython-313.pyc index 36def678..584d09f6 100644 Binary files a/osinaweb/osinacore/__pycache__/urls.cpython-313.pyc and b/osinaweb/osinacore/__pycache__/urls.cpython-313.pyc differ diff --git a/osinaweb/osinacore/__pycache__/views.cpython-313.pyc b/osinaweb/osinacore/__pycache__/views.cpython-313.pyc index 9375ab1b..19d2e764 100644 Binary files a/osinaweb/osinacore/__pycache__/views.cpython-313.pyc and b/osinaweb/osinacore/__pycache__/views.cpython-313.pyc differ diff --git a/osinaweb/osinacore/templates/projects-dashboard.html b/osinaweb/osinacore/templates/projects-dashboard.html new file mode 100644 index 00000000..942ae031 --- /dev/null +++ b/osinaweb/osinacore/templates/projects-dashboard.html @@ -0,0 +1,117 @@ +{% extends "main.html" %} +{% load static %} +{% block content %} + + + + +
+
+

Projects Dashboard

+
+ +
+
+
+
+

From:

+ +
+
+

To:

+ +
+
+ +
+
+

Projects

+ +
+ +
+

Staff

+ +
+
+ + +
+
+ +
+ + + + + + + + + + + {% for task in tasks %} + + + + + + + {% endfor %} + +
ProjectStatusDateStaff
{{ task.project.name }}{{ task.status }}{{ task.start_date }}{{ task.assigned_to.user.first_name }} {{ task.assigned_to.user.last_name }}
+
+
+ + + +{% endblock content %} \ No newline at end of file diff --git a/osinaweb/osinacore/urls.py b/osinaweb/osinacore/urls.py index 0809ef37..20175249 100644 --- a/osinaweb/osinacore/urls.py +++ b/osinaweb/osinacore/urls.py @@ -91,6 +91,7 @@ urlpatterns = [ path('fetch_epics/', views.fetch_epics, name='fetch_epics'), path('projects/status//', views.fetch_projects_by_status, name='projects_by_status'), path('all-projects/', views.fetch_projects_by_status, name='all_projects'), + path('projects-dashboard/', views.projects_dashboard, name='projects_dashboard'), ] diff --git a/osinaweb/osinacore/views.py b/osinaweb/osinacore/views.py index 65dfdf00..482e9dd7 100644 --- a/osinaweb/osinacore/views.py +++ b/osinaweb/osinacore/views.py @@ -893,10 +893,6 @@ def addressbookdetails(request, addressbook_id): @staff_login_required def prospecting_lists(request): Country.objects.get_or_create(name='Lebanon') - Group.objects.get_or_create(name='Test Group 1') - Group.objects.get_or_create(name='Test Group 2') - Group.objects.get_or_create(name='Test Group 3') - Group.objects.get_or_create(name='Test Group 4') query = request.GET.get('q', '') lists = ProspectingList.objects.all() @@ -910,3 +906,55 @@ def prospecting_lists(request): 'lists': lists, } return render(request, 'listing_pages/prospecting-lists.html', context) + + +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 + all_projects = Project.objects.all() + all_staff = StaffProfile.objects.all() + + # Initialize variables + selected_project_ids = [] + selected_staff_ids = [] + start_date = None + end_date = None + + # Get filter parameters from GET request + if request.method == 'GET': + selected_project_ids = request.GET.getlist('projects', []) + selected_staff_ids = request.GET.getlist('staff', []) + start_date_str = request.GET.get('start_date', '') + end_date_str = request.GET.get('end_date', '') + + # Parse dates + 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() + + if selected_project_ids: + tasks = tasks.filter(project__id__in=selected_project_ids) + + if selected_staff_ids: + tasks = tasks.filter(assigned_to__id__in=selected_staff_ids) + + if start_date and end_date: + tasks = tasks.filter(end_date__range=[start_date, end_date]) + + context = { + 'projects': all_projects, + 'staffs': all_staff, # Changed from 'staff' to match your template + 'tasks': tasks, + '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 '', + 'end_date': end_date_str if end_date else '', + } + + return render(request, "projects-dashboard.html", context) \ No newline at end of file diff --git a/osinaweb/static/dist/output.css b/osinaweb/static/dist/output.css index d8f19388..d0b91e2c 100644 --- a/osinaweb/static/dist/output.css +++ b/osinaweb/static/dist/output.css @@ -1473,6 +1473,10 @@ video { max-width: 48rem; } +.max-w-\[300px\] { + max-width: 300px; +} + .max-w-\[80\%\] { max-width: 80%; } @@ -1501,6 +1505,10 @@ video { flex-grow: 0; } +.table-auto { + table-layout: auto; +} + .border-collapse { border-collapse: collapse; } @@ -1619,6 +1627,10 @@ video { resize: both; } +.list-inside { + list-style-position: inside; +} + .list-disc { list-style-type: disc; } @@ -1753,6 +1765,10 @@ video { align-self: flex-end; } +.self-center { + align-self: center; +} + .justify-self-end { justify-self: end; } @@ -1819,6 +1835,10 @@ video { border-radius: 0px; } +.rounded-xl { + border-radius: 0.75rem; +} + .rounded-b-md { border-bottom-right-radius: 0.375rem; border-bottom-left-radius: 0.375rem; @@ -3791,6 +3811,10 @@ video { width: 480px; } + .lg\:flex-row { + flex-direction: row; + } + .lg\:text-\[48px\] { font-size: 48px; } diff --git a/osinaweb/static/js/projects-dashboard.js b/osinaweb/static/js/projects-dashboard.js new file mode 100644 index 00000000..5f643fbb --- /dev/null +++ b/osinaweb/static/js/projects-dashboard.js @@ -0,0 +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 = ` + ${task.project_name} + ${task.status} + ${task.start_date} + ${task.staff} + `; + 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); + });