def GET(self, *args, **kwargs):
return self.parent.root_with_msg()
- def _get_enabled_list(self):
- cur = list()
- for p in self._site[self.facility].available.values():
- if p.is_enabled:
- cur.append(p.name)
- return cur
-
@admin_protect
def POST(self, *args, **kwargs):
message = "Nothing was modified."
message_type = "info"
- cur_enabled = self._get_enabled_list()
+ changed = None
+ cur_enabled = self._site[self.facility].enabled
if 'order' in kwargs:
order = kwargs['order'].split(',')
message = "New configuration saved."
message_type = ADMIN_STATUS_OK
+ changed = dict()
+ self.debug('%s -> %s' % (cur_enabled, new_order))
+ for i in range(0, len(cur_enabled)):
+ if cur_enabled[i] != new_order[i]:
+ changed[cur_enabled[i]] = 'reordered'
+
except ValueError, e:
message = str(e)
message_type = ADMIN_STATUS_ERROR
message_type = ADMIN_STATUS_ERROR
return self.parent.root_with_msg(message=message,
- message_type=message_type)
+ message_type=message_type,
+ changed=changed)
class AdminPlugins(AdminPage):
def save_enabled_plugins(self, names):
self._site[self.facility].save_enabled(names)
- def root_with_msg(self, message=None, message_type=None):
+ def root_with_msg(self, message=None, message_type=None, changed=None):
plugins = self._site[self.facility]
+ if changed is None:
+ changed = dict()
+
targs = {'title': self.title,
'menu': self._master.menu,
'message': message,
'message_type': message_type,
'available': plugins.available,
'enabled': plugins.enabled,
+ 'changed': changed,
'baseurl': self.url,
'newurl': self.url}
if self.order:
obj.enable()
obj.save_enabled_state()
msg = "Plugin %s enabled" % obj.name
- return self.root_with_msg(msg, ADMIN_STATUS_OK)
+ return self.root_with_msg(msg, ADMIN_STATUS_OK,
+ changed={obj.name: 'enabled'})
enable.public_function = True
@admin_protect
obj.disable()
obj.save_enabled_state()
msg = "Plugin %s disabled" % obj.name
- return self.root_with_msg(msg, ADMIN_STATUS_OK)
+ return self.root_with_msg(msg, ADMIN_STATUS_OK,
+ changed={obj.name: 'disabled'})
disable.public_function = True
// Open Sans Fonts
@import "font.less";
+// Admin Interface styles
+@import "admin/variables.less";
+@import "admin/widgets.less";
+
+
// remove warnings
@fa-var-angle-right: ">";
@fa-var-angle-down: "\f107";
-
-// bigger default font
-@font-size-base: 14px;
--- /dev/null
+// Copyright (C) 2014 Ipsilon project Contributors, for licensee see COPYING
+
+// Basic variables
+@state-enabled-bg: #ffffff;
+@state-disabled-bg: #ededed;
+
+// bigger default font
+@font-size-base: 14px;
+
--- /dev/null
+// Copyright (C) 2014 Ipsilon project Contributors, for licensee see COPYING
+
+// Widgets
+
+// imitate tables
+.ipsilon-row {
+
+ // reuse bootstrap colors
+ border-top: 1px solid @table-border-color;
+ padding: @table-cell-padding;
+
+ // to have equal height - basically a hack, increase if default elements are
+ // larger. Proper equal height would have to be done in JavaScript.
+ min-height: @input-height-large;
+}
+
+
+.ipsilon-row:last-child {
+ border-bottom: 1px solid @table-border-color;
+}
+
+// add to div with 'ipsilon-row' class to change background
+.hl-enabled {
+ // ugly color
+ background-color: @state-enabled-bg;
+}
+
+.hl-disabled {
+ background-color: @state-disabled-bg;
+
+ strong {
+ color: #555;
+ }
+}
+
+// animation
+// https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations
+
+@keyframes bgfadein {
+ from {
+ background-color: @state-disabled-bg;
+ }
+ to {
+ background-color: @state-enabled-bg;
+ }
+}
+
+@keyframes bgfadeout {
+ from {
+ background-color: @state-enabled-bg;
+ }
+ to {
+ background-color: @state-disabled-bg;
+ }
+}
+
+// add these classes to rows to hightlight them on load
+.hl-enabled-new {
+ animation-duration: 2s;
+ animation-name: bgfadein;
+ animation-fill-mode: both
+}
+
+.hl-disabled-new {
+ animation-duration: 2s;
+ animation-name: bgfadeout;
+ animation-fill-mode: both
+}
+
+@keyframes flashout {
+ 0% {
+ background-color: @state-enabled-bg;
+ }
+ 50% {
+ background-color: @state-info-bg;
+ }
+ 100% {
+ background-color: @state-enabled-bg;
+ }
+}
+
+.hl-enabled-flash {
+ animation-duration: 1s;
+ animation-name: flashout;
+ animation-fill-mode: both
+}
</div>
</div>
- <table class="table">
{% for p in enabled %}
- <tr><td>
- <div class="row">
+ {% set highlight = "hl-enabled" %}
+ {% if p in changed %}
+ {% if changed[p] == 'enabled' %}
+ {% set highlight = "hl-enabled-new" %}
+ {% elif changed[p] == 'reordered' %}
+ {% set highlight = "hl-enabled-flash" %}
+ {% endif %}
+ {% endif %}
+ <div class="row ipsilon-row {{ highlight }}">
<div class="col-md-3 col-sm-3 col-xs-5">
- <strong>{{ p }}</strong>
+ <p><strong>{{ p }}</strong></p>
</div>
<div class="col-md-7 col-sm-7 col-xs-5">
<div class="row">
<div class="col-md-6 col-sm-6 col-xs-12">
- <a class="text-info" href="{{ baseurl }}/disable/{{ p }}">Disable</a>
+ <p class="text-info"><a href="{{ baseurl }}/disable/{{ p }}">Disable</a></p>
</div>
<div class="col-md-6 col-sm-6 col-xs-12">
{%- if available[p].get_config_obj() %}
- <a class="text-primary" href="{{ baseurl }}/{{ p }}">Configure</a>
+ <p class="text-primary"><a href="{{ baseurl }}/{{ p }}">Configure</a></p>
{% endif %}
</div>
</div>
{%- endif %}
</div>
</div>
- </td></tr>
{% endfor %}
{% for p in available if not p in enabled %}
- <tr><td>
- <div class="row">
+ {% set highlight = "hl-disabled" %}
+ {% if p in changed %}
+ {% if changed[p] == 'disabled' %}
+ {% set highlight = "hl-disabled-new" %}
+ {% endif %}
+ {% endif %}
+ <div class="row ipsilon-row {{ highlight }}">
<div class="col-md-3 col-sm-3 col-xs-5">
<strong>{{ p }}</strong>
</div>
<div class="col-md-2 col-sm-2 col-xs-1">
</div>
</div>
- </td></tr>
{% endfor %}
- <tr><td>
- </td></tr>
- </table>
-
{% endif %}
{% endblock %}
</div>
</div>
- <hr>
-
- {% for p in enabled %}
- <div class="row">
+ {% for p in available %}
+ {%- if p in enabled %}
+ {%- set highlight = "hl-enabled" %}
+ {%- set actpath = "disable" %}
+ {%- set actlabel = "Disable" %}
+ {%- if p in changed %}
+ {%- if changed[p] == 'enabled' %}
+ {%- set highlight = "hl-enabled-new" %}
+ {%- endif %}
+ {%- endif %}
+ {%- else %}
+ {%- set highlight = "hl-disabled" %}
+ {%- set actpath = "enable" %}
+ {%- set actlabel = "Enable" %}
+ {%- if p in changed %}
+ {%- if changed[p] == 'disabled' %}
+ {%- set highlight = "hl-disabled-new" %}
+ {%- endif %}
+ {%- endif %}
+ {%- endif %}
+ <div class="row ipsilon-row {{ highlight }}">
<div class="col-md-3 col-sm-3 col-xs-6">
<p><strong>{{ p }}</strong></p>
</div>
<div class="col-md-9 col-sm-9 col-xs-6">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-12">
- <p class="text-info"><a href="{{ baseurl }}/disable/{{ p }}">Disable</a></p>
+ <p class="text-info"><a href="{{ baseurl }}/{{ actpath }}/{{ p }}">{{ actlabel }}</a></p>
</div>
<div class="col-md-4 col-sm-4 col-xs-12">
{%- if available[p].get_config_obj() %}
+ {%- if p in enabled %}
<p class="text-primary"><a href="{{ baseurl }}/{{ p }}">Configure</a></p>
- {% endif %}
- </div>
- <div class="col-md-4 col-sm-4 col-xs-12">
- {%- if available[p].admin %}
- <p class="text-primary"><a href="{{ baseurl }}/{{ p }}/admin">Manage</a></p>
- {% endif %}
- </div>
- </div>
- </div>
- </div>
- <hr>
- {% endfor %}
-
- {% for p in available if not p in enabled %}
- <div class="row">
- <div class="col-md-3 col-sm-3 col-xs-6">
- <p><strong>{{ p }}</strong></p>
- </div>
- <div class="col-md-9 col-sm-9 col-xs-6">
- <div class="row">
- <div class="col-md-4 col-sm-4 col-xs-12">
- <p class="text-info"><a href="{{ baseurl }}/enable/{{ p }}">Enable</a></p>
- </div>
- <div class="col-md-4 col-sm-4 col-xs-12">
- {%- if available[p].get_config_obj() %}
+ {%- else %}
<p class="text-muted">Configure</p>
- {% endif %}
+ {%- endif %}
+ {%- endif %}
</div>
<div class="col-md-4 col-sm-4 col-xs-12">
{%- if available[p].admin %}
+ {%- if p in enabled %}
+ <p class="text-primary"><a href="{{ baseurl }}/{{ p }}/admin">Manage</a></p>
+ {%- else %}
<p class="text-muted">Manage</p>
+ {%- endif %}
{% endif %}
</div>
</div>
</div>
</div>
- <hr>
{% endfor %}
{% endif %}
font-weight: 900;
src: local('Open Sans Extrabold Italic'), url('../fonts/open-sans/OpenSans-ExtraBoldItalic.ttf') format('truetype');
}
+.ipsilon-row {
+ border-top: 1px solid #dddddd;
+ padding: 8px;
+ min-height: 37px;
+}
+.ipsilon-row:last-child {
+ border-bottom: 1px solid #dddddd;
+}
+.hl-enabled {
+ background-color: #ffffff;
+}
+.hl-disabled {
+ background-color: #ededed;
+}
+.hl-disabled strong {
+ color: #555;
+}
+@keyframes bgfadein {
+ from {
+ background-color: #ededed;
+ }
+ to {
+ background-color: #ffffff;
+ }
+}
+@keyframes bgfadeout {
+ from {
+ background-color: #ffffff;
+ }
+ to {
+ background-color: #ededed;
+ }
+}
+.hl-enabled-new {
+ animation-duration: 3s;
+ animation-name: bgfadein;
+ animation-fill-mode: both;
+}
+.hl-disabled-new {
+ animation-duration: 3s;
+ animation-name: bgfadeout;
+ animation-fill-mode: both;
+}
+@keyframes flashout {
+ 0% {
+ background-color: #ffffff;
+ }
+ 50% {
+ background-color: #d9edf7;
+ }
+ 100% {
+ background-color: #ffffff;
+ }
+}
+.hl-enabled-flash {
+ animation-duration: 1.5s;
+ animation-name: flashout;
+ animation-fill-mode: both;
+}