Added IDs and identifiable classes to all action buttons.
Fixes bug 953483. Change-Id: Ie6b858a9a595d024f71ca372a11b97a454b3b1e8
This commit is contained in:
parent
ee3e890466
commit
cb8f3ddf4e
@ -41,7 +41,7 @@ How to use Horizon in your own projects.
|
|||||||
intro
|
intro
|
||||||
quickstart
|
quickstart
|
||||||
topics/deployment
|
topics/deployment
|
||||||
topics/branding
|
topics/customizing
|
||||||
|
|
||||||
Developer Docs
|
Developer Docs
|
||||||
==============
|
==============
|
||||||
|
@ -28,8 +28,10 @@ Alternately specify the listen IP and port::
|
|||||||
Once the Horizon server is running point a web browser to http://localhost:8000
|
Once the Horizon server is running point a web browser to http://localhost:8000
|
||||||
or to the IP and port the server is listening.
|
or to the IP and port the server is listening.
|
||||||
|
|
||||||
.. note:: The ``DevStack`` project (http://devstack.org/) can be used to install
|
.. note::
|
||||||
an OpenStack development environment from scratch.
|
|
||||||
|
The ``DevStack`` project (http://devstack.org/) can be used to install
|
||||||
|
an OpenStack development environment from scratch.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
==============================
|
|
||||||
Change the branding of Horizon
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Changing the Page Title
|
|
||||||
=======================
|
|
||||||
|
|
||||||
The OpenStack Dashboard Page Title branding (i.e. "**OpenStack** Dashboard")
|
|
||||||
can be overwritten by adding the attribute ``SITE_BRANDING``
|
|
||||||
to ``local_settings.py`` with the value being the desired name.
|
|
||||||
|
|
||||||
The file ``local_settings.py`` can be found at the Horizon directory path of
|
|
||||||
``horizon/openstack-dashboard/local/local_settings.py``.
|
|
||||||
|
|
||||||
Changing the Page Logo
|
|
||||||
=======================
|
|
||||||
|
|
||||||
The OpenStack Logo is pulled in through ``style.css``::
|
|
||||||
|
|
||||||
#splash .modal {
|
|
||||||
background: #fff url(../images/logo.png) no-repeat center 35px;
|
|
||||||
|
|
||||||
h1.brand a {
|
|
||||||
background: url(../images/logo.png) top left no-repeat;
|
|
||||||
|
|
||||||
To override the OpenStack Logo image, replace the image at the directory path
|
|
||||||
``horizon/openstack-dashboard/dashboard/static/dashboard/images/logo.png``.
|
|
||||||
|
|
||||||
The dimensions should be ``width: 108px, height: 121px``.
|
|
72
docs/source/topics/customizing.rst
Normal file
72
docs/source/topics/customizing.rst
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
===================
|
||||||
|
Customizing Horizon
|
||||||
|
===================
|
||||||
|
|
||||||
|
Changing the Site Title
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The OpenStack Dashboard Site Title branding (i.e. "**OpenStack** Dashboard")
|
||||||
|
can be overwritten by adding the attribute ``SITE_BRANDING``
|
||||||
|
to ``local_settings.py`` with the value being the desired name.
|
||||||
|
|
||||||
|
The file ``local_settings.py`` can be found at the Horizon directory path of
|
||||||
|
``horizon/openstack-dashboard/local/local_settings.py``.
|
||||||
|
|
||||||
|
Changing the Logo
|
||||||
|
=================
|
||||||
|
|
||||||
|
The OpenStack Logo is pulled in through ``style.css``::
|
||||||
|
|
||||||
|
#splash .modal {
|
||||||
|
background: #fff url(../images/logo.png) no-repeat center 35px;
|
||||||
|
|
||||||
|
h1.brand a {
|
||||||
|
background: url(../images/logo.png) top left no-repeat;
|
||||||
|
|
||||||
|
To override the OpenStack Logo image, replace the image at the directory path
|
||||||
|
``horizon/openstack-dashboard/dashboard/static/dashboard/images/logo.png``.
|
||||||
|
|
||||||
|
The dimensions should be ``width: 108px, height: 121px``.
|
||||||
|
|
||||||
|
Button Icons
|
||||||
|
============
|
||||||
|
|
||||||
|
Horizon provides hooks for customizing the look and feel of each class of
|
||||||
|
button on the site. The following classes are used to identify each type of
|
||||||
|
button:
|
||||||
|
|
||||||
|
* Generic Classes
|
||||||
|
* btn-search
|
||||||
|
* btn-delete
|
||||||
|
* btn-upload
|
||||||
|
* btn-download
|
||||||
|
* btn-create
|
||||||
|
* btn-edit
|
||||||
|
* btn-list
|
||||||
|
* btn-copy
|
||||||
|
* btn-camera
|
||||||
|
* btn-stats
|
||||||
|
* btn-enable
|
||||||
|
* btn-disable
|
||||||
|
|
||||||
|
* Floating IP-specific Classes
|
||||||
|
* btn-allocate
|
||||||
|
* btn-release
|
||||||
|
* btn-associate
|
||||||
|
* btn-disassociate
|
||||||
|
|
||||||
|
* Instance-specific Classes
|
||||||
|
* btn-launch
|
||||||
|
* btn-terminate
|
||||||
|
* btn-reboot
|
||||||
|
* btn-pause
|
||||||
|
* btn-suspend
|
||||||
|
* btn-console
|
||||||
|
* btn-log
|
||||||
|
|
||||||
|
* Volume-specific classes
|
||||||
|
* btn-detach
|
||||||
|
|
||||||
|
Additionally, the site-wide default button classes can be configured by
|
||||||
|
setting ``ACTION_CSS_CLASSES`` to a tuple of the classes you wish to appear
|
||||||
|
on all action buttons in your ``local_settings.py`` file.
|
@ -32,7 +32,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
class AllocateIP(tables.LinkAction):
|
class AllocateIP(tables.LinkAction):
|
||||||
name = "allocate"
|
name = "allocate"
|
||||||
verbose_name = _("Allocate IP To Project")
|
verbose_name = _("Allocate IP To Project")
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-allocate")
|
||||||
url = "horizon:nova:access_and_security:floating_ips:allocate"
|
url = "horizon:nova:access_and_security:floating_ips:allocate"
|
||||||
|
|
||||||
def single(self, data_table, request, *args):
|
def single(self, data_table, request, *args):
|
||||||
@ -45,7 +45,7 @@ class ReleaseIPs(tables.BatchAction):
|
|||||||
action_past = _("Released")
|
action_past = _("Released")
|
||||||
data_type_singular = _("Floating IP")
|
data_type_singular = _("Floating IP")
|
||||||
data_type_plural = _("Floating IPs")
|
data_type_plural = _("Floating IPs")
|
||||||
classes = ('btn-danger',)
|
classes = ('btn-danger', 'btn-release')
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
def action(self, request, obj_id):
|
||||||
api.tenant_floating_ip_release(request, obj_id)
|
api.tenant_floating_ip_release(request, obj_id)
|
||||||
@ -55,7 +55,7 @@ class AssociateIP(tables.LinkAction):
|
|||||||
name = "associate"
|
name = "associate"
|
||||||
verbose_name = _("Associate IP")
|
verbose_name = _("Associate IP")
|
||||||
url = "horizon:nova:access_and_security:floating_ips:associate"
|
url = "horizon:nova:access_and_security:floating_ips:associate"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-associate")
|
||||||
|
|
||||||
def allowed(self, request, fip):
|
def allowed(self, request, fip):
|
||||||
if fip.instance_id:
|
if fip.instance_id:
|
||||||
@ -66,6 +66,7 @@ class AssociateIP(tables.LinkAction):
|
|||||||
class DisassociateIP(tables.Action):
|
class DisassociateIP(tables.Action):
|
||||||
name = "disassociate"
|
name = "disassociate"
|
||||||
verbose_name = _("Disassociate IP")
|
verbose_name = _("Disassociate IP")
|
||||||
|
classes = ("btn-disassociate", "btn-danger")
|
||||||
|
|
||||||
def allowed(self, request, fip):
|
def allowed(self, request, fip):
|
||||||
if fip.instance_id:
|
if fip.instance_id:
|
||||||
|
@ -37,14 +37,14 @@ class ImportKeyPair(tables.LinkAction):
|
|||||||
name = "import"
|
name = "import"
|
||||||
verbose_name = _("Import Keypair")
|
verbose_name = _("Import Keypair")
|
||||||
url = "horizon:nova:access_and_security:keypairs:import"
|
url = "horizon:nova:access_and_security:keypairs:import"
|
||||||
attrs = {"class": "ajax-modal btn"}
|
classes = ("ajax-modal", "btn-upload")
|
||||||
|
|
||||||
|
|
||||||
class CreateKeyPair(tables.LinkAction):
|
class CreateKeyPair(tables.LinkAction):
|
||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Keypair")
|
verbose_name = _("Create Keypair")
|
||||||
url = "horizon:nova:access_and_security:keypairs:create"
|
url = "horizon:nova:access_and_security:keypairs:create"
|
||||||
attrs = {"class": "ajax-modal btn"}
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class KeypairsTable(tables.DataTable):
|
class KeypairsTable(tables.DataTable):
|
||||||
|
@ -43,14 +43,14 @@ class CreateGroup(tables.LinkAction):
|
|||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Security Group")
|
verbose_name = _("Create Security Group")
|
||||||
url = "horizon:nova:access_and_security:security_groups:create"
|
url = "horizon:nova:access_and_security:security_groups:create"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class EditRules(tables.LinkAction):
|
class EditRules(tables.LinkAction):
|
||||||
name = "edit_rules"
|
name = "edit_rules"
|
||||||
verbose_name = _("Edit Rules")
|
verbose_name = _("Edit Rules")
|
||||||
url = "horizon:nova:access_and_security:security_groups:edit_rules"
|
url = "horizon:nova:access_and_security:security_groups:edit_rules"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupsTable(tables.DataTable):
|
class SecurityGroupsTable(tables.DataTable):
|
||||||
|
@ -25,7 +25,6 @@ from django.utils import http
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from horizon import api
|
from horizon import api
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
|
|
||||||
|
|
||||||
@ -63,20 +62,21 @@ class CreateContainer(tables.LinkAction):
|
|||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Container")
|
verbose_name = _("Create Container")
|
||||||
url = "horizon:nova:containers:create"
|
url = "horizon:nova:containers:create"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class ListObjects(tables.LinkAction):
|
class ListObjects(tables.LinkAction):
|
||||||
name = "list_objects"
|
name = "list_objects"
|
||||||
verbose_name = _("List Objects")
|
verbose_name = _("List Objects")
|
||||||
url = "horizon:nova:containers:object_index"
|
url = "horizon:nova:containers:object_index"
|
||||||
|
classes = ("btn-list",)
|
||||||
|
|
||||||
|
|
||||||
class UploadObject(tables.LinkAction):
|
class UploadObject(tables.LinkAction):
|
||||||
name = "upload"
|
name = "upload"
|
||||||
verbose_name = _("Upload Object")
|
verbose_name = _("Upload Object")
|
||||||
url = "horizon:nova:containers:object_upload"
|
url = "horizon:nova:containers:object_upload"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-upload")
|
||||||
|
|
||||||
def get_link_url(self, datum=None):
|
def get_link_url(self, datum=None):
|
||||||
# Usable for both the container and object tables
|
# Usable for both the container and object tables
|
||||||
@ -130,7 +130,7 @@ class CopyObject(tables.LinkAction):
|
|||||||
name = "copy"
|
name = "copy"
|
||||||
verbose_name = _("Copy")
|
verbose_name = _("Copy")
|
||||||
url = "horizon:nova:containers:object_copy"
|
url = "horizon:nova:containers:object_copy"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-copy")
|
||||||
|
|
||||||
def get_link_url(self, obj):
|
def get_link_url(self, obj):
|
||||||
return reverse(self.url, args=(http.urlquote(obj.container.name),
|
return reverse(self.url, args=(http.urlquote(obj.container.name),
|
||||||
@ -141,6 +141,7 @@ class DownloadObject(tables.LinkAction):
|
|||||||
name = "download"
|
name = "download"
|
||||||
verbose_name = _("Download")
|
verbose_name = _("Download")
|
||||||
url = "horizon:nova:containers:object_download"
|
url = "horizon:nova:containers:object_download"
|
||||||
|
classes = ("btn-download",)
|
||||||
|
|
||||||
def get_link_url(self, obj):
|
def get_link_url(self, obj):
|
||||||
#assert False, obj.__dict__['_apiresource'].__dict__
|
#assert False, obj.__dict__['_apiresource'].__dict__
|
||||||
|
@ -43,14 +43,14 @@ class LaunchImage(tables.LinkAction):
|
|||||||
name = "launch"
|
name = "launch"
|
||||||
verbose_name = _("Launch")
|
verbose_name = _("Launch")
|
||||||
url = "horizon:nova:images_and_snapshots:images:launch"
|
url = "horizon:nova:images_and_snapshots:images:launch"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-launch")
|
||||||
|
|
||||||
|
|
||||||
class EditImage(tables.LinkAction):
|
class EditImage(tables.LinkAction):
|
||||||
name = "edit"
|
name = "edit"
|
||||||
verbose_name = _("Edit")
|
verbose_name = _("Edit")
|
||||||
url = "horizon:nova:images_and_snapshots:images:update"
|
url = "horizon:nova:images_and_snapshots:images:update"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
def get_image_type(image):
|
def get_image_type(image):
|
||||||
|
@ -29,7 +29,6 @@ LOG = logging.getLogger(__name__)
|
|||||||
class DeleteVolumeSnapshot(tables.DeleteAction):
|
class DeleteVolumeSnapshot(tables.DeleteAction):
|
||||||
data_type_singular = _("Volume Snapshot")
|
data_type_singular = _("Volume Snapshot")
|
||||||
data_type_plural = _("Volume Snapshots")
|
data_type_plural = _("Volume Snapshots")
|
||||||
classes = ('btn-danger',)
|
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
def delete(self, request, obj_id):
|
||||||
api.volume_snapshot_delete(request, obj_id)
|
api.volume_snapshot_delete(request, obj_id)
|
||||||
|
@ -55,7 +55,7 @@ class TerminateInstance(tables.BatchAction):
|
|||||||
action_past = _("Terminated")
|
action_past = _("Terminated")
|
||||||
data_type_singular = _("Instance")
|
data_type_singular = _("Instance")
|
||||||
data_type_plural = _("Instances")
|
data_type_plural = _("Instances")
|
||||||
classes = ('btn-danger',)
|
classes = ('btn-danger', 'btn-terminate')
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
def action(self, request, obj_id):
|
||||||
api.server_delete(request, obj_id)
|
api.server_delete(request, obj_id)
|
||||||
@ -67,7 +67,7 @@ class RebootInstance(tables.BatchAction):
|
|||||||
action_past = _("Rebooted")
|
action_past = _("Rebooted")
|
||||||
data_type_singular = _("Instance")
|
data_type_singular = _("Instance")
|
||||||
data_type_plural = _("Instances")
|
data_type_plural = _("Instances")
|
||||||
classes = ('btn-danger',)
|
classes = ('btn-danger', 'btn-reboot')
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
return instance.status in ACTIVE_STATES or instance.status == 'SHUTOFF'
|
return instance.status in ACTIVE_STATES or instance.status == 'SHUTOFF'
|
||||||
@ -82,6 +82,7 @@ class TogglePause(tables.BatchAction):
|
|||||||
action_past = (_("Paused"), _("Unpaused"))
|
action_past = (_("Paused"), _("Unpaused"))
|
||||||
data_type_singular = _("Instance")
|
data_type_singular = _("Instance")
|
||||||
data_type_plural = _("Instances")
|
data_type_plural = _("Instances")
|
||||||
|
classes = ("btn-pause")
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
self.paused = False
|
self.paused = False
|
||||||
@ -107,6 +108,7 @@ class ToggleSuspend(tables.BatchAction):
|
|||||||
action_past = (_("Suspended"), _("Resumed"))
|
action_past = (_("Suspended"), _("Resumed"))
|
||||||
data_type_singular = _("Instance")
|
data_type_singular = _("Instance")
|
||||||
data_type_plural = _("Instances")
|
data_type_plural = _("Instances")
|
||||||
|
classes = ("btn-suspend")
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
self.suspended = False
|
self.suspended = False
|
||||||
@ -130,20 +132,21 @@ class LaunchLink(tables.LinkAction):
|
|||||||
name = "launch"
|
name = "launch"
|
||||||
verbose_name = _("Launch Instance")
|
verbose_name = _("Launch Instance")
|
||||||
url = "horizon:nova:images_and_snapshots:index"
|
url = "horizon:nova:images_and_snapshots:index"
|
||||||
|
classes = ("btn-launch",)
|
||||||
|
|
||||||
|
|
||||||
class EditInstance(tables.LinkAction):
|
class EditInstance(tables.LinkAction):
|
||||||
name = "edit"
|
name = "edit"
|
||||||
verbose_name = _("Edit Instance")
|
verbose_name = _("Edit Instance")
|
||||||
url = "horizon:nova:instances_and_volumes:instances:update"
|
url = "horizon:nova:instances_and_volumes:instances:update"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
class SnapshotLink(tables.LinkAction):
|
class SnapshotLink(tables.LinkAction):
|
||||||
name = "snapshot"
|
name = "snapshot"
|
||||||
verbose_name = _("Snapshot")
|
verbose_name = _("Snapshot")
|
||||||
url = "horizon:nova:images_and_snapshots:snapshots:create"
|
url = "horizon:nova:images_and_snapshots:snapshots:create"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-camera")
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
return instance.status in ACTIVE_STATES
|
return instance.status in ACTIVE_STATES
|
||||||
@ -153,6 +156,7 @@ class ConsoleLink(tables.LinkAction):
|
|||||||
name = "console"
|
name = "console"
|
||||||
verbose_name = _("VNC Console")
|
verbose_name = _("VNC Console")
|
||||||
url = "horizon:nova:instances_and_volumes:instances:vnc"
|
url = "horizon:nova:instances_and_volumes:instances:vnc"
|
||||||
|
classes = ("btn-console",)
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
return instance.status in ACTIVE_STATES
|
return instance.status in ACTIVE_STATES
|
||||||
@ -162,6 +166,7 @@ class LogLink(tables.LinkAction):
|
|||||||
name = "log"
|
name = "log"
|
||||||
verbose_name = _("View Log")
|
verbose_name = _("View Log")
|
||||||
url = "horizon:nova:instances_and_volumes:instances:console"
|
url = "horizon:nova:instances_and_volumes:instances:console"
|
||||||
|
classes = ("btn-log",)
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
return instance.status in ACTIVE_STATES
|
return instance.status in ACTIVE_STATES
|
||||||
|
@ -34,7 +34,6 @@ DELETABLE_STATES = ("available", "error")
|
|||||||
class DeleteVolume(tables.DeleteAction):
|
class DeleteVolume(tables.DeleteAction):
|
||||||
data_type_singular = _("Volume")
|
data_type_singular = _("Volume")
|
||||||
data_type_plural = _("Volumes")
|
data_type_plural = _("Volumes")
|
||||||
classes = ('btn-danger',)
|
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
def delete(self, request, obj_id):
|
||||||
api.volume_delete(request, obj_id)
|
api.volume_delete(request, obj_id)
|
||||||
@ -58,14 +57,14 @@ class CreateVolume(tables.LinkAction):
|
|||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Volume")
|
verbose_name = _("Create Volume")
|
||||||
url = "%s:volumes:create" % URL_PREFIX
|
url = "%s:volumes:create" % URL_PREFIX
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class EditAttachments(tables.LinkAction):
|
class EditAttachments(tables.LinkAction):
|
||||||
name = "attachments"
|
name = "attachments"
|
||||||
verbose_name = _("Edit Attachments")
|
verbose_name = _("Edit Attachments")
|
||||||
url = "%s:volumes:attach" % URL_PREFIX
|
url = "%s:volumes:attach" % URL_PREFIX
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
def allowed(self, request, volume=None):
|
def allowed(self, request, volume=None):
|
||||||
return volume.status in ("available", "in-use")
|
return volume.status in ("available", "in-use")
|
||||||
@ -75,7 +74,7 @@ class CreateSnapshot(tables.LinkAction):
|
|||||||
name = "snapshots"
|
name = "snapshots"
|
||||||
verbose_name = _("Create Snapshot")
|
verbose_name = _("Create Snapshot")
|
||||||
url = "%s:volumes:create_snapshot" % URL_PREFIX
|
url = "%s:volumes:create_snapshot" % URL_PREFIX
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-camera")
|
||||||
|
|
||||||
def allowed(self, request, volume=None):
|
def allowed(self, request, volume=None):
|
||||||
return volume.status == "available"
|
return volume.status == "available"
|
||||||
@ -154,7 +153,7 @@ class DetachVolume(tables.BatchAction):
|
|||||||
action_past = _("Detached")
|
action_past = _("Detached")
|
||||||
data_type_singular = _("Volume")
|
data_type_singular = _("Volume")
|
||||||
data_type_plural = _("Volumes")
|
data_type_plural = _("Volumes")
|
||||||
classes = ('btn-danger',)
|
classes = ('btn-danger', 'btn-detach')
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
def action(self, request, obj_id):
|
||||||
instance_id = self.table.get_object_by_id(obj_id)['serverId']
|
instance_id = self.table.get_object_by_id(obj_id)['serverId']
|
||||||
|
@ -21,7 +21,7 @@ class CreateFlavor(tables.LinkAction):
|
|||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Flavor")
|
verbose_name = _("Create Flavor")
|
||||||
url = "horizon:syspanel:flavors:create"
|
url = "horizon:syspanel:flavors:create"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class FlavorsTable(tables.DataTable):
|
class FlavorsTable(tables.DataTable):
|
||||||
|
@ -16,26 +16,28 @@ class ModifyQuotasLink(tables.LinkAction):
|
|||||||
name = "quotas"
|
name = "quotas"
|
||||||
verbose_name = _("Modify Quotas")
|
verbose_name = _("Modify Quotas")
|
||||||
url = "horizon:syspanel:projects:quotas"
|
url = "horizon:syspanel:projects:quotas"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
class ViewMembersLink(tables.LinkAction):
|
class ViewMembersLink(tables.LinkAction):
|
||||||
name = "users"
|
name = "users"
|
||||||
verbose_name = _("Modify Users")
|
verbose_name = _("Modify Users")
|
||||||
url = "horizon:syspanel:projects:users"
|
url = "horizon:syspanel:projects:users"
|
||||||
|
classes = ("btn-download",)
|
||||||
|
|
||||||
|
|
||||||
class UsageLink(tables.LinkAction):
|
class UsageLink(tables.LinkAction):
|
||||||
name = "usage"
|
name = "usage"
|
||||||
verbose_name = _("View Usage")
|
verbose_name = _("View Usage")
|
||||||
url = "horizon:syspanel:projects:usage"
|
url = "horizon:syspanel:projects:usage"
|
||||||
|
classes = ("btn-stats",)
|
||||||
|
|
||||||
|
|
||||||
class EditLink(tables.LinkAction):
|
class EditLink(tables.LinkAction):
|
||||||
name = "update"
|
name = "update"
|
||||||
verbose_name = _("Edit Project")
|
verbose_name = _("Edit Project")
|
||||||
url = "horizon:syspanel:projects:update"
|
url = "horizon:syspanel:projects:update"
|
||||||
attrs = {"class": "ajax-modal"}
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
class CreateLink(tables.LinkAction):
|
class CreateLink(tables.LinkAction):
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django import shortcuts
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import api
|
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,20 +15,21 @@ class CreateUserLink(tables.LinkAction):
|
|||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create User")
|
verbose_name = _("Create User")
|
||||||
url = "horizon:syspanel:users:create"
|
url = "horizon:syspanel:users:create"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
|
||||||
class EditUserLink(tables.LinkAction):
|
class EditUserLink(tables.LinkAction):
|
||||||
name = "edit"
|
name = "edit"
|
||||||
verbose_name = _("Edit")
|
verbose_name = _("Edit")
|
||||||
url = "horizon:syspanel:users:update"
|
url = "horizon:syspanel:users:update"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
|
||||||
class EnableUsersAction(tables.Action):
|
class EnableUsersAction(tables.Action):
|
||||||
name = "enable"
|
name = "enable"
|
||||||
verbose_name = _("Enable")
|
verbose_name = _("Enable")
|
||||||
verbose_name_plural = _("Enable Users")
|
verbose_name_plural = _("Enable Users")
|
||||||
|
classes = ("btn-enable",)
|
||||||
|
|
||||||
def allowed(self, request, user):
|
def allowed(self, request, user):
|
||||||
return not user.enabled
|
return not user.enabled
|
||||||
@ -57,6 +58,7 @@ class DisableUsersAction(tables.Action):
|
|||||||
name = "disable"
|
name = "disable"
|
||||||
verbose_name = _("Disable")
|
verbose_name = _("Disable")
|
||||||
verbose_name_plural = _("Disable Users")
|
verbose_name_plural = _("Disable Users")
|
||||||
|
classes = ("btn-disable",)
|
||||||
|
|
||||||
def allowed(self, request, user):
|
def allowed(self, request, user):
|
||||||
return user.enabled
|
return user.enabled
|
||||||
|
@ -32,6 +32,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# For Bootstrap integration; can be overridden in settings.
|
# For Bootstrap integration; can be overridden in settings.
|
||||||
ACTION_CSS_CLASSES = ("btn", "btn-small")
|
ACTION_CSS_CLASSES = ("btn", "btn-small")
|
||||||
|
STRING_SEPARATOR = "__"
|
||||||
|
|
||||||
|
|
||||||
class BaseAction(html.HTMLElement):
|
class BaseAction(html.HTMLElement):
|
||||||
@ -41,6 +42,10 @@ class BaseAction(html.HTMLElement):
|
|||||||
requires_input = False
|
requires_input = False
|
||||||
preempt = False
|
preempt = False
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(BaseAction, self).__init__()
|
||||||
|
self.id_counter = 0
|
||||||
|
|
||||||
def allowed(self, request, datum):
|
def allowed(self, request, datum):
|
||||||
""" Determine whether this action is allowed for the current request.
|
""" Determine whether this action is allowed for the current request.
|
||||||
|
|
||||||
@ -64,11 +69,21 @@ class BaseAction(html.HTMLElement):
|
|||||||
|
|
||||||
def get_default_classes(self):
|
def get_default_classes(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of the default classes for the tab. Defaults to
|
Returns a list of the default classes for the action. Defaults to
|
||||||
``["btn", "btn-small"]``.
|
``["btn", "btn-small"]``.
|
||||||
"""
|
"""
|
||||||
return getattr(settings, "ACTION_CSS_CLASSES", ACTION_CSS_CLASSES)
|
return getattr(settings, "ACTION_CSS_CLASSES", ACTION_CSS_CLASSES)
|
||||||
|
|
||||||
|
def get_default_attrs(self):
|
||||||
|
"""
|
||||||
|
Returns a list of the default HTML attributes for the action. Defaults
|
||||||
|
to returning an ``id`` attribute with the value
|
||||||
|
``{{ table.name }}__action_{{ action.name }}__{{ creation counter }}``.
|
||||||
|
"""
|
||||||
|
bits = (self.table.name, "action_%s" % self.name, str(self.id_counter))
|
||||||
|
self.id_counter += 1
|
||||||
|
return {"id": STRING_SEPARATOR.join(bits)}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s: %s>" % (self.__class__.__name__, self.name)
|
return "<%s: %s>" % (self.__class__.__name__, self.name)
|
||||||
|
|
||||||
@ -286,6 +301,11 @@ class FilterAction(BaseAction):
|
|||||||
"""
|
"""
|
||||||
return "__".join([self.table.name, self.name, self.param_name])
|
return "__".join([self.table.name, self.name, self.param_name])
|
||||||
|
|
||||||
|
def get_default_classes(self):
|
||||||
|
classes = super(FilterAction, self).get_default_classes()
|
||||||
|
classes += ("btn-search",)
|
||||||
|
return classes
|
||||||
|
|
||||||
def filter(self, table, data, filter_string):
|
def filter(self, table, data, filter_string):
|
||||||
""" Provides the actual filtering logic.
|
""" Provides the actual filtering logic.
|
||||||
|
|
||||||
@ -452,10 +472,14 @@ class DeleteAction(BatchAction):
|
|||||||
name = "delete"
|
name = "delete"
|
||||||
action_present = _("Delete")
|
action_present = _("Delete")
|
||||||
action_past = _("Deleted")
|
action_past = _("Deleted")
|
||||||
classes = ('btn-danger',)
|
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
def action(self, request, obj_id):
|
||||||
return self.delete(request, obj_id)
|
return self.delete(request, obj_id)
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
def delete(self, request, obj_id):
|
||||||
raise NotImplementedError("DeleteAction must define a delete method.")
|
raise NotImplementedError("DeleteAction must define a delete method.")
|
||||||
|
|
||||||
|
def get_default_classes(self):
|
||||||
|
classes = super(DeleteAction, self).get_default_classes()
|
||||||
|
classes += ("btn-danger", "btn-delete")
|
||||||
|
return classes
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
{% if filter %}
|
{% if filter %}
|
||||||
<div class="table_search">
|
<div class="table_search">
|
||||||
<input class="span3 example" value="{{ filter.filter_string|default:'' }}" type="text" name="{{ filter.get_param_name }}" />
|
<input class="span3 example" value="{{ filter.filter_string|default:'' }}" type="text" name="{{ filter.get_param_name }}" />
|
||||||
<button type="submit" class="btn btn-small filter">Filter</button>
|
<button type="submit" {{ filter.attr_string|safe }}>Filter</button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for action in table_actions %}
|
{% for action in table_actions %}
|
||||||
{% if action != filter %}
|
{% if action != filter %}
|
||||||
{% if action.method != "GET" %}
|
{% if action.method != "GET" %}
|
||||||
<button class='btn btn-small {{ action.classes|join:" " }}' name="action" value="{{ action.get_param_name }}" type="submit">{% if action.handles_multiple %}{{ action.verbose_name_plural }}{% else %}{{ action.verbose_name }}{% endif %}</button>
|
<button {{ action.attr_string|safe }} name="action" value="{{ action.get_param_name }}" type="submit">{% if action.handles_multiple %}{{ action.verbose_name_plural }}{% else %}{{ action.verbose_name }}{% endif %}</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href='{{ action.get_link_url }}' {{ action.attr_string|safe }}>{{ action.verbose_name }}</a>
|
<a href='{{ action.get_link_url }}' {{ action.attr_string|safe }}>{{ action.verbose_name }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -8,6 +8,7 @@ from horizon.templatetags.sizeformat import mbformat
|
|||||||
class CSVSummary(tables.LinkAction):
|
class CSVSummary(tables.LinkAction):
|
||||||
name = "csv_summary"
|
name = "csv_summary"
|
||||||
verbose_name = _("Download CSV Summary")
|
verbose_name = _("Download CSV Summary")
|
||||||
|
classes = ("btn-download",)
|
||||||
|
|
||||||
def get_link_url(self, usage=None):
|
def get_link_url(self, usage=None):
|
||||||
return self.table.kwargs['usage'].csv_link()
|
return self.table.kwargs['usage'].csv_link()
|
||||||
|
@ -16,13 +16,17 @@ class HTMLElement(object):
|
|||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def get_default_attrs(self):
|
||||||
|
return {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attr_string(self):
|
def attr_string(self):
|
||||||
"""
|
"""
|
||||||
Returns a flattened string of HTML attributes based on the
|
Returns a flattened string of HTML attributes based on the
|
||||||
``attrs`` dict provided to the class.
|
``attrs`` dict provided to the class.
|
||||||
"""
|
"""
|
||||||
final_attrs = copy.copy(self.attrs)
|
final_attrs = copy.copy(self.get_default_attrs())
|
||||||
|
final_attrs.update(self.attrs)
|
||||||
# Handle css class concatenation
|
# Handle css class concatenation
|
||||||
default = " ".join(self.get_default_classes())
|
default = " ".join(self.get_default_classes())
|
||||||
defined = self.attrs.get('class', '')
|
defined = self.attrs.get('class', '')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user