Commit 3cf09597 by Bach Dániel

Merge branch 'feature-group-details-fixed'

Conflicts:
	circle/dashboard/static/dashboard/dashboard.js
	circle/dashboard/urls.py
parents 2d8071b0 9871de77
...@@ -19,11 +19,11 @@ from __future__ import absolute_import ...@@ -19,11 +19,11 @@ from __future__ import absolute_import
from datetime import timedelta from datetime import timedelta
from django.contrib.auth.models import User
from django.contrib.auth.forms import ( from django.contrib.auth.forms import (
AuthenticationForm, PasswordResetForm, SetPasswordForm, AuthenticationForm, PasswordResetForm, SetPasswordForm,
PasswordChangeForm, PasswordChangeForm,
) )
from django.contrib.auth.models import User, Group
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import ( from crispy_forms.layout import (
...@@ -312,6 +312,55 @@ class VmCustomizeForm(forms.Form): ...@@ -312,6 +312,55 @@ class VmCustomizeForm(forms.Form):
) )
class GroupCreateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(GroupCreateForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Div(
AnyTag(
'h4',
HTML(_("Name")),
),
css_class="col-sm-10",
),
css_class="row",
),
Div(
Div(
Field('name', id="group-create-name"),
css_class="col-sm-10",
),
css_class="row",
),
Div( # buttons
Div(
AnyTag( # tip: don't try to use Button class
"button",
AnyTag(
"i",
css_class="icon-play"
),
HTML(" Create"),
css_id="vm-create-submit",
css_class="btn btn-success",
),
css_class="col-sm-5",
),
css_class="row",
),
)
class Meta:
model = Group
fields = ['name', ]
class HostForm(forms.ModelForm): class HostForm(forms.ModelForm):
def setowner(self, user): def setowner(self, user):
......
...@@ -26,7 +26,7 @@ from django.contrib.auth.signals import user_logged_in ...@@ -26,7 +26,7 @@ from django.contrib.auth.signals import user_logged_in
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import ( from django.db.models import (
Model, ForeignKey, OneToOneField, CharField, IntegerField, TextField, Model, ForeignKey, OneToOneField, CharField, IntegerField, TextField,
DateTimeField, DateTimeField, permalink,
) )
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _, override, ugettext from django.utils.translation import ugettext_lazy as _, override, ugettext
...@@ -111,6 +111,11 @@ class GroupProfile(AclBase): ...@@ -111,6 +111,11 @@ class GroupProfile(AclBase):
except cls.DoesNotExist: except cls.DoesNotExist:
return Group.objects.get(name=name) return Group.objects.get(name=name)
@permalink
def get_absolute_url(self):
return ('dashboard.views.group-detail', None,
{'pk': self.group.pk})
def get_or_create_profile(self): def get_or_create_profile(self):
obj, created = GroupProfile.objects.get_or_create(group_id=self.pk) obj, created = GroupProfile.objects.get_or_create(group_id=self.pk)
......
...@@ -607,3 +607,26 @@ footer a, footer a:hover, footer a:visited { ...@@ -607,3 +607,26 @@ footer a, footer a:hover, footer a:visited {
#notifications-button { #notifications-button {
margin: 0; margin: 0;
} }
#group-detail-user-table td:first-child, #group-detail-user-table th:last-child,
#group-detail-user-table td:last-child,
#group-detail-perm-table td:first-child, #group-detail-perm-table th:last-child,
#group-detail-perm-table td:last-child {
text-align: center;
width: 100px;
}
#group-detail-perm-header {
margin-top: 25px;
}
textarea[name="list-new-namelist"] {
max-width: 500px;
min-height: 80px;
margin-bottom: 10px;
}
/* 2px border bottom for all bootstrap tables */
.table thead>tr>th {
border-bottom: 1px;
}
...@@ -34,6 +34,22 @@ $(function () { ...@@ -34,6 +34,22 @@ $(function () {
return false; return false;
}); });
$('.group-create').click(function(e) {
$.ajax({
type: 'GET',
url: '/dashboard/group/create/',
success: function(data) {
$('body').append(data);
addSliderMiscs();
$('#create-modal').modal('show');
$('#create-modal').on('hidden.bs.modal', function() {
$('#create-modal').remove();
});
}
});
return false;
});
$('.template-choose').click(function(e) { $('.template-choose').click(function(e) {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
......
/* rename */ /* rename */
$("#group-details-h1-name, .group-details-rename-button").click(function() { $("#group-details-h1-name, .group-details-rename-button").click(function() {
$("#group-details-h1-name").hide(); $("#group-details-h1-name").hide();
...@@ -30,4 +29,38 @@ ...@@ -30,4 +29,38 @@
$(".group-details-help").stop().slideToggle(); $(".group-details-help").stop().slideToggle();
}); });
/* for Node removes buttons */
$('.delete-from-group').click(function() {
var href = $(this).attr('href');
var tr = $(this).closest('tr');
var group = $(this).data('group_pk');
var member = $(this).data('member_pk');
var dir = window.location.pathname.indexOf('list') == -1;
addModalConfirmation(removeMember,
{ 'url': href,
'data': [],
'tr': tr,
'group_pk': group,
'member_pk': member,
'type': "user",
'redirect': dir});
return false;
});
function removeMember(data) {
$.ajax({
type: 'POST',
url: data['url'],
headers: {"X-CSRFToken": getCookie('csrftoken')},
success: function(re, textStatus, xhr) {
data['tr'].fadeOut(function() {
$(this).remove();});
},
error: function(xhr, textStatus, error) {
addMessage('Uh oh :(', 'danger')
}
});
}
...@@ -99,7 +99,7 @@ $(function() { ...@@ -99,7 +99,7 @@ $(function() {
$("#group-list-column-name", row).html( $("#group-list-column-name", row).html(
$("<a/>", { $("<a/>", {
'class': "real-link", 'class': "real-link",
href: "/dashboard/group/" + data['node_pk'] + "/", href: "/dashboard/group/" + data['group_pk'] + "/",
text: data['new_name'] text: data['new_name']
}) })
).show(); ).show();
......
...@@ -134,16 +134,19 @@ class GroupListTable(Table): ...@@ -134,16 +134,19 @@ class GroupListTable(Table):
) )
number_of_users = TemplateColumn( number_of_users = TemplateColumn(
orderable=False,
template_name='dashboard/group-list/column-users.html', template_name='dashboard/group-list/column-users.html',
attrs={'th': {'class': 'group-list-table-admin'}}, attrs={'th': {'class': 'group-list-table-admin'}},
) )
admin = TemplateColumn( admin = TemplateColumn(
orderable=False,
template_name='dashboard/group-list/column-admin.html', template_name='dashboard/group-list/column-admin.html',
attrs={'th': {'class': 'group-list-table-admin'}}, attrs={'th': {'class': 'group-list-table-admin'}},
) )
actions = TemplateColumn( actions = TemplateColumn(
orderable=False,
attrs={'th': {'class': 'group-list-table-thin'}}, attrs={'th': {'class': 'group-list-table-thin'}},
template_code=('{% include "dashboard/group-list/column-' template_code=('{% include "dashboard/group-list/column-'
'actions.html" with btn_size="btn-xs" %}'), 'actions.html" with btn_size="btn-xs" %}'),
......
{% load i18n %}
<div class="modal fade" id="confirmation-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to remove <strong>{{ member }}</strong> from <strong>{{ object }}</strong>?
{%endblocktrans%}
{% endif %}
<br />
<div class="pull-right" style="margin-top: 15px;">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button id="confirmation-modal-button" type="button" class="btn btn-warning">Remove</button>
</div>
<div class="clearfix"></div>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
{% load crispy_forms_tags %}
<style>
.row {
margin-bottom: 15px;
}
</style>
<form method="POST" action="/dashboard/group/create/">
{% csrf_token %}
{% crispy form %}
</form>
...@@ -37,51 +37,92 @@ ...@@ -37,51 +37,92 @@
<div class="row"> <div class="row">
<div class="col-md-12" id="group-detail-pane"> <div class="col-md-12" id="group-detail-pane">
<div class="panel panel-default" id="group-detail-panel"> <div class="panel panel-default" id="group-detail-panel">
<div class="tab-content panel-body"> <div class="tab-content panel-body" id="group-form-body">
<h3>{% trans "User list"|capfirst %}</h3>
<h3>{% trans "User list"|capfirst %}</h3> <form action="" method="post">{% csrf_token %}
<table class="table table-striped table-with-form-fields"> <table class="table table-striped table-with-form-fields table-bordered" id="group-detail-user-table">
<tbody> <tbody>
<thead><tr><th></th><th>{% trans "Who" %}</th><th></th><th></th></tr></thead> <thead><tr><th></th><th>{% trans "Who" %}</th><th>{% trans "Remove" %}</th></tr></thead>
{% for i in users %} {% for i in users %}
<tr><td><i class="icon-user"></i></td><td>{{i.username}}</td> <tr>
<td><a data-group-pk="{{ i.pk }}" href="#" class="real-link groupuser-delete btn btn-link btn-xs"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr> <td><i class="icon-user"></i></td><td>{{i.username}}</td>
<td>
<a data-group_pk="{{ group.pk }}" data-member_pk="{{i.pk}}" href="{% url "dashboard.views.remove-user" member_pk=i.pk group_pk=group.pk %}" class="real-link delete-from-group btn btn-link btn-xs"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a>
</td>
</tr>
{% endfor %} {% endfor %}
<tr><td><i class="icon-plus"></i></td> <tr>
<td><input type="text" class="form-control" name="perm-new-name" <td><i class="icon-plus"></i></td>
placeholder="{% trans "Name of group or user" %}"></td> <td colspan="2">
<input type="text" class="form-control" name="list-new-name"placeholder="{% trans "Name of user" %}">
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<textarea name="list-new-namelist" class="form-control"
placeholder="{% trans "List of usernames (one per line)." %}"></textarea>
<div class="form-actions">
<button type="submit" class="btn btn-success">{% trans "Save" %}</button>
</div>
</form>
<h3>{% trans "Permissions"|capfirst %}</h3> <h3 id="group-detail-perm-header">{% trans "Permissions"|capfirst %}</h3>
<form action="{{acl.url}}" method="post">{% csrf_token %} <form action="{{acl.url}}" method="post">{% csrf_token %}
<table class="table table-striped table-with-form-fields"> <table class="table table-striped table-with-form-fields table-bordered" id="group-detail-perm-table">
<thead><tr><th></th><th>{% trans "Who" %}</th><th>{% trans "What" %}</th><th></th></tr></thead> <thead>
<tr>
<th></th><th>{% trans "Who" %}</th><th>{% trans "What" %}</th><th>{% trans "Remove" %}</th>
</tr>
</thead>
<tbody> <tbody>
{% for i in acl.users %} {% for i in acl.users %}
<tr><td><i class="icon-user"></i></td><td>{{i.user}}</td> <tr>
<td><select class="form-control" name="perm-u-{{i.user.id}}"> <td><i class="icon-user"></i></td><td>{{i.user}}</td>
{% for id, name in acl.levels %} <td>
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option> <select class="form-control" name="perm-u-{{i.user.id}}">
{% endfor %} {% for id, name in acl.levels %}
</select></td> <option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
<td class="user-remove"><a href="#" class="btn btn-link btn-xs"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
{% endfor %} {% endfor %}
<tr><td><i class="icon-plus"></i></td> </select>
<td><input type="text" class="form-control" name="perm-new-name" </td>
placeholder="{% trans "Name of group or user" %}"></td> <td class="user-remove"><a data-group_pk="{{ group.pk }}" data-member_pk="{{i.user.pk }}" href="{% url "dashboard.views.remove-acluser" member_pk=i.user.pk group_pk=group.pk %}" class="real-link delete-from-group btn btn-link btn-xs"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td>
<td><select class="form-control" name="perm-new"> </tr>
{% for id, name in acl.levels %} {% endfor %}
<option value="{{id}}">{{name}}</option>
{% endfor %} {% for i in acl.groups %}
</select></td><td></td> <tr>
</tr> <td><i class="icon-group"></i></td><td>{{ i.group }}</td>
<td>
<select class="form-control" name="perm-g-{{ i.group.pk }}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
<td class="user-remove"><a data-group_pk="{{ i.pk }}"data-member_pk="{{i.group.pk }}" href="{% url "dashboard.views.remove-aclgroup" member_pk=i.group.pk group_pk=group.pk %}" class="real-link delete-from-group btn btn-link btn-xs"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a>
</td>
</tr>
{% endfor %}
<tr>
<td><i class="icon-plus"></i></td>
<td>
<input type="text" class="form-control" name="perm-new-name"
placeholder="{% trans "Name of group or user" %}">
</td>
<td>
<select class="form-control" name="perm-new">
{% for id, name in acl.levels %}
<option value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
<td></td>
</tr>
</tbody> </tbody>
</table> </table>
<textarea class="form-control"></textarea>
<div class="form-actions panel-body"> <div class="form-actions">
<button type="submit" class="btn btn-success">{% trans "Save" %}</button> <button type="submit" class="btn btn-success">{% trans "Save" %}</button>
</div> </div>
</form> </form>
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
<i class="icon-chevron-sign-right"></i> <strong>{{ more_groups }}</strong> more <i class="icon-chevron-sign-right"></i> <strong>{{ more_groups }}</strong> more
</a> </a>
{% endif %} {% endif %}
<a class="btn btn-success btn-xs group-create" href="#"><i class="icon-upload-alt"></i> {% trans "new" %} </a> <a class="btn btn-success btn-xs group-create" href="{% url "dashboard.views.group-create" %}"><i class="icon-upload-alt"></i> {% trans "new" %} </a>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
</div> </div>
{% endif %} {% endif %}
{% if perms.group %} {% if perms.auth %}
<div class="col-lg-4 col-sm-6"> <div class="col-lg-4 col-sm-6">
{% include "dashboard/index-groups.html" %} {% include "dashboard/index-groups.html" %}
</div> </div>
......
...@@ -21,7 +21,7 @@ from django.conf.urls import patterns, url, include ...@@ -21,7 +21,7 @@ from django.conf.urls import patterns, url, include
from vm.models import Instance from vm.models import Instance
from .views import ( from .views import (
AclUpdateView, DiskAddView, FavouriteView, GroupAclUpdateView, GroupDelete, AclUpdateView, DiskAddView, FavouriteView, GroupAclUpdateView, GroupDelete,
GroupDetailView, GroupList, GroupUserDelete, IndexView, GroupDetailView, GroupList, IndexView,
InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail, InstanceActivityDetail, LeaseCreate, LeaseDelete, LeaseDetail,
MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete, MyPreferencesView, NodeAddTraitView, NodeCreate, NodeDelete,
NodeDetailView, NodeFlushView, NodeGraphView, NodeList, NodeStatus, NodeDetailView, NodeFlushView, NodeGraphView, NodeList, NodeStatus,
...@@ -30,6 +30,8 @@ from .views import ( ...@@ -30,6 +30,8 @@ from .views import (
TransferOwnershipView, vm_activity, VmCreate, VmDelete, VmDetailView, TransferOwnershipView, vm_activity, VmCreate, VmDelete, VmDetailView,
VmDetailVncTokenView, VmGraphView, VmList, VmMassDelete, VmMigrateView, VmDetailVncTokenView, VmGraphView, VmList, VmMassDelete, VmMigrateView,
VmRenewView, DiskRemoveView, get_disk_download_status, InterfaceDeleteView, VmRenewView, DiskRemoveView, get_disk_download_status, InterfaceDeleteView,
GroupRemoveAclUserView, GroupRemoveAclGroupView, GroupRemoveUserView,
GroupCreate,
TemplateChoose, TemplateChoose,
) )
...@@ -116,9 +118,6 @@ urlpatterns = patterns( ...@@ -116,9 +118,6 @@ urlpatterns = patterns(
name='dashboard.views.group-detail'), name='dashboard.views.group-detail'),
url(r'^group/(?P<pk>\d+)/acl/$', GroupAclUpdateView.as_view(), url(r'^group/(?P<pk>\d+)/acl/$', GroupAclUpdateView.as_view(),
name='dashboard.views.group-acl'), name='dashboard.views.group-acl'),
url(r'^groupuser/delete/(?P<pk>\d+)/$', GroupUserDelete.as_view(),
name="dashboard.views.delete-groupuser"),
url(r'^notifications/$', NotificationView.as_view(), url(r'^notifications/$', NotificationView.as_view(),
name="dashboard.views.notifications"), name="dashboard.views.notifications"),
...@@ -134,4 +133,15 @@ urlpatterns = patterns( ...@@ -134,4 +133,15 @@ urlpatterns = patterns(
url(r'^profile/$', MyPreferencesView.as_view(), url(r'^profile/$', MyPreferencesView.as_view(),
name="dashboard.views.profile"), name="dashboard.views.profile"),
url(r'^group/(?P<group_pk>\d+)/remove/acl/user/(?P<member_pk>\d+)/$',
GroupRemoveAclUserView.as_view(),
name="dashboard.views.remove-acluser"),
url(r'^group/(?P<group_pk>\d+)/remove/acl/group/(?P<member_pk>\d+)/$',
GroupRemoveAclGroupView.as_view(),
name="dashboard.views.remove-aclgroup"),
url(r'^group/(?P<group_pk>\d+)/remove/user/(?P<member_pk>\d+)/$',
GroupRemoveUserView.as_view(),
name="dashboard.views.remove-user"),
url(r'^group/create/$', GroupCreate.as_view(),
name='dashboard.views.group-create'),
) )
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