Commit 08b9e86b by Csók Tamás

Merge remote-tracking branch 'origin/master' into issue-218

parents 4ec135f9 0fd140e8
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Level'
db.create_table(u'acl_level', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=50)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
('codename', self.gf('django.db.models.fields.CharField')(max_length=100)),
('weight', self.gf('django.db.models.fields.IntegerField')(null=True)),
))
db.send_create_signal(u'acl', ['Level'])
# Adding unique constraint on 'Level', fields ['content_type', 'codename']
db.create_unique(u'acl_level', ['content_type_id', 'codename'])
# Adding model 'ObjectLevel'
db.create_table(u'acl_objectlevel', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['acl.Level'])),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
('object_id', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal(u'acl', ['ObjectLevel'])
# Adding unique constraint on 'ObjectLevel', fields ['content_type', 'object_id', 'level']
db.create_unique(u'acl_objectlevel', ['content_type_id', 'object_id', 'level_id'])
# Adding M2M table for field users on 'ObjectLevel'
m2m_table_name = db.shorten_name(u'acl_objectlevel_users')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('objectlevel', models.ForeignKey(orm[u'acl.objectlevel'], null=False)),
('user', models.ForeignKey(orm[u'auth.user'], null=False))
))
db.create_unique(m2m_table_name, ['objectlevel_id', 'user_id'])
# Adding M2M table for field groups on 'ObjectLevel'
m2m_table_name = db.shorten_name(u'acl_objectlevel_groups')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('objectlevel', models.ForeignKey(orm[u'acl.objectlevel'], null=False)),
('group', models.ForeignKey(orm[u'auth.group'], null=False))
))
db.create_unique(m2m_table_name, ['objectlevel_id', 'group_id'])
def backwards(self, orm):
# Removing unique constraint on 'ObjectLevel', fields ['content_type', 'object_id', 'level']
db.delete_unique(u'acl_objectlevel', ['content_type_id', 'object_id', 'level_id'])
# Removing unique constraint on 'Level', fields ['content_type', 'codename']
db.delete_unique(u'acl_level', ['content_type_id', 'codename'])
# Deleting model 'Level'
db.delete_table(u'acl_level')
# Deleting model 'ObjectLevel'
db.delete_table(u'acl_objectlevel')
# Removing M2M table for field users on 'ObjectLevel'
db.delete_table(db.shorten_name(u'acl_objectlevel_users'))
# Removing M2M table for field groups on 'ObjectLevel'
db.delete_table(db.shorten_name(u'acl_objectlevel_groups'))
models = {
u'acl.level': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Level'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'weight': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
},
u'acl.objectlevel': {
'Meta': {'unique_together': "(('content_type', 'object_id', 'level'),)", 'object_name': 'ObjectLevel'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['acl.Level']"}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False'})
},
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['acl']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'ObjectLevel.object_id'
# db.alter_column(u'acl_objectlevel', 'object_id', self.gf('django.db.models.fields.IntegerField')())
db.execute('''ALTER TABLE "acl_objectlevel"
ALTER COLUMN "object_id" SET NOT NULL,
ALTER COLUMN "object_id" DROP DEFAULT,
ALTER COLUMN "object_id" TYPE integer USING ("object_id"::integer);''')
def backwards(self, orm):
# Changing field 'ObjectLevel.object_id'
db.alter_column(u'acl_objectlevel', 'object_id', self.gf('django.db.models.fields.CharField')(max_length=255))
models = {
u'acl.level': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Level'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'weight': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
},
u'acl.objectlevel': {
'Meta': {'unique_together': "(('content_type', 'object_id', 'level'),)", 'object_name': 'ObjectLevel'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['acl.Level']"}),
'object_id': ('django.db.models.fields.IntegerField', [], {}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False'})
},
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['acl']
# register a signal do update permissions every migration.
# This is based on app django_extensions update_permissions command
from south.signals import post_migrate
from django.db.models.signals import post_migrate
def update_permissions_after_migration(app, **kwargs):
def update_permissions_after_migration(sender, **kwargs):
"""
Update app permission just after every migration.
This is based on app django_extensions update_permissions
......@@ -12,9 +12,9 @@ def update_permissions_after_migration(app, **kwargs):
"""
from django.conf import settings
from django.db.models import get_app, get_models
from django.db.models import get_models
from django.contrib.auth.management import create_permissions
create_permissions(get_app(app), get_models(), 2 if settings.DEBUG else 0)
create_permissions(sender, get_models(), 2 if settings.DEBUG else 0)
post_migrate.connect(update_permissions_after_migration)
......@@ -78,6 +78,9 @@ TEMPLATE_DEBUG = DEBUG
########## MANAGER CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
ADMINS = (
('Root', 'root@localhost'),
)
EMAIL_SUBJECT_PREFIX = get_env_variable('DJANGO_SUBJECT_PREFIX', '[CIRCLE] ')
......@@ -339,10 +342,6 @@ THIRD_PARTY_APPS = (
'pipeline',
)
import django
if django.get_version() < '1.7':
THIRD_PARTY_APPS += 'south',
# Apps specific for this project go here.
LOCAL_APPS = (
......@@ -526,15 +525,6 @@ except:
LOCALE_PATHS = (join(SITE_ROOT, 'locale'), )
COMPANY_NAME = "BME IK 2014"
SOUTH_MIGRATION_MODULES = {
'taggit': 'taggit.south_migrations',
'vm': 'vm.south_migrations',
'firewall': 'firewall.south_migrations',
'acl': 'acl.south_migrations',
'dashboard': 'dashboard.south_migrations',
'storage': 'storage.south_migrations',
}
graphite_host = environ.get("GRAPHITE_HOST", None)
graphite_port = environ.get("GRAPHITE_PORT", None)
......@@ -559,3 +549,8 @@ MAX_NODE_RAM = get_env_variable("MAX_NODE_RAM", 1024)
# Url to download the client: (e.g. http://circlecloud.org/client/download/)
CLIENT_DOWNLOAD_URL = get_env_variable('CLIENT_DOWNLOAD_URL', 'http://circlecloud.org/client/download/')
ADMIN_ENABLED = False
BLACKLIST_PASSWORD = get_env_variable("BLACKLIST_PASSWORD", "")
BLACKLIST_HOOK_URL = get_env_variable("BLACKLIST_HOOK_URL", "")
......@@ -113,3 +113,5 @@ if DEBUG:
PIPELINE_DISABLED_COMPILERS = (
'pipeline.compilers.less.LessCompiler',
)
ADMIN_ENABLED = True
......@@ -27,22 +27,16 @@ from django.shortcuts import redirect
from circle.settings.base import get_env_variable
from dashboard.views import circle_login, HelpView
from dashboard.forms import CirclePasswordResetForm, CircleSetPasswordForm
from firewall.views import add_blacklist_item
admin.autodiscover()
urlpatterns = patterns(
'',
# url(r'^$', TemplateView.as_view(template_name='base.html')),
# Examples:
# url(r'^$', 'circle.views.home', name='home'),
# url(r'^circle/', include('circle.foo.urls')),
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^$', lambda x: redirect(reverse("dashboard.index"))),
url(r'^admin/', include(admin.site.urls)),
url(r'^network/', include('network.urls')),
url(r'^blacklist-add/', add_blacklist_item),
url(r'^dashboard/', include('dashboard.urls')),
# django/contrib/auth/urls.py (care when new version)
......@@ -79,6 +73,12 @@ if 'rosetta' in settings.INSTALLED_APPS:
url(r'^rosetta/', include('rosetta.urls')),
)
if settings.ADMIN_ENABLED:
urlpatterns += patterns(
'',
url(r'^admin/', include(admin.site.urls)),
)
if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
urlpatterns += patterns(
......
......@@ -417,20 +417,6 @@ class HumanSortField(CharField):
setattr(model_instance, self.attname, value[:self.max_length])
return super(HumanSortField, self).pre_save(model_instance, add)
# allow South to handle these fields smoothly
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules(rules=[
(
(HumanSortField,),
[],
{'monitor': ('monitor', {}),
'maximum_number_length': ('maximum_number_length', {}), }
),
], patterns=['common\.models\.'])
except ImportError:
pass
class HumanReadableObject(object):
def __init__(self, user_text_template, admin_text_template, params):
......
......@@ -29,4 +29,5 @@ def notifications(request):
def extract_settings(request):
return {
'COMPANY_NAME': getattr(settings, "COMPANY_NAME", None),
'ADMIN_ENABLED': getattr(settings, "ADMIN_ENABLED", False),
}
......@@ -20,6 +20,7 @@ from __future__ import absolute_import
from datetime import timedelta
from urlparse import urlparse
from django.forms import ModelForm
from django.contrib.auth.forms import (
AuthenticationForm, PasswordResetForm, SetPasswordForm,
PasswordChangeForm,
......@@ -31,10 +32,12 @@ from django.core.exceptions import PermissionDenied, ValidationError
import autocomplete_light
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (
Layout, Div, BaseInput, Field, HTML, Submit, TEMPLATE_PACK,
Layout, Div, BaseInput, Field, HTML, Submit, TEMPLATE_PACK, Fieldset
)
from crispy_forms.utils import render_field
from crispy_forms.bootstrap import FormActions
from django import forms
from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
from django.forms.widgets import TextInput, HiddenInput
......@@ -51,6 +54,7 @@ from firewall.models import Vlan, Host
from vm.models import (
InstanceTemplate, Lease, InterfaceTemplate, Node, Trait, Instance
)
from storage.models import DataStore, Disk
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Permission
from .models import Profile, GroupProfile
......@@ -1424,18 +1428,52 @@ class RawDataForm(forms.ModelForm):
return helper
permissions_filtered = Permission.objects.exclude(
codename__startswith="add_").exclude(
codename__startswith="delete_").exclude(
codename__startswith="change_")
class GroupPermissionForm(forms.ModelForm):
permissions = forms.ModelMultipleChoiceField(
queryset=permissions_filtered,
queryset=None,
widget=FilteredSelectMultiple(_("permissions"), is_stacked=False)
)
def get_filtered_permissions(self):
""" Collected with this + djcelery source
def get_model_classes_in_module(module):
import sys
import inspect
from django.db.models import Model
classes = []
for name, obj in inspect.getmembers(sys.modules[module]):
if inspect.isclass(obj) and issubclass(obj, Model):
classes.append(name.lower())
return classes
"""
excluded_objs = [
"tag", "taggeditem", "level", "objectlevel",
"permission", "contenttype", "migrationhistory", "site",
"session", "intervalschedule", "crontabschedule", "periodictask",
"periodictasks", "workerstate", "taskstate", "taskmeta",
"tasksetmeta", "logentry",
"baseresourceconfigmodel", "instance", "instanceactivity",
"instancetemplate", "interface", "interfacetemplate", "lease",
"namedbaseresourceconfig", "node", "nodeactivity", "trait",
"virtualmachinedescmodel", "aclbase", "connectcommand",
"favourite", "futuremember", "groupprofile", "model",
"notification", "profile", "timestampedmodel", "userkey",
"datastore", "disk", "model", "timestampedmodel", "aclbase",
"blacklistitem", "domain", "ethernetdevice", "firewall",
"host", "record", "rule", "switchport",
"vlan", "vlangroup", "sender",
]
exclude_add = ["add_%s" % l for l in excluded_objs]
exclude_change = ["change_%s" % l for l in excluded_objs]
exclude_delete = ["delete_%s" % l for l in excluded_objs + ["user"]]
return Permission.objects.exclude(codename__in=exclude_add).exclude(
codename__in=exclude_change).exclude(codename__in=exclude_delete)
def __init__(self, *args, **kwargs):
super(GroupPermissionForm, self).__init__(*args, **kwargs)
self.fields['permissions'].queryset = self.get_filtered_permissions()
class Meta:
model = Group
fields = ('permissions', )
......@@ -1544,3 +1582,36 @@ class UserListSearchForm(forms.Form):
'class': "form-control input-tags",
'placeholder': _("Search...")
}))
class DataStoreForm(ModelForm):
@property
def helper(self):
helper = FormHelper()
helper.layout = Layout(
Fieldset(
'',
'name',
'path',
'hostname',
),
FormActions(
Submit('submit', _('Save')),
)
)
return helper
class Meta:
model = DataStore
class DiskForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DiskForm, self).__init__(*args, **kwargs)
for k, v in self.fields.iteritems():
v.widget.attrs['readonly'] = True
class Meta:
model = Disk
......@@ -168,6 +168,7 @@ $(function() {
} else {
in_progress = false;
if(reload_vm_detail) location.reload();
if(runs > 1) addConnectText();
}
$('a[href="#activity"] i').removeClass('fa-spin');
},
......@@ -179,6 +180,17 @@ $(function() {
});
function addConnectText() {
var activities = $(".timeline .activity");
if(activities.length > 1) {
if(activities.eq(0).data("activity-code") == "vm.Instance.wake_up" ||
activities.eq(0).data("activity-code") == "vm.Instance.agent") {
$("#vm-detail-successfull-boot").slideDown(500);
}
}
}
String.prototype.hashCode = function() {
var hash = 0, i, chr, len;
if (this.length === 0) return hash;
......
......@@ -1247,3 +1247,25 @@ textarea[name="new_members"] {
.pagination {
width: 100%;
}
#empty-vm-help {
position: absolute;
bottom: 70px;
right: 30px;
color: #101010;
text-align: right;
i {
padding-right: 10px;
}
}
#vm-detail-successfull-boot {
margin-bottom: 20px;
display: none;
}
#vm-detail-access-help {
background: #f9f9f9;
margin-top: 20px;
}
......@@ -18,7 +18,7 @@
from __future__ import absolute_import
from django.contrib.auth.models import Group, User
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, ugettext
from django.utils.html import mark_safe
from django_tables2 import Table, A
......@@ -27,10 +27,36 @@ from django_tables2.columns import (
)
from django_sshkey.models import UserKey
from storage.models import Disk
from vm.models import Node, InstanceTemplate, Lease
from dashboard.models import ConnectCommand
class FileSizeColumn(Column):
def render(self, value):
from sizefield.utils import filesizeformat
size = filesizeformat(value)
return size
class ApplianceColumn(TemplateColumn):
def render(self, *args, **kwargs):
value = super(ApplianceColumn, self).render(*args, **kwargs)
abbr = '<abbr title="%s">%s</abbr>'
appliance = kwargs['record'].get_appliance()
if appliance is None:
return value
elif isinstance(appliance, InstanceTemplate):
# Translators: [T] as Template
title, text = ugettext("Template"), ugettext("[T]")
else:
# Translators: [VM] as Virtual Machine
title, text = ugettext("Virtual machine"), ugettext("[VM]")
return mark_safe("%s %s" % (abbr % (title, text), value))
class NodeListTable(Table):
pk = Column(
......@@ -299,3 +325,29 @@ class ConnectCommandListTable(Table):
"You don't have any custom connection commands yet. You can "
"specify commands to be displayed on VM detail pages instead of "
"the defaults.")
class DiskListTable(Table):
pk = LinkColumn(
'dashboard.views.disk-detail',
args=[A('pk')],
verbose_name=_("ID"),
)
size = FileSizeColumn()
appliance = ApplianceColumn(
template_name="dashboard/storage/column-appliance.html",
verbose_name=_("Appliance"),
orderable=False,
)
is_ready = BooleanColumn(
verbose_name=_("ready")
)
class Meta:
model = Disk
attrs = {'class': "table table-bordered table-striped table-hover",
'id': "disk-list-table"}
fields = ("pk", "appliance", "filename", "size", "is_ready")
prefix = "disk-"
order_by = ("-pk", )
per_page = 65536
......@@ -25,5 +25,6 @@
<div style="clear: both;"></div>
{% if request.user.is_superuser %}
<small>{% trans "File name" %}: {{ d.filename }}</small>
<small>{% trans "File name" %}: {{ d.filename }}</small><br/>
<small>{% trans "Bus" %}: {{ d.device_bus }}</small>
{% endif %}
......@@ -20,9 +20,16 @@
{% if user.is_authenticated and user.pk and not request.token_user %}
<ul class="nav navbar-nav navbar-right" id="dashboard-menu">
{% if user.is_superuser %}
{% if ADMIN_ENABLED %}
<li>
<a href="/admin/"><i class="fa fa-cogs"></i> {% trans "Admin" %}</a>
</li>
{% endif %}
<li>
<a href="{% url "dashboard.views.storage" %}"><i class="fa fa-database"></i>
{% trans "Storage" %}
</a>
</li>
<li>
<a href="/network/"><i class="fa fa-globe"></i> {% trans "Network" %}</a>
</li>
......
......@@ -34,7 +34,7 @@
</div>
<div class="list-group-item list-group-footer">
<div class="row">
<div <