setup for basic openstack dashing

setup client handling for multiple services and regions
shows cpu and ram totals across all given regions,
shows cpu and ram per region
can connect and show nagios status
This commit is contained in:
adriant 2014-12-11 16:47:54 +13:00
parent bd9532d5ea
commit 493a398901
15 changed files with 518 additions and 114 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@ -49,7 +49,8 @@
.widget.widget-progress-bars .outer-progress-bar .inner-progress-bar {
background-color: #2391ab;
border-radius: 0.35em;
color: #ffffff; }
color: #ffffff;
white-space: pre; }
.widget.widget-progress-bars .zebra-stripe {
background-color: #57c3dd; }
@ -87,18 +88,12 @@
.hotness4 {
background-color: #FF003C; }
.widget-image {
background-color: #4b4b4b; }
.widget-image {
background-color: #FFFFFF; }
.widget-clock {
background-color: #666666; }
.widget-clock {
background-color: #dc5945; }
.widget-meter {
background-color: #9c4274; }
.widget-meter input.meter {
@ -111,6 +106,39 @@
.widget-meter .updated-at {
color: rgba(0, 0, 0, 0.3); }
.widget-nagios li {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding-top: 25px; }
.widget-nagios li h3 {
font-size: 60px;
font-weight: bold; }
.widget-nagios li h4 {
font-size: 20px;
font-weight: bold;
text-transform: uppercase; }
p .widget-nagios li.updated-at {
font-size: 10px; }
.widget-nagios li.green {
background-color: #86d751; }
.widget-nagios li.green p.updated-at {
color: #c0eaa4; }
.widget-nagios li.yellow {
background-color: #edde43; }
.widget-nagios li.yellow p.updated-at {
color: #f6eea0; }
.widget-nagios li.red {
background-color: #e3394f; }
.widget-nagios li.red p.updated-at {
color: #f0929e; }
.widget-nagios li.error {
background-color: #f75f00; }
.widget-nagios li.error p.updated-at {
color: #ff9c5e; }
.widget-usage-gauge {
background-color: #ec223f; }
.widget-usage-gauge .title {

24
pydashie/conf.yaml Normal file
View File

@ -0,0 +1,24 @@
main:
log_file: pydashie.log
openstack:
regions:
- 'region1'
allocation:
region1:
vcpus_allocation_ratio: 2.0
ram_allocation_ratio: 1.0
# remove this amount per node available metric
reserved_ram_per_node: 0
reserved_vcpus_per_node: 0
auth:
auth_url: 'http://localhost:5000/v2.0'
username: 'admin'
password: 'openstack'
project_name: 'demo'
insecure: True
nagios:
services:
region1:
statfile: './region1-status.dat'
host: 'region1-mon0'
username: 'admin'

View File

@ -1,12 +1,19 @@
import datetime
import json
from math import ceil
from repeated_timer import RepeatedTimer
from novaclient.v1_1 import client as novaclient
from cinderclient.v1 import client as cinderclient
from keystoneclient.v2_0 import client as keystoneclient
class DashieSampler(object):
def __init__(self, app, interval):
def __init__(self, app, interval, conf=None):
self._app = app
self._os_clients = {}
self._conf = conf
self._timer = RepeatedTimer(interval, self._sample)
def stop(self):
@ -26,7 +33,8 @@ class DashieSampler(object):
def _send_event(self, widget_id, body):
body['id'] = widget_id
body['updatedAt'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S +0000')
body['updatedAt'] = (datetime.datetime.now().
strftime('%Y-%m-%d %H:%M:%S +0000'))
formatted_json = 'data: %s\n\n' % (json.dumps(body))
self._app.last_events[widget_id] = formatted_json
for event_queue in self._app.events_queue.values():
@ -36,3 +44,48 @@ class DashieSampler(object):
data = self.sample()
if data:
self._send_event(self.name(), data)
def _convert(self, num):
if num >= 1024 ** 3:
return int(ceil(num / (1024 ** 3))), 'GB'
elif num >= 1024 ** 2:
return int(ceil(num / (1024 ** 2))), 'MB'
elif num >= 1024:
return int(ceil(num / (1024))), 'KB'
else:
return num, 'B'
def _client(self, service, region):
if not self._os_clients.get(region):
self._os_clients[region] = {}
if not self._os_clients[region].get(service):
if service == 'compute':
client = novaclient.Client(
self._conf['auth']['username'],
self._conf['auth']['password'],
self._conf['auth']['project_name'],
self._conf['auth']['auth_url'],
region_name=region,
insecure=self._conf['auth']['insecure'])
self._os_clients[region][service] = client
elif service == 'storage':
client = cinderclient.Client(
self._conf['auth']['username'],
self._conf['auth']['password'],
self._conf['auth']['project_name'],
self._conf['auth']['auth_url'],
region_name=region,
insecure=self._conf['auth']['insecure'])
self._os_clients[region][service] = client
elif service == 'identity':
client = keystoneclient.Client(
username=self._conf['auth']['username'],
password=self._conf['auth']['password'],
project_name=self._conf['auth']['project_name'],
auth_url=self._conf['auth']['auth_url'],
region_name=region,
insecure=self._conf['auth']['insecure'])
self._os_clients[region][service] = client
return self._os_clients[region][service]

View File

@ -1,27 +1,31 @@
from example_samplers import (
SynergySampler,
HotnessSampler,
CPUSampler,
RAMSampler,
RegionsRAMSampler,
RegionsCPUSampler,
NagiosSampler,
BuzzwordsSampler,
ConvergenceSampler,
ProgressBarsSampler,
UsageGaugeSampler,
)
def run(app, xyzzy):
def run(args, conf, app, xyzzy):
samplers = [
SynergySampler(xyzzy, 3),
HotnessSampler(xyzzy, 3),
BuzzwordsSampler(xyzzy, 2), # 10
ConvergenceSampler(xyzzy, 1),
ProgressBarsSampler(xyzzy, 5),
UsageGaugeSampler(xyzzy, 3),
CPUSampler(xyzzy, 10, conf['openstack']),
RAMSampler(xyzzy, 10, conf['openstack']),
RegionsCPUSampler(xyzzy, 10, conf['openstack']),
RegionsRAMSampler(xyzzy, 10, conf['openstack']),
NagiosSampler(xyzzy, 10, conf['nagios']),
# BuzzwordsSampler(xyzzy, 2),
# ConvergenceSampler(xyzzy, 1),
]
try:
app.run(debug=True,
host='0.0.0.0',
port=5000,
host=args.ip,
port=args.port,
threaded=True,
use_reloader=False,
use_debugger=True

View File

@ -1,21 +1,39 @@
import collections
import random
import nagios
from dashie_sampler import DashieSampler
class SynergySampler(DashieSampler):
class CPUSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(SynergySampler, self).__init__(*args, **kwargs)
super(CPUSampler, self).__init__(*args, **kwargs)
self._last = 0
def name(self):
return 'synergy'
return 'cpu'
def sample(self):
max_cpu = 0
cur_cpu = 0
for region in self._conf['regions']:
nova = self._client('compute', region)
stats = nova.hypervisors.statistics()
hypervisors = nova.hypervisors.list()
reserved = 0
for hypervisor in hypervisors:
reserved = reserved + self._conf['allocation'][region]['reserved_vcpus_per_node']
cpu_ratio = self._conf['allocation'][region]['vcpus_allocation_ratio']
max_cpu = max_cpu + (stats.vcpus * cpu_ratio) - reserved
cur_cpu = cur_cpu + stats.vcpus_used
s = {'min': 0,
'max': 100,
'value': random.randint(0, 100),
'max': max_cpu,
'value': cur_cpu,
'last': self._last}
s['moreinfo'] = "%s/%s" % (s['value'], s['max'])
s['current'] = s['value']
@ -23,19 +41,143 @@ class SynergySampler(DashieSampler):
return s
class HotnessSampler(DashieSampler):
class RAMSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(HotnessSampler, self).__init__(*args, **kwargs)
super(RAMSampler, self).__init__(*args, **kwargs)
self._last = 0
def name(self):
return 'hotness'
return 'ram'
def sample(self):
s = {'value': random.randint(0, 100),
'current': random.randint(0, 100),
max_ram = 0
cur_ram = 0
for region in self._conf['regions']:
nova = self._client('compute', region)
stats = nova.hypervisors.statistics()
hypervisors = nova.hypervisors.list()
reserved = 0
for hypervisor in hypervisors:
reserved = reserved + self._conf['allocation'][region]['reserved_ram_per_node']
ram_ratio = self._conf['allocation'][region]['ram_allocation_ratio']
max_ram = max_ram + (stats.memory_mb * ram_ratio * 1024 * 1024) - reserved
cur_ram = cur_ram + stats.memory_mb_used * 1024 * 1024
ram_converted = self._convert(max_ram)
ram_converted_used = self._convert(cur_ram)
s = {'min': 0,
'max': ram_converted[0],
'value': ram_converted_used[0],
'last': self._last}
self._last = s['current']
s['moreinfo'] = "%s%s out of %s%s" % (ram_converted_used[0],
ram_converted_used[1],
ram_converted[0],
ram_converted[1])
s['current'] = s['value']
self._last = s['value']
return s
class RegionsCPUSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(RegionsCPUSampler, self).__init__(*args, **kwargs)
def name(self):
return 'cpu_regions'
def sample(self):
regions = []
for region in self._conf['regions']:
nova = self._client('compute', region)
stats = nova.hypervisors.statistics()
hypervisors = nova.hypervisors.list()
reserved = 0
for hypervisor in hypervisors:
reserved = reserved + self._conf['allocation'][region]['reserved_vcpus_per_node']
cpu_ratio = self._conf['allocation'][region]['vcpus_allocation_ratio']
max_cpu = (stats.vcpus * cpu_ratio) - reserved
cur_cpu = stats.vcpus_used
regions.append({'name': region, 'progress': (cur_cpu * 100.0) / max_cpu,
'max': max_cpu, 'value': cur_cpu})
return {'progress_items': regions}
class RegionsRAMSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(RegionsRAMSampler, self).__init__(*args, **kwargs)
def name(self):
return 'ram_regions'
def sample(self):
regions = []
for region in self._conf['regions']:
nova = self._client('compute', region)
stats = nova.hypervisors.statistics()
hypervisors = nova.hypervisors.list()
reserved = 0
for hypervisor in hypervisors:
reserved = reserved + self._conf['allocation'][region]['reserved_ram_per_node']
ram_ratio = self._conf['allocation'][region]['ram_allocation_ratio']
max_ram = (stats.memory_mb * ram_ratio * 1024 * 1024) - reserved
cur_ram = stats.memory_mb_used * 1024 * 1024
ram_converted = self._convert(max_ram)[0]
ram_converted_used = self._convert(cur_ram)[0]
regions.append({'name': region,
'progress': ((ram_converted_used * 100.0) /
ram_converted),
'max': ram_converted, 'value': ram_converted_used})
return {'progress_items': regions}
class NagiosSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(NagiosSampler, self).__init__(*args, **kwargs)
self._last = 0
def name(self):
return 'nagios'
def sample(self):
nagios.get_statusfiles(self._conf['services'])
servicestatus = nagios.parse_status(self._conf['services'])
criticals = 0
warnings = 0
for region in servicestatus:
criticals = criticals + servicestatus[region]['critical']
warnings = warnings + servicestatus[region]['warning']
status = 'green'
if criticals > 0:
status = 'red'
elif warnings > 0:
status = 'yellow'
s = {'criticals': criticals,
'warnings': warnings,
'status': status}
return s
@ -75,22 +217,6 @@ class ConvergenceSampler(DashieSampler):
return {'points': list(self.items)}
class ProgressBarsSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(ProgressBarsSampler, self).__init__(*args, **kwargs)
def name(self):
return 'progress_bars'
def sample(self):
random_progress = []
for i in range(5):
random_progress.append({'name': "Project %d" % i, 'progress': random.randint(0, 100)})
return {'title': "Progress Bars Title", 'progress_items': random_progress}
class UsageGaugeSampler(DashieSampler):
def __init__(self, *args, **kwargs):
super(UsageGaugeSampler, self).__init__(*args, **kwargs)

View File

@ -1,6 +1,9 @@
import argparse
import logging
import os
import sys
import Queue
import yaml
from flask import (
current_app,
@ -12,8 +15,9 @@ from flask import (
)
app = Flask(__name__)
logging.basicConfig()
log = logging.getLogger(__name__)
# we setup the log in __main__
log = None
@app.route("/")
@ -53,6 +57,7 @@ def javascripts():
'widgets/hotness/hotness.coffee',
'widgets/progress_bars/progress_bars.coffee',
'widgets/usage_gauge/usage_gauge.coffee',
'widgets/nagios/nagios.coffee',
]
nizzle = True
if not nizzle:
@ -173,10 +178,35 @@ def close_stream(*args, **kwargs):
def run_sample_app():
a = argparse.ArgumentParser("Openstack-PyDashboard")
a.add_argument("-c", "--config", dest="config", help="Path to config file",
required=True)
a.add_argument("-i", "--interface", dest="ip",
help="IP address to serve on.", default="0.0.0.0")
a.add_argument("-p", "--port", help="port to serve on", default="6000")
args = a.parse_args()
conf = None
try:
with open(args.config) as f:
conf = yaml.load(f)
except IOError as e:
print "Couldn't load config file: %s" % e
sys.exit(1)
logging.basicConfig(filename=conf['main']['log_file'],
level=logging.INFO,
format='%(asctime)s %(message)s')
global log
log = logging.getLogger(__name__)
import SocketServer
SocketServer.BaseServer.handle_error = close_stream
import example_app
example_app.run(app, xyzzy)
example_app.run(args, conf, app, xyzzy)
if __name__ == "__main__":

44
pydashie/nagios.py Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
# quick checker for nagios status
import paramiko
from pynag.Parsers import status
def get_statusfiles(services):
# ssh to each server in the config, grab the status.dat and put it in
# the location specified in the config
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for region in services.keys():
ssh.connect(services[region]['host'],
username=services[region]['username'])
ftp = ssh.open_sftp()
ftp.get('/var/lib/icinga/status.dat', services[region]['statfile'])
ftp.close()
ssh.close()
def parse_status(services):
# parse the status.dat files listed in the config
# return the status of the servers in a hash
for region in services.keys():
services[region]['warning'] = 0
services[region]['critical'] = 0
services[region]['unknown'] = 0
s = status(services[region]['statfile'])
s.parse()
for service in s.data.get('servicestatus', []):
if (int(service.get('scheduled_downtime_depth', None)) == 0
and int(service.get('problem_has_been_acknowledged',
None)) == 0):
# get all the 'not OK' services
if (int(service.get('current_state', None)) == 1):
services[region]['warning'] += 1
elif (int(service.get('current_state', None)) == 2):
services[region]['critical'] += 1
elif (int(service.get('current_state', None)) == 3):
services[region]['unknown'] += 1
return services

View File

@ -20,51 +20,38 @@
<div id="container">
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="1">
- <div data-id="welcome" data-view="Text" data-title="Hello" data-text="This is your shiny new (python powered) dashboard." data-moreinfo="Protip: You can drag the widgets around!"></div>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
<div data-id="clock" data-view="Clock" data-title="Clock"></div>
</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="1">
<div data-id="hotness" data-view="Hotness" data-title="Hotness" data-cool="40" data-warm="90"></div>
<li data-row="1" data-col="2" data-sizex="1" data-sizey="1">
<div data-id="nagios" data-view="Nagios" data-unordered="true" data-title="Icinga Prod" data-moreinfo="Unacknowledged events"></div>
</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">
<div data-id="clock" data-view="Clock" data-title="Clock"></div>
</li>
<div data-id="cpu" data-view="Meter" data-title="CPU"></div>
</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="1">
<div data-view="Image" data-image="/images/dashie.png"></div>
<div data-id="ram" data-view="Meter" data-title="RAM"></div>
</li>
<li data-row="2" data-col="2" data-sizex="2" data-sizey="1">
<div data-id="progress_bars" data-view="ProgressBars" data-title="Project Bars"></div>
<div data-id="cpu_regions" data-view="ProgressBars" data-title="CPU usage per region"></div>
</li>
<li data-row="2" data-col="4" data-sizex="1" data-sizey="1">
<div data-id="synergy" data-view="Meter" data-title="Synergy"></div>
</li>
<li data-row="2" data-col="5" data-sizex="1" data-sizey="1">
<div data-id="synergy" data-view="Meter" data-title="Synergy"></div>
<li data-row="2" data-col="4" data-sizex="2" data-sizey="1">
<div data-id="ram_regions" data-view="ProgressBars" data-title="RAM usage per region"></div>
</li>
<li data-row="2" data-col="1" data-sizex="1" data-sizey="2">
<div data-id="buzzwords" data-view="List" data-unordered="true" data-title="Buzzwords" data-moreinfo="Absolute ranking of pony preferences"></div>
</li>
<li data-row="3" data-col="2" data-sizex="2" data-sizey="1">
<li data-row="4" data-col="2" data-sizex="2" data-sizey="1">
<div data-id="convergence" data-view="Graph" data-title="Convergence" style="background-color:#ff9618"></div>
</li>
<li data-row="3" data-col="4" data-sizex="1" data-sizey="1">
<div data-id="website_up" data-view="Text" data-title="Website"></div>
</li>
<li data-row="3" data-col="5" data-sizex="1" data-sizey="1">
<!-- <style scoped>.memcached_used_memory .gauge { height: 145px;}</style> -->
<div data-id="usage_gauge" data-view="UsageGauge" style="background-color: #3e3735" data-title="Power !!"></div>
</li>
</ul>
</div>
</body>

View File

@ -0,0 +1,9 @@
class Dashing.Nagios extends Dashing.Widget
ready: ->
# This is fired when the widget is done being rendered
onData: (data) ->
# Handle incoming data
# You can access the html node of this widget with `@node`
# Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in.

View File

@ -0,0 +1,21 @@
<ul>
<li data-bind-class="status">
<h1 class="title" data-bind="title"></h1>
<div data-showif="status | equals 'error'"> <!-- error -->
<h4>Error querying Icinga</h4>
</div> <!-- /no error -->
<div data-hideif="status | equals 'error'"> <!-- no error -->
<div>
<h3 data-bind="criticals"></h3>
<h4 data-showif="criticals | equals 1">critical</h4>
<h4 data-hideif="criticals | equals 1">criticals</h4>
</div>
<div>
<h3 data-bind="warnings"></h3>
<h4 data-showif="warnings | equals 1">warning</h4>
<h4 data-hideif="warnings | equals 1">warnings</h4>
</div>
<p class="updated-at" data-bind="updatedAtMessage"></p>
</div> <!-- /no error -->
</li>
</ul>

View File

@ -0,0 +1,72 @@
$background: #444;
$text: #fff;
$success: #86d751;
$warning: #edde43;
$failure: #e3394f;
$error: #f75f00;
.widget-nagios {
li {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding-top: 25px;
h3 {
font-size: 60px;
font-weight: bold;
}
h4 {
font-size: 20px;
font-weight: bold;
text-transform: uppercase;
}
p &.updated-at {
font-size: 10px;
}
&.green {
background-color: $success;
p {
&.updated-at {
color: lighten($success, 20%);
}
}
}
&.yellow {
background-color: $warning;
p {
&.updated-at {
color: lighten($warning, 20%);
}
}
}
&.red {
background-color: $failure;
p {
&.updated-at {
color: lighten($failure, 20%);
}
}
}
&.error {
background-color: $error;
p {
&.updated-at {
color: lighten($error, 20%);
}
}
}
}
}

View File

@ -1,17 +1,17 @@
class Dashing.ProgressBars extends Dashing.Widget
@accessor 'title'
ready: ->
@drawWidget( @get('progress_items') )
onData: (eventData) ->
@drawWidget(eventData.progress_items)
drawWidget: (progress_items) ->
container = $(@node)
rowsContainer = container.find('.rows-container')
if progress_items.length == 0
rowsContainer.empty()
else
@ -19,13 +19,13 @@ class Dashing.ProgressBars extends Dashing.Widget
rowHeight = 100 / progress_items.length
counter = 0
@clearIntervals()
# Add or move rows for each project. Checks first if the row already exists.
progress_items.forEach (item) =>
normalizedItemName = item.name.replace(/\W+/g, "_")
referenceRow = rowsContainer.children().eq(counter)
existingRow = rowsContainer.find("."+normalizedItemName)
if existingRow.length
if referenceRow.attr("class").indexOf(normalizedItemName) == -1
existingRow.detach().insertBefore(referenceRow)
@ -37,28 +37,29 @@ class Dashing.ProgressBars extends Dashing.Widget
else
rowsContainer.append(row)
row.hide().fadeIn(1200)
elem = rowsContainer.find("."+normalizedItemName+" .inner-progress-bar")
if elem.length
@animateProgressBarContent(elem[0], parseFloat(elem[0].style.width),
parseFloat(item.progress), 1000)
parseFloat(item.progress), parseFloat(item.value),
parseFloat(item.max), 1000)
++counter
# Remove any nodes that were not in the new data, these will be the rows
# at the end of the widget.
currentNode = rowsContainer.children().eq(counter-1)
while currentNode.next().length
currentNode = currentNode.next()
currentNode.fadeOut(100, -> $(this).remove() )
# Set the height after rows were added/removed.
rows = rowsContainer.children()
percentageOfTotalHeight = 100 / progress_items.length
applyCorrectedRowHeight(rows, percentageOfTotalHeight)
applyZebraStriping(rows)
#***/
# Create a JQuery row object with the proper structure and base
# settings for the item passed in.
@ -73,35 +74,35 @@ class Dashing.ProgressBars extends Dashing.Widget
# @item - object representing an item and it's progress
# /
createRow = (item) ->
row = ( $("<div/>")
.attr("class", "row " + item.name.replace(/\W+/g, "_") ) )
rowContent = ( $("<div/>")
.attr("class", "row-content") )
projectName = ( $("<div/>")
.attr("class", "project-name")
.text(item.name)
.attr("title", item.name) )
outerProgressBar = ( $("<div/>")
.attr("class", "outer-progress-bar") )
innerProgressBar = $("<div/>")
.attr("class", "inner-progress-bar")
.text("0%")
innerProgressBar.css("width", "0%")
# Put it all together.
outerProgressBar.append(innerProgressBar)
rowContent.append(projectName)
rowContent.append(outerProgressBar)
row.append(rowContent)
return row
#***/
# Does calculations for the animation and sets up the javascript
# interval to perform the animation.
@ -109,20 +110,22 @@ class Dashing.ProgressBars extends Dashing.Widget
# @element - element that is going to be animated.
# @from - the value that the element starts at.
# @to - the value that the element is going to.
# @value - the actual value (not percentage) to display.
# @max - the max value (used for percentage).
# @baseDuration - the minimum time the animation will perform.
# /
animateProgressBarContent: (element, from, to, baseDuration) ->
animateProgressBarContent: (element, from, to, value, max, baseDuration) ->
endpointDifference = (to-from)
if endpointDifference != 0
currentValue = from
# Every x milliseconds, the function should run.
stepInterval = 16.667
# Change the duration based on the distance between points.
duration = baseDuration + Math.abs(endpointDifference) * 25
numberOfSteps = duration / stepInterval
valueIncrement = endpointDifference / numberOfSteps
@ -130,29 +133,31 @@ class Dashing.ProgressBars extends Dashing.Widget
->
currentValue += valueIncrement
if Math.abs(currentValue - from) >= Math.abs(endpointDifference)
setProgressBarValue(element, to)
setProgressBarValue(element, to, value, max)
clearInterval(interval)
else
setProgressBarValue(element, currentValue)
setProgressBarValue(element, currentValue, value, max)
stepInterval)
@addInterval(interval)
#***/
# Sets the text and width of the element in question to the specified value
# after making sure it is bounded between [0-100]
#
# @element - element to be set
# @value - the numeric value to set the element to. This can be a float.
# @literal - the actual value (not in percentage).
# @max - the max value (which was used for percentage).
# /
setProgressBarValue = (element, value) ->
setProgressBarValue = (element, value, literal, max) ->
if (value > 100)
value = 100
else if (value < 0)
value = 0
element.textContent = Math.floor(value) + "%"
element.textContent = Math.floor(value) + "% - " + Math.floor(literal) + "/" + Math.floor(max) + ""
element.style.width = value + "%"
#***/
# Applies a percentage-based row height to the list of rows passed in.
#
@ -163,7 +168,7 @@ class Dashing.ProgressBars extends Dashing.Widget
height = percentageOfTotalHeight + "%"
for row in rows
row.style.height = height
#***/
# Adds a class to every other row to change the background color. This
# was done mainly for readability.
@ -178,7 +183,7 @@ class Dashing.ProgressBars extends Dashing.Widget
if isZebraStripe
row.classList.add("zebra-stripe")
isZebraStripe = !isZebraStripe
#***/
# Stops all javascript intervals from running and clears the list.
#/
@ -187,7 +192,7 @@ class Dashing.ProgressBars extends Dashing.Widget
for interval in @intervalList
clearInterval(interval)
@intervalList = []
#***/
# Adds a javascript interval to a list so that it can be tracked and cleared
# ahead of time if the need arises.
@ -197,4 +202,4 @@ class Dashing.ProgressBars extends Dashing.Widget
addInterval: (interval) ->
if !@intervalList
@intervalList = []
@intervalList.push(interval)
@intervalList.push(interval)

View File

@ -87,6 +87,7 @@ $text-color: $base-color-lightest;
background-color: $base-color-dark;
border-radius: $row-size / 2;
color: $white;
white-space: pre;
}
}