diff --git a/sde_collections/urls.py b/sde_collections/urls.py index 98a1df06..7c17feb1 100644 --- a/sde_collections/urls.py +++ b/sde_collections/urls.py @@ -19,6 +19,7 @@ urlpatterns = [ path("", view=views.CollectionListView.as_view(), name="list"), + path("sde-dashboard/", view=views.SdeDashboardView.as_view(), name="dashboard"), path("/", view=views.CollectionDetailView.as_view(), name="detail"), path( "api/collections/push_to_github/", diff --git a/sde_collections/views.py b/sde_collections/views.py index 3873a9f1..374910a3 100644 --- a/sde_collections/views.py +++ b/sde_collections/views.py @@ -216,6 +216,24 @@ def get_context_data(self, **kwargs): return context +class SdeDashboardView(LoginRequiredMixin,ListView ): + + model = Collection + template_name = "sde_collections/sde_dashboard.html" + context_object_name = "collections" + + def get_queryset(self): + return ( + super() + .get_queryset() + ) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["segment"] = "collections" + return context + + class CollectionFilterMixin: def get_queryset(self): @@ -367,14 +385,13 @@ def create(self, request, *args, **kwargs): class CollectionViewSet(viewsets.ModelViewSet): queryset = Collection.objects.all() - serializer_class = CollectionSerializer class CollectionReadViewSet(viewsets.ReadOnlyModelViewSet): queryset = Collection.objects.all() serializer_class = CollectionReadSerializer -class PushToGithubView(APIView): +class PushToGithubView(APIView): def post(self, request): collection_ids = request.POST.getlist("collection_ids[]", []) if len(collection_ids) == 0: diff --git a/sde_indexing_helper/static/css/candidate_url_list.css b/sde_indexing_helper/static/css/candidate_url_list.css index 3b45355e..615d4704 100644 --- a/sde_indexing_helper/static/css/candidate_url_list.css +++ b/sde_indexing_helper/static/css/candidate_url_list.css @@ -99,39 +99,6 @@ .select-dropdown.focus { box-shadow: none, 0 0 0 0.2rem rgba(76, 175, 80, 0.5); } - - -.tab-nav { - color: black; - padding-right: 25px; - padding-left: 25px; - font-weight: 500; -} - -/* tab headers hover effect */ -.tab-nav:hover { - text-decoration: underline; - color: #0066CA; -} - -/* alligning tab container with the table */ -.nav-tabs { - padding-left: 0px; -} - -/* active tab */ -.nav-item > .active { - color: #0066CA; - font-weight: 700; - border-bottom: 3px solid #FF3D57; - padding-bottom: 15px; -} - -/* line under the tab options */ -div > .nav { - padding-bottom: 15px; - border-bottom: 1px solid #F8FAFB; -} /* badge showing workflow status by header */ .badge { @@ -279,11 +246,7 @@ letter-spacing: -0.02em; font-weight: 500; } - .pageTitle{ - font-size:56px; - color:white; - font-weight:500; - } + .custom-select, .buttons-csv, .customizeColumns, .addPattern{ border-style: solid !important; diff --git a/sde_indexing_helper/static/css/project.css b/sde_indexing_helper/static/css/project.css index 33d8476c..376ddfad 100644 --- a/sde_indexing_helper/static/css/project.css +++ b/sde_indexing_helper/static/css/project.css @@ -365,6 +365,11 @@ body { } +.pageTitle{ + font-size:56px; + color:white; + font-weight:500; + } /* base_auth.html layout css */ .auth-wrapper { @@ -572,8 +577,43 @@ height: 38px; justify-content: center; } +.tab-nav { + color: black; + padding-right: 25px; + padding-left: 25px; + font-weight: 500; +} + .dropdown-menu { z-index: 1030; } +/* tab headers hover effect */ +.tab-nav:hover { + text-decoration: underline; + color: #0066CA; +} + +/* alligning tab container with the table */ +.nav-tabs { + padding-left: 0px; +} + +/* active tab */ +.nav-item > .active { + color: #0066CA; + font-weight: 700; + border-bottom: 3px solid #FF3D57; + padding-bottom: 15px; +} + +/* line under the tab options */ +div > .nav { + padding-bottom: 15px; + border-bottom: 1px solid #F8FAFB; +} +.divisionDropdown { + appearance: auto !important; + padding:10px; +} \ No newline at end of file diff --git a/sde_indexing_helper/static/css/sde_dashboard.css b/sde_indexing_helper/static/css/sde_dashboard.css new file mode 100644 index 00000000..76cba047 --- /dev/null +++ b/sde_indexing_helper/static/css/sde_dashboard.css @@ -0,0 +1,11 @@ +.dashboardContainer { + background: #15232E; + padding: 40px 30px; + border-radius: 15px; +} + +.filterDiv { + float: right; + margin-top: 10px; +} + diff --git a/sde_indexing_helper/static/js/sde_dashboard.js b/sde_indexing_helper/static/js/sde_dashboard.js new file mode 100644 index 00000000..a5da0139 --- /dev/null +++ b/sde_indexing_helper/static/js/sde_dashboard.js @@ -0,0 +1,576 @@ +////////////////// Division //////////////////////////// +let divisionChart = document.getElementById("divisionChart").getContext("2d"); + +const labels = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", + "November", "December" +]; +const divisionData = { + labels: labels, + datasets: [{ + label: 'Total SDE Entries', + data: [65, 59, 80, 81, 56, 55, 40, 43, 7, 50, 12, 52], + fill: true, + borderColor: '#65B1EF', + tension: 0.1 + }] +}; + +const stackedLine = new Chart(divisionChart, { + type: 'line', + data: divisionData, + options: { + + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Total SDE Entries', + position: 'top', + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + subtitle: { + display: true, + position: 'top', + align: 'start', + padding: 10, + text: '3000', + color: '#65B1EF', + font: { + size: 24, + family: 'sans-serif', + weight: '700', + }, + }, + }, + scales: { + y: { + stacked: true, + grid: { + color: '#A7BACD' + }, + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Number of Entries', + color:'white' + } + }, + x: { + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Months', + color:'white' + } + } + } + } +}); +///////////////////////////////////////////// +////// candidiate urls ///////////////////// +let urlChart = document.getElementById("urlChart").getContext("2d"); + +const urlData = { + labels: labels, + datasets: [{ + label: 'Total Scraped URLs', + data: [6512, 59, 800, 81, 56, 55, 40, 4300, 7, 50, 120, 520], + fill: true, + borderColor: '#65B1EF', + tension: 0.1 + }] +}; + +const stackedLine2 = new Chart(urlChart, { + type: 'line', + data: urlData, + options: { + + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Total Scraped URLs', + position: 'top', + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + subtitle: { + display: true, + position: 'top', + align: 'start', + padding: 10, + text: '5280', + color: '#65B1EF', + font: { + size: 24, + family: 'sans-serif', + weight: '700', + }, + }, + }, + scales: { + y: { + stacked: true, + grid: { + color: '#A7BACD' + }, + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Number of URLs', + color:'white' + } + }, + x: { + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Months', + color:'white' + } + } + } + } +}); +////////////////////////////////////////////////////////////// +/////////////// Workflow status /////////////////////////////// +let workflowChart = document.getElementById("workflowChart").getContext("2d"); + +const workflowData = { + labels: ["Research in Progress", "Ready for Engineering", "Engineering in Progress", "Ready for Curation", + "Curation in Progress", + "Curated", + "Quality Fixed", + "Secret Deployment Started", + "Secret Deployment Failed", + "Ready for LRM Quality Check", + "Ready for Quality Check", + "Quality Check Failed", + "Ready for Public Production", + "Perfect and on Production", + "Low Priority Problems on Production", + "High Priority Problems on Production, only for old sources", + "Code Merge Pending" + ], + datasets: [{ + label: 'Total', + data: [651, 59, 800, 81, 56, 550, 40, 430, 7, 50, 120, 520, 13, 14, 15, 16, 17], + backgroundColor: [ + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + ], + borderColor: [ + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + ], + borderWidth: 1 + + }] +}; + +const barChart = new Chart(workflowChart, { + type: 'bar', + data: workflowData, + options: { + + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Workflow Status Totals', + position: 'top', + padding: 20, + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + }, + scales: { + y: { + beginAtZero: true, + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Totals', + color:'white' + } + }, + x: { + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Statuses', + color:'white' + } + } + + } + } +}); +/////////////////////////////////////////////////////////////// +///////////////// Curator ///////////////////////// +let sdeChart = document.getElementById("sdeChart").getContext("2d"); + +const stackedLine3 = new Chart(sdeChart, { + type: 'line', + data: divisionData, + options: { + + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Total SDE Entries', + position: 'top', + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + subtitle: { + display: true, + position: 'top', + align: 'start', + padding: 10, + text: '3000', + color: '#65B1EF', + font: { + size: 24, + family: 'sans-serif', + weight: '700', + }, + }, + }, + scales: { + y: { + stacked: true, + grid: { + color: '#A7BACD' + }, + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Number of Entries', + color:'white' + } + }, + x: { + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Months', + color:'white' + } + } + } + } +}); + + +let divisionChart2 = document.getElementById("divisionChart2").getContext("2d"); + +const division2Data = { + labels: ["Astrophysics", "Biological and Physical Sciences", "Earth Science", + "Heliophysics", "Planetary Science", "General" + ], + datasets: [{ + label: 'Total', + data: [25, 90, 120, 12, 56, 132], + backgroundColor: [ + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + ], + borderColor: [ + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + '#65B1EF', + ], + borderWidth: 1 + + }] +}; + +const barChart2 = new Chart(divisionChart2, { + type: 'bar', + data: division2Data, + options: { + + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Entries by Division', + position: 'top', + padding: 20, + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + subtitle: { + display: true, + position: 'top', + align: 'start', + padding: 10, + text: '4561', + color: '#65B1EF', + font: { + size: 24, + family: 'sans-serif', + weight: '700', + }, + }, + }, + scales: { + y: { + beginAtZero: true, + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Totals', + color:'white' + } + }, + x: { + ticks: { + color: "white", + beginAtZero: true + }, + title:{ + display:true, + text: 'Divisions', + color:'white' + } + } + + } + } +}); + +let pieChart = document.getElementById("pieChart").getContext("2d"); + +const pieChartData = { + labels: [ + 'Not Started', + 'In Progress', + 'In Production' + ], + datasets: [{ + label: 'Workflow Status Completion', + data: [300, 50, 100], + backgroundColor: [ + '#F4C534', + '#09B66D', + '#65B1EF' + ], + hoverOffset: 4 + }] + }; + + const doughnutChart = new Chart(pieChart, { + type: 'doughnut', + data: pieChartData, + options: { + + plugins: { + legend: { + display: true, + position:'bottom', + labels: { + color:'white' + } + }, + title: { + display: true, + text: 'Workflow Status Completion', + position: 'top', + padding: 20, + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + }, + } + + }); + + let timeSpentChart = document.getElementById("timeSpentChart").getContext("2d"); + + +const timeLabels = ["12 AM", "8 AM", "4 PM", "11 PM"]; + +const notStartedData = { + labels: timeLabels, + datasets: [{ + label: 'Not Started', + data: [250, 390, 400, 81], + fill: true, + borderColor: '#65B1EF', + tension: 0.1 + }, + { + label: 'In Production', + data: [150, 590, 20, 810], + fill: true, + borderColor: 'red', + tension: 0.1 + }, + { + label: 'In Progress', + data: [20, 293, 630, 124], + fill: true, + borderColor: 'green', + tension: 0.1 + }] +}; + + +const stackedLine4 = new Chart(timeSpentChart, { + type: 'line', + data: notStartedData, + options: { + + plugins: { + legend: { + display: true, + position:'bottom', + labels: { + color:'white' + } + }, + title: { + display: true, + text: 'Total time spent', + position: 'top', + align: 'start', + color: '#A7BACD', + font: { + family: 'sans-serif', + size: 14, + weight: '400', + }, + }, + }, + scales: { + y: { + stacked: true, + grid: { + color: '#A7BACD' + }, + title:{ + display:true, + text: 'Number of Entries', + color:'white' + } + }, + x: { + title:{ + display:true, + text: 'Time', + color:'white' + } + } + } + } +}); + diff --git a/sde_indexing_helper/templates/includes/navigation.html b/sde_indexing_helper/templates/includes/navigation.html index 01183f6c..658b4275 100644 --- a/sde_indexing_helper/templates/includes/navigation.html +++ b/sde_indexing_helper/templates/includes/navigation.html @@ -50,6 +50,7 @@ diff --git a/sde_indexing_helper/templates/sde_collections/sde_dashboard.html b/sde_indexing_helper/templates/sde_collections/sde_dashboard.html new file mode 100644 index 00000000..c4a7d90b --- /dev/null +++ b/sde_indexing_helper/templates/sde_collections/sde_dashboard.html @@ -0,0 +1,115 @@ +{% extends "layouts/base.html" %} +{% load static %} +{% block title %} +{{ collection.name }} +{% endblock title %} +{% block stylesheets %} +{{ block.super }} + + +{% endblock stylesheets %} + +{% block content %} + +
+

SDE Dashboard

+
+
+ + + + +
+
+
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+
+
+ +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +{% endblock content %} +{% block javascripts %} + + + +{% endblock javascripts %} \ No newline at end of file