From 35c34c690ae9616d791c39fa218fe1621fa8d8d2 Mon Sep 17 00:00:00 2001 From: maxbr Date: Fri, 29 Jul 2016 12:43:43 +0200 Subject: import pharos dashboard code JIRA: RELENG-12 The last commit was missing some JS/CSS dependencies of the site. This happened because they are in folders that are named 'build' or 'dist'. This commit adds a bower.json file, that specifies dependencies. Dependencies can now be installed by running 'bower install' in the dashboard/static folder. Change-Id: I054f319c66771f767e97711cb678d79d3bd6bee4 Signed-off-by: maxbr --- tools/pharos-dashboard/dashboard/static/bower.json | 24 ++++++++ .../dashboard/static/css/theme.css | 7 +++ .../dashboard/static/js/booking-calendar.js | 68 ++++++++++++++++++++++ tools/pharos-dashboard/dashboard/static/js/csrf.js | 34 +++++++++++ .../dashboard/static/js/dataTables-sort.js | 26 +++++++++ .../dashboard/static/js/datetimepicker-options.js | 7 +++ .../dashboard/static/js/fullcalendar-options.js | 65 +++++++++++++++++++++ 7 files changed, 231 insertions(+) create mode 100644 tools/pharos-dashboard/dashboard/static/bower.json create mode 100644 tools/pharos-dashboard/dashboard/static/css/theme.css create mode 100644 tools/pharos-dashboard/dashboard/static/js/booking-calendar.js create mode 100644 tools/pharos-dashboard/dashboard/static/js/csrf.js create mode 100644 tools/pharos-dashboard/dashboard/static/js/dataTables-sort.js create mode 100644 tools/pharos-dashboard/dashboard/static/js/datetimepicker-options.js create mode 100644 tools/pharos-dashboard/dashboard/static/js/fullcalendar-options.js (limited to 'tools/pharos-dashboard/dashboard/static') diff --git a/tools/pharos-dashboard/dashboard/static/bower.json b/tools/pharos-dashboard/dashboard/static/bower.json new file mode 100644 index 00000000..78406217 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/bower.json @@ -0,0 +1,24 @@ +{ + "name": "pharos-dashboard-dependencies", + "authors": [ + "maxbr " + ], + "description": "This package contains all the Js/CSS dependencies needed to run the Pharos Dashboard.", + "main": "", + "license": "Apache2", + "homepage": "", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "eonasdan-bootstrap-datetimepicker": "^4.17.37", + "fullcalendar": "^2.9.0", + "jquery-migrate": "^3.0.0", + "startbootstrap-sb-admin-2": "^1.0.9" + } +} diff --git a/tools/pharos-dashboard/dashboard/static/css/theme.css b/tools/pharos-dashboard/dashboard/static/css/theme.css new file mode 100644 index 00000000..4cec341d --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/css/theme.css @@ -0,0 +1,7 @@ +.blink_me { + animation: blinker 1.5s linear infinite; +} + +@keyframes blinker { + 20% { opacity: 0.4; } +} \ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/static/js/booking-calendar.js b/tools/pharos-dashboard/dashboard/static/js/booking-calendar.js new file mode 100644 index 00000000..edc20551 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/js/booking-calendar.js @@ -0,0 +1,68 @@ +function parseDisabledTimeIntervals(bookings) { + var timeIntervals = []; + + for (var i = 0; i < bookings.length; i++) { + var interval = [ + moment(bookings[i]['start_date_time']), + moment(bookings[i]['end_date_time']) + ]; + timeIntervals.push(interval); + } + return timeIntervals; +} + +function parseCalendarEvents(bookings) { + var events = []; + for (var i = 0; i < bookings.length; i++) { + event = { + id: bookings[i]['booking_id'], + title: bookings[i]['purpose'], + start: bookings[i]['start_date_time'], + end: bookings[i]['end_date_time'], + editable: true + }; + events.push(event); + } + return events; +} + +function loadEvents(bookings_url) { + $.ajax({ + url: bookings_url, + type: 'get', + success: function (data) { + $('#calendar').fullCalendar('addEventSource', parseCalendarEvents(data['bookings'])); + var intervals = parseDisabledTimeIntervals(data['bookings']); + $('#starttimepicker').data("DateTimePicker").disabledTimeIntervals(intervals); + $('#endtimepicker').data("DateTimePicker").disabledTimeIntervals(intervals); + }, + failure: function (data) { + alert('Error loading booking data'); + } + }); +} + +$(document).ready(function () { + $('#calendar').fullCalendar(calendarOptions); + $('#starttimepicker').datetimepicker(timepickerOptions); + $('#endtimepicker').datetimepicker(timepickerOptions); + + loadEvents(bookings_url); + + // send Post request to delete url if button is clicked + $("#deletebutton").click(function () { + var booking_id = $('#id_booking_id').val(); + $.ajax({ + type: 'post', + url: '/booking/' + booking_id + '/delete', + success: function () { + $('#calendar').fullCalendar('removeEvents'); + loadEvents(bookings_url); + $('#calendar').fullCalendar('rerenderEvents'); + }, + failure: function () { + alert('Deleting failed') + } + }) + }) +}); \ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/static/js/csrf.js b/tools/pharos-dashboard/dashboard/static/js/csrf.js new file mode 100644 index 00000000..12429b38 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/js/csrf.js @@ -0,0 +1,34 @@ +/** + * use django csrf token in ajax requests + * source: https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax + */ +// using jQuery +function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} +var csrftoken = getCookie('csrftoken'); + +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} + +$.ajaxSetup({ + beforeSend: function (xhr, settings) { + if (!csrfSafeMethod(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } +}); \ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/static/js/dataTables-sort.js b/tools/pharos-dashboard/dashboard/static/js/dataTables-sort.js new file mode 100644 index 00000000..7189ca15 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/js/dataTables-sort.js @@ -0,0 +1,26 @@ +/** + * This is a sort function for dataTables to sort tables by the status column. + * The order should be: online < online/idle < offline + */ +jQuery.extend(jQuery.fn.dataTableExt.oSort, { + "status-pre": function (a) { + switch (a) { + case 'online': + return 1; + case 'online / idle': + return 2; + case 'offline': + return 3; + default: + return a; + } + }, + + "status-asc": function (a, b) { + return ((a < b) ? -1 : ((a > b) ? 1 : 0)); + }, + + "status-desc": function (a, b) { + return ((a < b) ? 1 : ((a > b) ? -1 : 0)); + } +}); \ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/static/js/datetimepicker-options.js b/tools/pharos-dashboard/dashboard/static/js/datetimepicker-options.js new file mode 100644 index 00000000..1deb8191 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/js/datetimepicker-options.js @@ -0,0 +1,7 @@ +/** + * Created by max on 7/25/16. + */ +var timepickerOptions = { + format: 'YYYY-MM-DD HH:00 ZZ', + sideBySide: true +}; \ No newline at end of file diff --git a/tools/pharos-dashboard/dashboard/static/js/fullcalendar-options.js b/tools/pharos-dashboard/dashboard/static/js/fullcalendar-options.js new file mode 100644 index 00000000..c0417eb1 --- /dev/null +++ b/tools/pharos-dashboard/dashboard/static/js/fullcalendar-options.js @@ -0,0 +1,65 @@ +// converts a moment to a readable fomat for the backend +function convertInputTime(time) { + return moment(time).format('YYYY-MM-DD HH:00 ZZ'); +} + +function sendEventToForm(event) { + var start = convertInputTime(event.start); + var end = convertInputTime(event.end); + $('#starttimepicker').data("DateTimePicker").date(start); + $('#endtimepicker').data("DateTimePicker").date(end); + $('#submitform').html("Change Booking"); + $('#purposefield').val(event.title); + $('#id_booking_id').val(event.id); // create a new booking + $("#deletebutton").removeClass('hidden'); // show delete button +} + +var calendarOptions = { + height: 600, + header: { + left: 'prev,next today', + center: 'title', + right: 'agendaWeek,month' + }, + timezone: 'local', + defaultView: 'agendaWeek', + slotDuration: '00:60:00', + slotLabelFormat: "HH:mm", + firstDay: 1, + allDaySlot: false, + selectOverlap: false, + eventOverlap: false, + selectable: true, + selectHelper: true, + editable: false, + eventLimit: true, // allow "more" link when too many events + timeFormat: 'H(:mm)', // uppercase H for 24-hour clock + unselectAuto: false, + + select: function (start, end) { + var start = convertInputTime(start); + var end = convertInputTime(end); + + $('#starttimepicker').data("DateTimePicker").date(start); + $('#endtimepicker').data("DateTimePicker").date(end); + $('#submitform').html("Book Pod"); + $('#purposefield').val(''); + $('#id_booking_id').val(''); // create a new booking + $("#deletebutton").addClass('hidden'); // hide delete button + }, + + eventClick: function (event, jsEvent, view) { + $('#calendar').fullCalendar('unselect'); + sendEventToForm(event); + }, + + eventDrop: function (event) { + $('#calendar').fullCalendar('unselect'); + sendEventToForm(event); + }, + + eventResize: function (event) { + $('#calendar').fullCalendar('unselect'); + sendEventToForm(event); + } +}; \ No newline at end of file -- cgit 1.2.3-korg