Commit 921944e9 by Kálmán Viktor

Merge branch 'master' into issue-291

parents 7c5eae88 db42d716
......@@ -18,6 +18,7 @@
"jquery-knob": "~1.2.9",
"jquery-simple-slider": "https://github.com/BME-IK/jquery-simple-slider.git",
"bootbox": "~4.3.0",
"intro.js": "0.9.0"
"intro.js": "0.9.0",
"favico.js": "~0.3.5"
}
}
......@@ -197,6 +197,7 @@ PIPELINE_JS = {
"intro.js/intro.js",
"jquery-knob/dist/jquery.knob.min.js",
"jquery-simple-slider/js/simple-slider.js",
"favico.js/favico.js",
"dashboard/dashboard.js",
"dashboard/activity.js",
"dashboard/group-details.js",
......
......@@ -31,6 +31,7 @@ from django.db.models import (
)
from django.db.models.signals import post_save, pre_delete, post_delete
from django.templatetags.static import static
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
from django_sshkey.models import UserKey
from django.core.exceptions import ObjectDoesNotExist
......@@ -87,7 +88,8 @@ class Notification(TimeStampedModel):
@property
def subject(self):
return HumanReadableObject.from_dict(self.subject_data)
return HumanReadableObject.from_dict(
self.escape_dict(self.subject_data))
@subject.setter
def subject(self, value):
......@@ -95,7 +97,14 @@ class Notification(TimeStampedModel):
@property
def message(self):
return HumanReadableObject.from_dict(self.message_data)
return HumanReadableObject.from_dict(
self.escape_dict(self.message_data))
def escape_dict(self, data):
for k, v in data['params'].items():
if isinstance(v, basestring):
data['params'][k] = escape(v)
return data
@message.setter
def message(self, value):
......
$(function () {
var favicon= new Favico({
animation:'none'
});
var notifications = $("#notification_count").data("notifications");
if(notifications)
favicon.badge(notifications);
$(".not-tab-pane").removeClass("not-tab-pane").addClass("tab-pane");
$('.vm-create').click(function(e) {
......@@ -151,7 +159,8 @@ $(function () {
$("#dashboard-vm-search-input").keyup(function(e) {
// if my_vms is empty get a list of our vms
if(my_vms.length < 1) {
$.ajaxSetup( { "async": false } );
$("#dashboard-vm-search-form button i").addClass("fa-spinner fa-spin");
$.get("/dashboard/vm/list/", function(result) {
for(var i in result) {
my_vms.push({
......@@ -165,8 +174,10 @@ $(function () {
'owner': result[i].owner,
});
}
$("#dashboard-vm-search-input").trigger("keyup");
$("#dashboard-vm-search-form button i").removeClass("fa-spinner fa-spin").addClass("fa-search");
});
$.ajaxSetup( { "async": true } );
return;
}
input = $("#dashboard-vm-search-input").val().toLowerCase();
......@@ -311,6 +322,8 @@ $(function () {
$("#notification-button a").click(function() {
$('#notification-messages').load("/dashboard/notifications/");
$('#notification-button a span[class*="badge-pulse"]').remove();
favicon.reset();
});
/* on the client confirmation button fire the clientInstalledAction */
......@@ -349,7 +362,6 @@ $(function () {
li.addClass('panel-primary').find('input').prop("checked", true);
return true;
});
});
function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
......@@ -358,7 +370,7 @@ function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
'<span class="index-vm-list-name">' +
'<i class="fa ' + icon + '" title="' + _status + '"></i> ' + safe_tags_replace(name) +
'</span>' +
'<small class="text-muted"> ' + host + '</small>' +
'<small class="text-muted index-vm-list-host"> ' + host + '</small>' +
'<div class="pull-right dashboard-vm-favourite" data-vm="' + pk + '">' +
(fav ? '<i class="fa fa-star text-primary title-favourite" title="' + gettext("Unfavourite") + '"></i>' :
'<i class="fa fa-star-o text-primary title-favourite" title="' + gettext("Mark as favorite") + '"></i>' ) +
......
......@@ -23,46 +23,23 @@ html {
padding-right: 15px;
}
/* values for 45px tall navbar */
.navbar {
min-height: 45px;
}
.navbar-brand {
height: 45px;
padding: 12.5px 12.5px;
}
/* --- */
.navbar-toggle {
margin-top: 5.5px;
margin-bottom: 5.5px;
#dashboard-menu > li > a {
color: white;
font-size: 10px;
}
.navbar-form {
margin-top: 5.5px;
margin-bottom: 5.5px;
}
.navbar-btn {
margin-top: 5.5px;
margin-bottom: 5.5px;
#dashboard-menu {
margin-right: 15px;
}
.navbar-btn.btn-sm {
margin-top: 7.5px;
margin-bottom: 7.5px;
}
.navbar-btn.btn-xs {
margin-top: 11.5px;
margin-bottom: 11.5px;
}
.navbar-text {
margin-top: 12.5px;
margin-bottom: 12.5px;
/* we need this for mobile view */
.container > :first-child {
margin-top: 15px;
}
/* --- */
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Let the jumbotron breathe */
......@@ -80,6 +57,7 @@ html {
}
}
.no-margin {
margin: 0!important;
}
......@@ -400,10 +378,6 @@ a.hover-black {
font-size: 12px;
}
#notification-button {
margin-right: 15px;
}
#vm-migrate-node-list {
list-style: none;
}
......@@ -519,15 +493,6 @@ footer a, footer a:hover, footer a:visited {
padding: 5px; /* it's nice this way in the tour */
}
.index-vm-list-name {
display: inline-block;
max-width: 70%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
float: left;
}
#dashboard-vm-list a small {
padding-left: 10px;
}
......@@ -756,12 +721,15 @@ textarea[name="new_members"] {
margin-top: 8px;
}
#dashboard-files-toplist div.list-group-item {
#dashboard-files-toplist {
div.list-group-item {
color: #555;
}
height: 41px;
#dashboard-files-toplist div.list-group-item:hover {
&:hover {
background: #eee;
}
}
}
.store-list-item-name {
......@@ -1109,6 +1077,25 @@ textarea[name="new_members"] {
text-align: center;
}
.vm-create-list-name {
display: inline-block;
max-width: 60%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
float: left;
}
.vm-create-list-system {
display: inline-block;
max-width: 40%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
float: right;
}
/* for introjs
* newer version has this fixed
* but it doesn't work w bootstrap 3.2.0
......@@ -1155,3 +1142,78 @@ textarea[name="new_members"] {
background-position: 0 0px;
}
}
#dashboard-vm-list {
.list-group-item {
display: flex;
}
.index-vm-list-name, .index-vm-list-host {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.index-vm-list-name {
max-width: 70%;
}
.index-vm-list-host {
padding-top: 3px;
flex: 1;
}
}
.fa-fw-12 {
/* fa-fw is too wide */
width: 12px;
}
.btn-op-form-send {
padding: 6px 12px 6px 8px;
}
@media (max-width: 767px) {
#vm-detail-panel .graph-buttons {
padding-top: 15px;
}
.graph-buttons a {
margin-bottom: 8px;
}
#ops .operation {
margin-bottom: 5px;
}
.vm-details-connection dd {
margin-left: 25px;
}
.vm-details-connection dt {
padding-left: 0px;
}
}
#notifications-upper-pagination {
margin-top: 4px;
}
#notifications-bottom-pagination {
* {
display: inline-block;
}
a {
font-size: 20px;
&:hover {
text-decoration: none;
}
}
.page-numbers {
padding: 25px;
}
}
......@@ -82,7 +82,6 @@ html {
z-index: 1;
}
.nojs-dropdown-toggle:focus + .nojs-dropdown-menu
{
display: block;
......@@ -98,32 +97,6 @@ html {
display: block;
}
.notification-messages {
padding: 10px 8px;
width: 350px;
}
.notification-message {
margin-bottom: 10px;
padding: 0 0 4px 0;
border-bottom: 1px dotted #D3D3D3;
}
.notification-messages .notification-message:last-child {
margin-bottom: 0px;
padding: 0px;
border-bottom: none;
}
.notification-message-text {
padding: 8px 15px;
display: none;
}
.notification-message .notification-message-subject {
cursor: pointer;
}
/* footer */
footer {
position: absolute;
......@@ -148,10 +121,6 @@ footer a, footer a:hover, footer a:visited {
display: none;
}
#notifications-button {
margin: 0;
}
/* 2px border bottom for all bootstrap tables */
.table thead>tr>th {
border-bottom: 1px;
......
......@@ -9,7 +9,7 @@
<a href="{{ op.remove_disk.get_url }}?disk={{d.pk}}"
class="btn btn-xs btn-{{ op.remove_disk.effect}} pull-right operation disk-remove-btn
{% if op.remove_disk.disabled %}disabled{% endif %}">
<i class="fa fa-{{ op.remove_disk.icon }}"></i> {% trans "Remove" %}
<i class="fa fa-{{ op.remove_disk.icon }} fa-fw-12"></i> {% trans "Remove" %}
</a>
</span>
{% endif %}
......@@ -18,7 +18,7 @@
<a href="{{ op.resize_disk.get_url }}?disk={{d.pk}}"
class="btn btn-xs btn-{{ op.resize_disk.effect }} pull-right operation disk-resize-btn
{% if op.resize_disk.disabled %}disabled{% endif %}">
<i class="fa fa-{{ op.resize_disk.icon }}"></i> {% trans "Resize" %}
<i class="fa fa-{{ op.resize_disk.icon }} fa-fw-12"></i> {% trans "Resize" %}
</a>
</span>
{% endif %}
......
{% load i18n %}
{% load hro %}
{% for n in notifications %}
{% for n in page %}
<li class="notification-message" id="msg-{{n.id}}">
<span class="notification-message-subject">
{% if n.status == "new" %}<i class="fa fa-envelope-o"></i> {% endif %}
......
......@@ -5,8 +5,14 @@
{% for t in templates %}
<div class="vm-create-template">
<div class="vm-create-template-summary">
<span class="vm-create-list-name">
{{ t.name }}
<span class="pull-right"><i class="fa fa-{{ t.os_type }}"></i> {{ t.system }}</span>
</span>
<span class="vm-create-list-system">
<i class="fa fa-{{ t.os_type }}"></i>
{{ t.system }}
</span>
<div class="clearfix"></div>
</div>
<div class="vm-create-template-details">
<ul>
......
......@@ -18,35 +18,53 @@
{% block navbar %}
{% if user.is_authenticated and user.pk and not request.token_user %}
<ul class="nav navbar-nav pull-right">
<li class="dropdown" id="notification-button">
<a href="{% url "dashboard.views.notifications" %}"
class="dropdown-toggle" data-toggle="dropdown">
<ul class="nav navbar-nav navbar-right" id="dashboard-menu">
{% if user.is_superuser %}
<li>
<a href="/admin/"><i class="fa fa-cogs"></i> {% trans "Admin" %}</a>
</li>
<li>
<a href="/network/"><i class="fa fa-globe"></i> {% trans "Network" %}</a>
</li>
{% endif %}
<li>
<a href="{% url "dashboard.views.profile-preferences" %}">
<i class="fa fa-user"></i>
{% include "dashboard/_display-name.html" with user=user show_org=True %}
</a>
</li>
<li>
<a href="{% url "logout" %}?next={% url "login" %}">
<i class="fa fa-sign-out"></i> {% trans "Log out" %}
</a>
</li>
<li class="visible-xs">
<a href="{% url "dashboard.views.notifications" %}">
{% trans "Notifications" %}
{% if NEW_NOTIFICATIONS_COUNT > 0 %}
<span class="badge badge-pulse">{{ NEW_NOTIFICATIONS_COUNT }}</span>
{% endif %}
</a>
</li>
<li class="dropdown hidden-xs" id="notification-button">
<a href="{% url "dashboard.views.notifications" %}"
class="dropdown-toggle" data-toggle="dropdown"
id="notification_count" data-notifications="{{ NEW_NOTIFICATIONS_COUNT }}">
{% trans "Notifications" %}
{% if NEW_NOTIFICATIONS_COUNT > 0 %}
<span class="badge badge-pulse">
{{ NEW_NOTIFICATIONS_COUNT }}
</span>
{% endif %}
</a>
<ul class="dropdown-menu" id="notification-messages">
<li>{% trans "Loading..." %}</li>
</ul>
</li>
</ul>
<a class="navbar-brand pull-right" href="{% url "logout" %}?next={% url "login" %}" style="color: white; font-size: 10px;">
<i class="fa fa-sign-out"></i> {% trans "Log out" %}
</a>
<a class="navbar-brand pull-right" href="{% url "dashboard.views.profile-preferences" %}" style="color: white; font-size: 10px;">
<i class="fa fa-user"></i>
{% include "dashboard/_display-name.html" with user=user show_org=True %}
</a>
{% if user.is_superuser %}
<a class="navbar-brand pull-right" href="/network/" style="color: white; font-size: 10px;"><i class="fa fa-globe"></i> {% trans "Network" %}</a>
<a class="navbar-brand pull-right" href="/admin/" style="color: white; font-size: 10px;"><i class="fa fa-cogs"></i> {% trans "Admin" %}</a>
{% endif %}
{% else %}
<a class="navbar-brand pull-right" href="{% url "login" %}?next={{ request.path }}" style="color: white; font-size: 10px;"><i class="fa fa-sign-in"></i> {% trans "Log in " %}</a>
<a class="navbar-brand pull-right" href="{% url "login" %}?next={{ request.path }}"><i class="fa fa-sign-in"></i> {% trans "Log in " %}</a>
{% endif %}
{% endblock %}
......@@ -16,9 +16,11 @@
<div class="panel-body">
<div id="table_container">
<div id="rendered_table" class="panel-body">
<div class="table-responsive">
{% render_table table %}
</div>
</div>
</div>
</div><!-- .panel-body -->
</div>
</div>
......
......@@ -13,7 +13,14 @@
<span class="btn btn-default btn-xs infobtn" data-container="body" title="{% trans "List of your current virtual machines. Favourited ones are ahead of others." %}"><i class="fa fa-info-circle"></i></span>
</div>
<h3 class="no-margin">
<i class="fa fa-desktop"></i> {% trans "Virtual machines" %}
<span class="visible-xs">
<i class="fa fa-desktop"></i>
{% trans "VMs" %}
</span>
<span class="hidden-xs">
<i class="fa fa-desktop"></i>
{% trans "Virtual machines" %}
</span>
</h3>
</div>
<div class="list-group" id="vm-list-view">
......@@ -25,7 +32,7 @@
<i class="fa {{ i.get_status_icon }}" title="{{ i.get_status_display }}"></i>
{{ i.name }}
</span>
<small class="text-muted">
<small class="text-muted index-vm-list-host">
{% if i.owner == request.user %}{{ i.short_hostname }}
{% else %}{{i.owner.profile.get_display_name}}{% endif %}
</small>
......
......@@ -15,11 +15,13 @@
</div>
<div id="table_container">
<div id="rendered_table" class="panel-body">
<div class="table-responsive">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
......
......@@ -6,6 +6,18 @@
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div id="notifications-upper-pagination" class="pull-right">
{% if page.has_previous %}
<a href="?page={{ page.previous_page_number }}">
<i class="fa fa-chevron-left"></i></a>
</a>
{% endif %}
{{ page.number }} / {{ paginator.num_pages }}
{% if page.has_next %}
<a href="?page={{ page.next_page_number }}"><i class="fa fa-chevron-right"></i></a>
{% endif %}
</div>
<h3 class="no-margin"><i class="fa fa-desktop"></i> {% trans "Notifications" %}</h3>
</div>
<div class="panel-body">
......@@ -13,6 +25,29 @@
{% include "dashboard/_notifications-timeline.html" %}
</ul>
</div>
<div class="panel-body text-center" id="notifications-bottom-pagination">
{% if page.has_previous %}
<a href="?page=1">
<i class="fa fa-angle-double-left"></i>
</a>
<a href="{% if page.has_previous %}?page={{ page.previous_page_number}}{% else %}#{% endif %}">
<i class="fa fa-angle-left"></i>
</a>
{% endif %}
<div class="page-numbers">
{{ page.number }} / {{ paginator.num_pages }}
</div>
{% if page.has_next %}
<a href="{% if page.has_next %}?page={{ page.next_page_number}}{% else %}#{% endif %}">
<i class="fa fa-angle-right"></i>
</a>
<a href="?page={{ paginator.num_pages }}">
<i class="fa fa-angle-double-right"></i>
</a>
{% endif %}
</div>
</div>
</div>
</div>
......
......@@ -19,8 +19,8 @@ Do you want to perform the following operation on
<div class="pull-right">
<a class="btn btn-default" href="{{object.get_absolute_url}}"
data-dismiss="modal">{% trans "Cancel" %}</a>
<button class="btn btn-{{ opview.effect }}" type="submit" id="op-form-send">
{% if opview.icon %}<i class="fa fa-{{opview.icon}}"></i> {% endif %}{{ op|capfirst }}
<button class="btn btn-{{ opview.effect }} btn-op-form-send" type="submit" id="op-form-send">
{% if opview.icon %}<i class="fa fa-fw fa-{{opview.icon}}"></i> {% endif %}{{ op|capfirst }}
</button>
</div>
</form>
......@@ -54,7 +54,7 @@
</div>
{% endfor %}
</div>
<div class="list-group-item list-group-footer no-hover">
<div class="list-group-item list-group-footer">
<div class="text-right">
<form class="pull-left" method="POST" action="{% url "dashboard.views.store-refresh-toplist" %}">
{% csrf_token %}
......
......@@ -34,10 +34,12 @@
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
{% if show_lease_table %}
......
......@@ -4,7 +4,7 @@
{% if op.is_disk_operation %}
<a href="{{op.get_url}}" class="btn btn-success btn-xs
operation operation-{{op.op}}">
<i class="fa fa-{{op.icon}}"></i>
<i class="fa fa-{{op.icon}} fa-fw-12"></i>
{{op.name}} </a>
{% endif %}
{% endfor %}
......@@ -13,7 +13,10 @@
<select class="form-control" name="proto" style="width: 70px;"><option>tcp</option><option>udp</option></select>
<div class="input-group-btn">
<button type="submit" class="btn btn-success btn-sm
{% if not is_operator %}disabled{% endif %}">{% trans "Add" %}</button>
{% if not is_operator %}disabled{% endif %}">
<span class="hidden-xs">{% trans "Add" %}</span>
<span class="visible-xs"><i class="fa fa-plus-circle"></i></span>
</button>
</div>
</div>
</form>
......
......@@ -22,13 +22,14 @@
<div id="vm-details-resources-disk">
<h3>
{% trans "Disks" %}
<div class="pull-right">
<div id="disk-ops">
{% include "dashboard/vm-detail/_disk-operations.html" %}
</div>
</div>
{% trans "Disks" %}
</h3>
<div class="clearfix"></div>
{% if not instance.disks.all %}
{% trans "No disks are added." %}
......
......@@ -50,6 +50,7 @@
</div><!-- .row -->
</div><!-- .panel-body -->
<div class="panel-body">
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover vm-list-table"
id="vm-list-table">
<thead><tr>
......@@ -140,6 +141,7 @@
{% endfor %}
</tbody>
</table>
</div><!-- .table-responsive -->
</div>
</div>
</div>
......
......@@ -30,6 +30,7 @@ from django.core.exceptions import (
PermissionDenied, SuspiciousOperation,
)
from django.core.urlresolvers import reverse, reverse_lazy
from django.core.paginator import Paginator, InvalidPage
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import redirect, get_object_or_404
from django.utils.translation import ugettext as _
......@@ -67,9 +68,18 @@ class NotificationView(LoginRequiredMixin, TemplateView):
def get_context_data(self, *args, **kwargs):
context = super(NotificationView, self).get_context_data(
*args, **kwargs)
n = 10 if self.request.is_ajax() else 1000
context['notifications'] = list(
self.request.user.notification_set.all()[:n])
paginate_by = 10 if self.request.is_ajax() else 25
page = self.request.GET.get("page", 1)
notifications = self.request.user.notification_set.all()
paginator = Paginator(notifications, paginate_by)
try:
current_page = paginator.page(page)
except InvalidPage:
current_page = paginator.page(1)
context['page'] = current_page
context['paginator'] = paginator
return context
def get(self, *args, **kwargs):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment