Add booking utilization chart 81/20881/1
authormaxbr <maxbr@mi.fu-berlin.de>
Mon, 12 Sep 2016 09:08:56 +0000 (11:08 +0200)
committermaxbr <maxbr@mi.fu-berlin.de>
Mon, 12 Sep 2016 09:08:56 +0000 (11:08 +0200)
JIRA: PHAROS-263

Change-Id: I3a3a5115a1cf7742f9ac5a3ec753699c36b49815
Signed-off-by: maxbr <maxbr@mi.fu-berlin.de>
13 files changed:
tools/pharos-dashboard/.gitignore
tools/pharos-dashboard/account/jira_util.py
tools/pharos-dashboard/dashboard/models.py
tools/pharos-dashboard/dashboard/templatetags/jira_filters.py
tools/pharos-dashboard/dashboard/urls.py
tools/pharos-dashboard/dashboard/views.py
tools/pharos-dashboard/static/bower.json
tools/pharos-dashboard/static/js/flot-pie-chart.js [new file with mode: 0644]
tools/pharos-dashboard/templates/dashboard/resource.html
tools/pharos-dashboard/templates/dashboard/resource_all.html
tools/pharos-dashboard/templates/dashboard/resource_detail.html
tools/pharos-dashboard/templates/dashboard/server_table.html
tools/pharos-dashboard/templates/layout.html

index 9eb1cfd..2b73909 100644 (file)
@@ -20,6 +20,7 @@ coverage.xml
 *.log
 *.pot
 migrations/
+settings.py
 
 # KDE:
 .directory
index bd07ff3..c066a68 100644 (file)
@@ -5,7 +5,7 @@ import oauth2 as oauth
 from jira import JIRA
 from tlslite.utils import keyfactory
 
-from pharos_dashboard import settings
+from django.conf import settings
 
 
 class SignatureMethod_RSA_SHA1(oauth.SignatureMethod):
index d645cd5..734da38 100644 (file)
@@ -1,3 +1,6 @@
+from datetime import timedelta
+
+from django.utils import timezone
 from django.contrib.auth.models import User
 from django.db import models
 
@@ -9,9 +12,42 @@ class Resource(models.Model):
     name = models.CharField(max_length=100, unique=True)
     description = models.CharField(max_length=300, blank=True, null=True)
     url = models.CharField(max_length=100, blank=True, null=True)
-    owner = models.ForeignKey(User)
+    owner = models.ForeignKey(User, related_name='user_lab_owner', null=True)
+    vpn_users = models.ManyToManyField(User, related_name='user_vpn_users')
     slave = models.ForeignKey(JenkinsSlave, on_delete=models.DO_NOTHING, null=True)
 
+    def get_booking_utilization(self, weeks):
+        """
+        Return a dictionary containing the count of booked and free seconds for a resource in the
+        range [now,now + weeks] if weeks is positive,
+        or [now-weeks, now] if weeks is negative
+        """
+
+        length = timedelta(weeks=abs(weeks))
+        now = timezone.now()
+
+        start = now
+        end = now + length
+        if weeks < 0:
+            start = now - length
+            end = now
+
+        bookings = self.booking_set.filter(start__lt=start + length, end__gt=start)
+
+        booked_seconds = 0
+        for booking in bookings:
+            booking_start = booking.start
+            booking_end = booking.end
+            if booking_start < start:
+                booking_start = start
+            if booking_end > end:
+                booking_end = start + length
+            total = booking_end - booking_start
+            booked_seconds += total.total_seconds()
+
+        return {'booked_seconds': booked_seconds,
+                'available_seconds': length.total_seconds() - booked_seconds}
+
     class Meta:
         db_table = 'resource'
 
index d9c2761..1be0600 100644 (file)
@@ -1,6 +1,6 @@
 from django.template.defaultfilters import register
 
-from pharos_dashboard import settings
+from django.conf import settings
 
 
 @register.filter
index 809204c..baa2d63 100644 (file)
@@ -23,6 +23,9 @@ urlpatterns = [
     url(r'^jenkins_slaves/$', JenkinsSlavesView.as_view(), name='jenkins_slaves'),
     url(r'^resource/all/$', LabOwnerView.as_view(), name='resources'),
     url(r'^resource/(?P<resource_id>[0-9]+)/$', ResourceView.as_view(), name='resource'),
-
+    url(r'^resource/(?P<resource_id>[0-9]+)/booking_utilization/(?P<weeks>-?\d+)/$',
+        BookingUtilizationJSON.as_view(), name='booking_utilization'),
+    url(r'^resource/(?P<resource_id>[0-9]+)/jenkins_utilization/(?P<weeks>-?\d+)/$',
+        JenkinsUtilizationJSON.as_view(), name='jenkins_utilization'),
     url(r'^$', DevelopmentPodsView.as_view(), name="index"),
 ]
index ef1845c..8954f6c 100644 (file)
@@ -59,7 +59,8 @@ class ResourceView(TemplateView):
         utilization = resource.slave.get_utilization(timedelta(days=7))
         bookings = Booking.objects.filter(resource=resource, end__gt=timezone.now())
         context = super(ResourceView, self).get_context_data(**kwargs)
-        context.update({'title': str(resource), 'resource': resource, 'utilization': utilization, 'bookings': bookings})
+        context.update({'title': str(resource), 'resource': resource, 'utilization': utilization,
+                        'bookings': bookings})
         return context
 
 
@@ -76,3 +77,22 @@ class LabOwnerView(TemplateView):
         context = super(LabOwnerView, self).get_context_data(**kwargs)
         context.update({'title': "Overview", 'pods': pods})
         return context
+
+
+class BookingUtilizationJSON(View):
+    def get(self, request, *args, **kwargs):
+        resource = get_object_or_404(Resource, id=kwargs['resource_id'])
+        utilization = resource.get_booking_utilization(int(kwargs['weeks']))
+        utilization = [
+            {
+                'label': 'Booked',
+                'data': utilization['booked_seconds'],
+                'color': '#d9534f'
+            },
+            {
+                'label': 'Available',
+                'data': utilization['available_seconds'],
+                'color': '#5cb85c'
+            },
+        ]
+        return JsonResponse({'data': utilization})
index 7840621..f473747 100644 (file)
@@ -19,6 +19,6 @@
     "eonasdan-bootstrap-datetimepicker": "^4.17.37",
     "fullcalendar": "^2.9.0",
     "jquery-migrate": "^3.0.0",
-    "startbootstrap-sb-admin-2": "^1.0.9"
+    "startbootstrap-sb-admin-2-blackrockdigital": "^3.3.7"
   }
 }
diff --git a/tools/pharos-dashboard/static/js/flot-pie-chart.js b/tools/pharos-dashboard/static/js/flot-pie-chart.js
new file mode 100644 (file)
index 0000000..98d174e
--- /dev/null
@@ -0,0 +1,22 @@
+function loadChartData(chart_id, url) {
+    $.ajax({
+        url: url,
+        type: 'get',
+        success: function (data) {
+            var data = data['data'];
+            $(function () {
+                var plotObj = $.plot($("#" + chart_id), data, {
+                    series: {
+                        pie: {
+                            show: true
+                        }
+                    }
+                });
+            });
+        },
+        failure: function (data) {
+            alert('Error loading data');
+        }
+    });
+
+}
\ No newline at end of file
index 92d02f6..c9e5735 100644 (file)
     <script src="{% static "bower_components/flot/jquery.flot.time.js" %}"></script>
     <script src="{% static "bower_components/flot.tooltip/js/jquery.flot.tooltip.min.js" %}"></script>
 
+    <script src="{% static "js/flot-pie-chart.js" %}"></script>
+
     <script type="text/javascript">
         $(document).ready(function () {
             $('#{{ resource.id }}_server_table').DataTable({});
             $('#{{ resource.id }}_bookings_table').DataTable({});
+            $('#{{ resource.id }}_vpn_user_table').DataTable({});
 
-            $(function () {
-                var plotObj = $.plot($("#{{ resource.id }}_slave_utilization"), data_{{ resource.id }}, {
-                    series: {
-                        pie: {
-                            show: true
-                        }
-                    }
-                });
+            var chart_id = "{{ resource.id }}_booking_utilization";
+            var utilization_url = "{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}";
+            loadChartData(chart_id, utilization_url);
 
-            });
+            var chart_id = "{{ resource.id }}_jenkins_utilization";
+            var utilization_url = "{% url 'dashboard:jenkins_utilization' resource_id=resource.id weeks=1 %}";
+            loadChartData(chart_id, utilization_url);
         });
     </script>
 {% endblock extrajs %}
\ No newline at end of file
index 2078475..a770d4e 100644 (file)
@@ -50,6 +50,7 @@
     <script src="{% static "bower_components/flot/jquery.flot.resize.js" %}"></script>
     <script src="{% static "bower_components/flot/jquery.flot.time.js" %}"></script>
     <script src="{% static "bower_components/flot.tooltip/js/jquery.flot.tooltip.min.js" %}"></script>
+    <script src="{% static "js/flot-pie-chart.js" %}"></script><
 
     <script type="text/javascript">
         $(document).ready(function () {
 
                 $('#{{ resource.id }}_server_table').DataTable({});
                 $('#{{ resource.id }}_bookings_table').DataTable({});
+                $('#{{ resource.id }}_vpn_user_table').DataTable({});
 
-                $(function () {
-                    var plotObj = $.plot($("#{{ resource.id }}_slave_utilization"), data_{{ resource.id }}, {
-                        series: {
-                            pie: {
-                                show: true
-                            }
-                        }
-                    });
+                var chart_id = "{{ resource.id }}_booking_utilization";
+                var utilization_url = "{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}";
+                loadChartData(chart_id, utilization_url);
 
-                });
+                var chart_id = "{{ resource.id }}_jenkins_utilization";
+                var utilization_url = "{% url 'dashboard:jenkins_utilization' resource_id=resource.id weeks=1 %}";
+                loadChartData(chart_id, utilization_url);
             {% endfor %}
         });
     </script>
index 4fba476..904fecd 100644 (file)
     </div>
 </div>
 <div class="row">
-    <div class="col-lg-6">
+    <div class="col-lg-3">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Booking Utilization
+                <div class="pull-right">
+                    <div class="form-group">
+                        <select onchange="loadChartData('{{ resource.id }}_booking_utilization', this.value);">
+                            <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=-4 %}">
+                                Last Month
+                            </option>
+                            <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=-1 %}">
+                                Last Week
+                            </option>
+                            <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=1 %}">
+                                Next Week
+                            </option>
+                            <option selected="selected"
+                                    value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}">
+                                Next Month
+                            </option>
+                        </select>
+                    </div>
+                </div>
+            </div>
+            <div class="panel-body">
+                <div class="flot-chart">
+                    <div class="flot-chart-content"
+                         id="{{ resource.id }}_booking_utilization"></div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="col-lg-9">
         <div class="panel panel-default">
             <div class="panel-heading">
                 Bookings
index d47e520..fee7e8b 100644 (file)
@@ -26,5 +26,5 @@
             {{ server.storage }}
         </th>
     </tr>
-{% endfor %}`
+{% endfor %}
 </tbody>
\ No newline at end of file
index db9490f..64fed4a 100644 (file)
@@ -20,7 +20,7 @@
     <link href="{% static "bower_components/metisMenu/dist/metisMenu.min.css" %}" rel="stylesheet">
 
     <!-- Custom CSS -->
-    <link href="{% static "bower_components/startbootstrap-sb-admin-2/dist/css/sb-admin-2.css" %}"
+    <link href="{% static "bower_components/startbootstrap-sb-admin-2-blackrockdigital/dist/css/sb-admin-2.css" %}"
           rel="stylesheet">
     <link href="{% static "css/theme.css" %}" rel="stylesheet">
 
@@ -65,7 +65,7 @@
 <script src="{% static "bower_components/metisMenu/dist/metisMenu.min.js" %}"></script>
 
 <!-- Custom Theme JavaScript -->
-<script src="{% static "bower_components/startbootstrap-sb-admin-2/dist/js/sb-admin-2.js" %}"></script>
+<script src="{% static "bower_components/startbootstrap-sb-admin-2-blackrockdigital/dist/js/sb-admin-2.js" %}"></script>
 
 {% block extrajs %}
 {% endblock extrajs %}