diff options
23 files changed, 387 insertions, 65 deletions
diff --git a/tools/pharos-dashboard/.gitignore b/tools/pharos-dashboard/.gitignore index 9eb1cfde..2b73909a 100644 --- a/tools/pharos-dashboard/.gitignore +++ b/tools/pharos-dashboard/.gitignore @@ -20,6 +20,7 @@ coverage.xml *.log *.pot migrations/ +settings.py # KDE: .directory diff --git a/tools/pharos-dashboard/account/jira_util.py b/tools/pharos-dashboard/account/jira_util.py index bd07ff3b..c066a686 100644 --- a/tools/pharos-dashboard/account/jira_util.py +++ b/tools/pharos-dashboard/account/jira_util.py @@ -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): diff --git a/tools/pharos-dashboard/account/urls.py b/tools/pharos-dashboard/account/urls.py index b837814a..7289da69 100644 --- a/tools/pharos-dashboard/account/urls.py +++ b/tools/pharos-dashboard/account/urls.py @@ -21,5 +21,6 @@ urlpatterns = [ url(r'^settings/', AccountSettingsView.as_view(), name='settings'), url(r'^authenticated/$', JiraAuthenticatedView.as_view(), name='authenticated'), url(r'^login/$', JiraLoginView.as_view(), name='login'), - url(r'^logout/$', JiraLogoutView.as_view(), name='logout') + url(r'^logout/$', JiraLogoutView.as_view(), name='logout'), + url(r'^users/$', UserListView.as_view(), name='users'), ] diff --git a/tools/pharos-dashboard/account/views.py b/tools/pharos-dashboard/account/views.py index 7d2c9bd0..fd1762e5 100644 --- a/tools/pharos-dashboard/account/views.py +++ b/tools/pharos-dashboard/account/views.py @@ -10,13 +10,14 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils.decorators import method_decorator from django.views.generic import RedirectView +from django.views.generic import TemplateView from django.views.generic import UpdateView from jira import JIRA from account.forms import AccountSettingsForm from account.jira_util import SignatureMethod_RSA_SHA1 from account.models import UserProfile -from pharos_dashboard import settings +from django.conf import settings consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) @@ -50,7 +51,8 @@ class JiraLoginView(RedirectView): self.request.session['request_token'] = dict(urllib.parse.parse_qsl(content.decode())) # Step 3. Redirect the user to the authentication URL. url = settings.OAUTH_AUTHORIZE_URL + '?oauth_token=' + \ - self.request.session['request_token']['oauth_token'] + self.request.session['request_token']['oauth_token'] + \ + '&oauth_callback=' + settings.OAUTH_CALLBACK_URL return url @@ -109,3 +111,12 @@ class JiraAuthenticatedView(RedirectView): login(self.request, user) # redirect user to settings page to complete profile return url + +class UserListView(TemplateView): + template_name = "account/user_list.html" + + def get_context_data(self, **kwargs): + users = User.objects.all() + context = super(UserListView, self).get_context_data(**kwargs) + context.update({'title': "Dashboard Users", 'users': users}) + return context diff --git a/tools/pharos-dashboard/booking/models.py b/tools/pharos-dashboard/booking/models.py index 4be8ccab..e772fb5b 100644 --- a/tools/pharos-dashboard/booking/models.py +++ b/tools/pharos-dashboard/booking/models.py @@ -1,10 +1,10 @@ from django.contrib.auth.models import User from django.db import models from jira import JIRA +from jira import JIRAError from dashboard.models import Resource -from pharos_dashboard import settings - +from django.conf import settings class Booking(models.Model): id = models.AutoField(primary_key=True) @@ -13,6 +13,7 @@ class Booking(models.Model): start = models.DateTimeField() end = models.DateTimeField() jira_issue_id = models.IntegerField(null=True) + jira_issue_status = models.CharField(max_length=50) purpose = models.CharField(max_length=300, blank=False) @@ -20,9 +21,13 @@ class Booking(models.Model): db_table = 'booking' def get_jira_issue(self): - jira = JIRA(server=settings.JIRA_URL, basic_auth=(settings.JIRA_USER_NAME, settings.JIRA_USER_PASSWORD)) - issue = jira.issue(self.jira_issue_id) - return issue + try: + jira = JIRA(server=settings.JIRA_URL, + basic_auth=(settings.JIRA_USER_NAME, settings.JIRA_USER_PASSWORD)) + issue = jira.issue(self.jira_issue_id) + return issue + except JIRAError: + return None def authorization_test(self): """ diff --git a/tools/pharos-dashboard/booking/urls.py b/tools/pharos-dashboard/booking/urls.py index f6429daa..bdcd52d4 100644 --- a/tools/pharos-dashboard/booking/urls.py +++ b/tools/pharos-dashboard/booking/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ url(r'^(?P<resource_id>[0-9]+)/$', BookingFormView.as_view(), name='create'), url(r'^(?P<resource_id>[0-9]+)/bookings_json/$', ResourceBookingsJSON.as_view(), name='bookings_json'), + url(r'^detail/$', BookingView.as_view(), name='detail_prefix'), url(r'^detail/(?P<booking_id>[0-9]+)/$', BookingView.as_view(), name='detail'), ] diff --git a/tools/pharos-dashboard/booking/views.py b/tools/pharos-dashboard/booking/views.py index fde8d816..d0b2aefe 100644 --- a/tools/pharos-dashboard/booking/views.py +++ b/tools/pharos-dashboard/booking/views.py @@ -1,9 +1,13 @@ +from datetime import timedelta + +from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.shortcuts import redirect from django.urls import reverse +from django.utils import timezone from django.views import View from django.views.generic import FormView from django.views.generic import TemplateView @@ -67,7 +71,8 @@ class BookingFormView(LoginRequiredMixin, FormView): messages.add_message(self.request, messages.ERROR, err) return super(BookingFormView, self).form_invalid(form) try: - create_jira_ticket(user, booking) + if settings.CREATE_JIRA_TICKET: + create_jira_ticket(user, booking) except JIRAError: messages.add_message(self.request, messages.ERROR, 'Failed to create Jira Ticket. ' 'Please check your Jira ' @@ -93,5 +98,6 @@ class BookingView(TemplateView): class ResourceBookingsJSON(View): def get(self, request, *args, **kwargs): resource = get_object_or_404(Resource, id=self.kwargs['resource_id']) - bookings = resource.booking_set.get_queryset().values('id', 'start', 'end', 'purpose') - return JsonResponse({'bookings': list(bookings)}) + bookings = resource.booking_set.get_queryset().values('id', 'start', 'end', 'purpose', + 'jira_issue_status') + return JsonResponse({'bookings': list(bookings)})
\ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/models.py b/tools/pharos-dashboard/dashboard/models.py index d645cd55..734da386 100644 --- a/tools/pharos-dashboard/dashboard/models.py +++ b/tools/pharos-dashboard/dashboard/models.py @@ -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' diff --git a/tools/pharos-dashboard/dashboard/templatetags/jira_filters.py b/tools/pharos-dashboard/dashboard/templatetags/jira_filters.py index d9c27612..1be0600b 100644 --- a/tools/pharos-dashboard/dashboard/templatetags/jira_filters.py +++ b/tools/pharos-dashboard/dashboard/templatetags/jira_filters.py @@ -1,6 +1,6 @@ from django.template.defaultfilters import register -from pharos_dashboard import settings +from django.conf import settings @register.filter diff --git a/tools/pharos-dashboard/dashboard/urls.py b/tools/pharos-dashboard/dashboard/urls.py index 809204c1..baa2d633 100644 --- a/tools/pharos-dashboard/dashboard/urls.py +++ b/tools/pharos-dashboard/dashboard/urls.py @@ -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"), ] diff --git a/tools/pharos-dashboard/dashboard/views.py b/tools/pharos-dashboard/dashboard/views.py index ef1845c8..0eddc130 100644 --- a/tools/pharos-dashboard/dashboard/views.py +++ b/tools/pharos-dashboard/dashboard/views.py @@ -1,7 +1,9 @@ from datetime import timedelta +from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.utils import timezone +from django.views import View from django.views.generic import TemplateView from booking.models import Booking @@ -40,10 +42,18 @@ class DevelopmentPodsView(TemplateView): dev_pods = [] for resource in resources: - dev_pod = (resource, None) + booking_utilization = resource.get_booking_utilization(weeks=4) + total = booking_utilization['booked_seconds'] + booking_utilization['available_seconds'] + try: + utilization_percentage = "%d%%" % (float(booking_utilization['booked_seconds']) / + total * 100) + except (ValueError, ZeroDivisionError): + return "" + + dev_pod = (resource, None, utilization_percentage) for booking in bookings: if booking.resource == resource: - dev_pod = (resource, booking) + dev_pod = (resource, booking, utilization_percentage) dev_pods.append(dev_pod) context = super(DevelopmentPodsView, self).get_context_data(**kwargs) @@ -59,7 +69,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 +87,47 @@ 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}) + + +class JenkinsUtilizationJSON(View): + def get(self, request, *args, **kwargs): + resource = get_object_or_404(Resource, id=kwargs['resource_id']) + weeks = int(kwargs['weeks']) + utilization = resource.slave.get_utilization(timedelta(weeks=weeks)) + utilization = [ + { + 'label': 'Offline', + 'data': utilization['offline'], + 'color': '#d9534f' + }, + { + 'label': 'Online', + 'data': utilization['online'], + 'color': '#5cb85c' + }, + { + 'label': 'Idle', + 'data': utilization['idle'], + 'color': '#5bc0de' + }, + ] + return JsonResponse({'data': utilization}) diff --git a/tools/pharos-dashboard/pharos_dashboard/urls.py b/tools/pharos-dashboard/pharos_dashboard/urls.py index 26ab3677..d8bf5608 100644 --- a/tools/pharos-dashboard/pharos_dashboard/urls.py +++ b/tools/pharos-dashboard/pharos_dashboard/urls.py @@ -13,13 +13,18 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ +from django.conf import settings from django.conf.urls import url, include +from django.conf.urls.static import static from django.contrib import admin urlpatterns = [ url(r'^', include('dashboard.urls', namespace='dashboard')), url(r'^booking/', include('booking.urls', namespace='booking')), - url(r'^account/', include('account.urls', namespace='account')), + url(r'^accounts/', include('account.urls', namespace='account')), url(r'^admin/', admin.site.urls), -]
\ No newline at end of file +] + +if settings.DEBUG is True: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
\ No newline at end of file diff --git a/tools/pharos-dashboard/static/bower.json b/tools/pharos-dashboard/static/bower.json index 78406217..f473747f 100644 --- a/tools/pharos-dashboard/static/bower.json +++ b/tools/pharos-dashboard/static/bower.json @@ -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 index 00000000..98d174e4 --- /dev/null +++ b/tools/pharos-dashboard/static/js/flot-pie-chart.js @@ -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 diff --git a/tools/pharos-dashboard/templates/account/user_list.html b/tools/pharos-dashboard/templates/account/user_list.html new file mode 100644 index 00000000..7618dc95 --- /dev/null +++ b/tools/pharos-dashboard/templates/account/user_list.html @@ -0,0 +1,42 @@ +{% extends "dashboard/table.html" %} +{% load staticfiles %} + +{% block table %} + <thead> + <tr> + <th>Username</th> + <th>Company</th> + <th>SSH Key</th> + <th>GPG Key</th> + </tr> + </thead> + <tbody> + {% for user in users %} + <tr> + <th> + {{ user.username }} + </th> + <th> + {{ user.userprofile.company }} + </th> + <th> + <a href={{ user.userprofile.ssh_public_key.url }}>Download</a> + </th> + <th> + <a href={{ user.userprofile.pgp_public_key.url }}>Download</a> + </th> + </tr> + {% endfor %} + </tbody> +{% endblock table %} + + +{% block tablejs %} + <script type="text/javascript"> + $(document).ready(function () { + $('#table').DataTable({ + "order": [[0, "asc"]] + }); + }); + </script> +{% endblock tablejs %}
\ No newline at end of file diff --git a/tools/pharos-dashboard/templates/base.html b/tools/pharos-dashboard/templates/base.html index 64174a1f..42156e3b 100644 --- a/tools/pharos-dashboard/templates/base.html +++ b/tools/pharos-dashboard/templates/base.html @@ -71,6 +71,11 @@ class="fa fa-fw"></i>Resources </a> </li> + <li> + <a href="{% url 'account:users' %}"><i + class="fa fa-fw"></i>Users + </a> + </li> </ul> </div> <!-- /.sidebar-collapse --> diff --git a/tools/pharos-dashboard/templates/dashboard/ci_pods.html b/tools/pharos-dashboard/templates/dashboard/ci_pods.html index 2982a6ff..a754252c 100644 --- a/tools/pharos-dashboard/templates/dashboard/ci_pods.html +++ b/tools/pharos-dashboard/templates/dashboard/ci_pods.html @@ -41,7 +41,7 @@ href={{ pod.slave.last_job_url }}>{{ pod.slave.last_job_name }}</a> </th> </tr> - {% endfor %}` + {% endfor %} </tbody> {% endblock table %} diff --git a/tools/pharos-dashboard/templates/dashboard/dev_pods.html b/tools/pharos-dashboard/templates/dashboard/dev_pods.html index 9c84bb91..c4cb1ba7 100644 --- a/tools/pharos-dashboard/templates/dashboard/dev_pods.html +++ b/tools/pharos-dashboard/templates/dashboard/dev_pods.html @@ -10,12 +10,14 @@ <th>Booked by</th> <th>Booked until</th> <th>Purpose</th> + <th>Utilization</th> <th>Status</th> <th></th> + <th></th> </tr> </thead> <tbody> - {% for pod, booking in dev_pods %} + {% for pod, booking, utilization in dev_pods %} <tr> <th> <a href={% url 'dashboard:resource' resource_id=pod.id %}>{{ pod.name }}</a> @@ -32,6 +34,9 @@ <th> {{ booking.purpose }} </th> + <th> + {{ utilization }} + </th> <th style="background-color:{{ pod.slave.status | jenkins_status_color }}"> {{ pod.slave.status }} </th> @@ -40,6 +45,11 @@ Book </a> </th> + <th> + <a href="{% url 'dashboard:resource' resource_id=pod.id %}" class="btn btn-primary"> + Info + </a> + </th> </tr> {% endfor %} </tbody> @@ -50,9 +60,9 @@ $(document).ready(function () { $('#table').DataTable({ columnDefs: [ - {type: 'status', targets: 5} + {type: 'status', targets: 6} ], - "order": [[5, "asc"]] + "order": [[6, "asc"]] }); }); </script> diff --git a/tools/pharos-dashboard/templates/dashboard/resource.html b/tools/pharos-dashboard/templates/dashboard/resource.html index 92d02f66..c9e57354 100644 --- a/tools/pharos-dashboard/templates/dashboard/resource.html +++ b/tools/pharos-dashboard/templates/dashboard/resource.html @@ -38,21 +38,21 @@ <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 diff --git a/tools/pharos-dashboard/templates/dashboard/resource_all.html b/tools/pharos-dashboard/templates/dashboard/resource_all.html index 2078475f..a770d4e8 100644 --- a/tools/pharos-dashboard/templates/dashboard/resource_all.html +++ b/tools/pharos-dashboard/templates/dashboard/resource_all.html @@ -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 () { @@ -57,17 +58,15 @@ $('#{{ 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> diff --git a/tools/pharos-dashboard/templates/dashboard/resource_detail.html b/tools/pharos-dashboard/templates/dashboard/resource_detail.html index 4fba4766..6067e1ea 100644 --- a/tools/pharos-dashboard/templates/dashboard/resource_detail.html +++ b/tools/pharos-dashboard/templates/dashboard/resource_detail.html @@ -1,12 +1,27 @@ +{% load jenkins_filters %} + <div class="row"> <div class="col-lg-3"> <div class="panel panel-default"> <div class="panel-heading"> - Utilization + Jenkins Utilization + <div class="pull-right"> + <div class="form-group"> + <select onchange="loadChartData('{{ resource.id }}_jenkins_utilization', this.value);"> + <option value="{% url 'dashboard:jenkins_utilization' resource_id=resource.id weeks=1 %}"> + Last Week + </option> + <option value="{% url 'dashboard:jenkins_utilization' resource_id=resource.id weeks=4 %}"> + Last Month + </option> + </select> + </div> + </div> </div> <div class="panel-body"> <div class="flot-chart"> - <div class="flot-chart-content" id="{{ resource.id }}_slave_utilization"></div> + <div class="flot-chart-content" + id="{{ resource.id }}_jenkins_utilization"></div> </div> </div> </div> @@ -29,7 +44,39 @@ </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 @@ -46,19 +93,92 @@ </div> </div> </div> - -<script type="text/javascript"> - var data_{{ resource.id }} = [{ - label: "Offline", - data: {{ utilization.offline }}, - color: '#d9534f' - }, { - label: "Online", - data: {{ utilization.online }}, - color: '#5cb85c' - }, { - label: "Idle", - data: {{ utilization.idle }}, - color: '#5bc0de' - }]; -</script>
\ No newline at end of file +<div class="row"> + <div class="col-lg-3"> + <div class="panel panel-default"> + <div class="panel-heading"> + Contact + </div> + <div class="panel-body"> + <p> + <b>Lab Owner: </b> + {{ resource.owner.username }} + </p> + <p> + <b>Email: </b> + </p> + <p> + <a href="{% url 'booking:create' resource_id=resource.id %}" class="btn + btn-primary"> + Booking + </a> + <a href="{{ resource.url }}" class="btn + btn-primary"> + OPNFV Wiki + </a> + </p> + </div> + </div> + </div> + <div class="col-lg-3"> + <div class="panel panel-default"> + <div class="panel-heading"> + Jenkins Status + </div> + <div class="panel-body"> + <p> + <b>Slave Name: </b> + <a target='_blank' + href={{ resource.slave.url }}>{{ resource.slave.name }}</a> + </p> + <p> + <b>Status: </b> + {{ resource.slave.status }} + </p> + <p> + <b>Last Job: </b> + <a href="{{ resource.slave.last_job_url }}"> + {{ resource.slave.last_job_name }} + </a> + </p> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="panel panel-default"> + <div class="panel-heading"> + VPN Users + </div> + <div class="panel-body"> + <div class="dataTables_wrapper"> + <table class="table table-striped table-bordered table-hover" + id="{{ resource.id }}_vpn_user_table" cellspacing="0" + width="100%"> + <thead> + <tr> + <th>User</th> + <th>Email</th> + <th>Company</th> + </tr> + </thead> + <tbody> + {% for user in resource.vpn_users.all %} + <tr> + <th> + {{ user.username }} + </th> + <th> + {{ user.email }} + </th> + <th> + {{ user.userprofile.company }} + </th> + </tr> + {% endfor %} + </table> + </tbody> + </div> + </div> + </div> + </div> +</div>
\ No newline at end of file diff --git a/tools/pharos-dashboard/templates/dashboard/server_table.html b/tools/pharos-dashboard/templates/dashboard/server_table.html index d47e5204..fee7e8b1 100644 --- a/tools/pharos-dashboard/templates/dashboard/server_table.html +++ b/tools/pharos-dashboard/templates/dashboard/server_table.html @@ -26,5 +26,5 @@ {{ server.storage }} </th> </tr> -{% endfor %}` +{% endfor %} </tbody>
\ No newline at end of file diff --git a/tools/pharos-dashboard/templates/layout.html b/tools/pharos-dashboard/templates/layout.html index db9490f5..64fed4ae 100644 --- a/tools/pharos-dashboard/templates/layout.html +++ b/tools/pharos-dashboard/templates/layout.html @@ -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 %} |