diff options
author | Joey Hagedorn <hagedorn@mcs.anl.gov> | 2006-06-15 15:43:07 +0000 |
---|---|---|
committer | Joey Hagedorn <hagedorn@mcs.anl.gov> | 2006-06-15 15:43:07 +0000 |
commit | 14724835e271422f196d97b9a5a65346fbb02e94 (patch) | |
tree | df94850b8c8e95df1a3e57e7586638e44df353e7 /reports | |
parent | 93fa7685dd976606273fc286a5f9988a1308cc85 (diff) | |
download | bcfg2-14724835e271422f196d97b9a5a65346fbb02e94.tar.gz bcfg2-14724835e271422f196d97b9a5a65346fbb02e94.tar.bz2 bcfg2-14724835e271422f196d97b9a5a65346fbb02e94.zip |
Initial commit of Django based reporting subsystem. Only works with fake data so far...
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1883 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'reports')
34 files changed, 1215 insertions, 0 deletions
diff --git a/reports/brpt/__init__.py b/reports/brpt/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/reports/brpt/__init__.py diff --git a/reports/brpt/__init__.pyc b/reports/brpt/__init__.pyc Binary files differnew file mode 100644 index 000000000..57e9107ae --- /dev/null +++ b/reports/brpt/__init__.pyc diff --git a/reports/brpt/manage.py b/reports/brpt/manage.py new file mode 100755 index 000000000..5e78ea979 --- /dev/null +++ b/reports/brpt/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +try: + import settings # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) + sys.exit(1) + +if __name__ == "__main__": + execute_manager(settings) diff --git a/reports/brpt/reports/__init__.py b/reports/brpt/reports/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/reports/brpt/reports/__init__.py diff --git a/reports/brpt/reports/__init__.pyc b/reports/brpt/reports/__init__.pyc Binary files differnew file mode 100644 index 000000000..1d697e5f3 --- /dev/null +++ b/reports/brpt/reports/__init__.pyc diff --git a/reports/brpt/reports/models.py b/reports/brpt/reports/models.py new file mode 100644 index 000000000..ac3506214 --- /dev/null +++ b/reports/brpt/reports/models.py @@ -0,0 +1,128 @@ +from django.db import models +#from timedelta import timedelta +from datetime import datetime, timedelta +# Create your models here. +KIND_CHOICES = ( + ('ConfigFile', 'ConfigFile'), + ('Package', 'Package'), + ('Service', 'Service'), + ('SymLink', 'SymLink'), + ('Directory', 'Directory'), + ('Permissions','Permissions'), +) + +class Client(models.Model): + #This exists for clients that are no longer in the repository even! (timeless) + creation = models.DateTimeField() + name = models.CharField(maxlength=128) + def __str__(self): + return self.name + + class Admin: + pass + + +class Metadata(models.Model): + client = models.ForeignKey(Client) + timestamp = models.DateTimeField() + #INSERT magic interface to Metadata HERE + def __str__(self): + return self.timestamp + +class Repository(models.Model): + timestamp = models.DateTimeField() + #INSERT magic interface to any other config info here... + def __str__(self): + return self.timestamp + + +#models each client-interaction +class Interaction(models.Model): + client = models.ForeignKey(Client, related_name="interactions", core=True) + timestamp = models.DateTimeField()#Timestamp for this record + state = models.CharField(maxlength=32)#good/bad/modified/etc + repo_revision = models.IntegerField()#you got it. the repo in use at time of client interaction + client_version = models.CharField(maxlength=32)#really simple; version of client running + pingable = models.BooleanField()#This is (was-pingable)status as of last attempted interaction + goodcount = models.IntegerField()#of good config-items we store this number, because we don't count the + totalcount = models.IntegerField()#of total config-items specified--grab this from metadata instead? + + def __str__(self): + return "With " + self.client.name + " @ " + self.timestamp.isoformat() + + def percentgood(self): + return (self.goodcount/self.totalcount)*100 + + def percentbad(self): + return (self.totalcount-self.goodcount)/(self.totalcount) + + def isclean(self): + if (self.bad_items.count() == 0 and self.extra_items.count() == 0 and self.goodcount == self.totalcount): + #if (self.state == "good"): + return True + else: + return False + + def isstale(self): + if (self == self.client.interactions.order_by('-timestamp')[0]):#Is Mostrecent + if(datetime.now()-self.timestamp > timedelta(hours=25) ): + return True + else: + return False + else: + #Search for subsequent Interaction for this client + #Check if it happened more than 25 hrs ago. + if (self.client.interactions.filter(timestamp__gt=self.timestamp) + .order_by('timestamp')[0].timestamp - self.timestamp > timedelta(hours=25)): + return True + else: + return False + + + class Admin: + list_display = ('client', 'timestamp', 'state') + list_filter = ['client', 'timestamp'] + pass + + + + +class Modified(models.Model): + interaction = models.ForeignKey(Interaction, related_name="modified_items", edit_inline=models.STACKED) + name = models.CharField(maxlength=128, core=True)#name of modified thing. + kind = models.CharField(maxlength=16, choices=KIND_CHOICES)#Service/Package/ConfgFile... + how = models.CharField(maxlength=256) + def __str__(self): + return self.name + + + +class Extra(models.Model): + interaction = models.ForeignKey(Interaction, related_name="extra_items", edit_inline=models.STACKED) + name = models.CharField(maxlength=128, core=True)#name of Extra thing. + kind = models.CharField(maxlength=16, choices=KIND_CHOICES)#Service/Package/ConfgFile... + why = models.CharField(maxlength=256)#current state of some thing... + def __str__(self): + return self.name + + + +class Bad(models.Model): + interaction = models.ForeignKey(Interaction, related_name="bad_items", edit_inline=models.STACKED) + name = models.CharField(maxlength=128, core=True)#name of bad thing. + kind = models.CharField(maxlength=16, choices=KIND_CHOICES)#Service/Package/ConfgFile... + reason = models.CharField(maxlength=256)#that its bad... + def __str__(self): + return self.name + + +#performance metrics, models a performance-metric-item +class Performance(models.Model): + interaction = models.ForeignKey(Interaction, related_name="performance_items", edit_inline=models.STACKED) + metric = models.CharField(maxlength=128, core=True) + value = models.FloatField(max_digits=32, decimal_places=16) + def __str__(self): + return self.metric + + + diff --git a/reports/brpt/reports/models.pyc b/reports/brpt/reports/models.pyc Binary files differnew file mode 100644 index 000000000..5d2c3cd75 --- /dev/null +++ b/reports/brpt/reports/models.pyc diff --git a/reports/brpt/reports/templates/base.html b/reports/brpt/reports/templates/base.html new file mode 100644 index 000000000..db242864e --- /dev/null +++ b/reports/brpt/reports/templates/base.html @@ -0,0 +1,46 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>{% block title %}Bcfg2 Reporting System{% endblock %}</title> + <link rel="stylesheet" type="text/css" href="/site_media/boxypastel.css" /> + <link rel="stylesheet" type="text/css" href="/site_media/base.css" /> + <script type="text/javascript" src="/site_media/main.js"> + </script> + {% block extra_header_info %}{% endblock %} +</head> + +<body> + <div id="header"> + <div id="branding"> + <h1>Bcfg2 Reporting System</h1> + </div> + <div id="user-tools">...Reporting into the future...</div> + </div> + <div id="sidebar"> + {% block sidebar %} + <ul class="sidebar"> + <li><a href="/" class="sidebar">Home</a></li> + <li><a href="/clients/" class="sidebar">Clients</a></li> + <li> + <a href="/displays/" class="sidebar">Displays</a> + <ul class="sidebar-level2"> + <li><a href="/displays/sys-view/" class="sidebar">System</a></li> + <li><a href="/displays/summary/" class="sidebar">Summary</a></li> + <li><a href="/displays/timing/" class="sidebar">Timing</a></li> + </ul> + </li> + </ul> + {% endblock %} + </div> + + <div id="content-main"> + <div id="container"> + {% block pagebanner %}{% endblock %} + {% block content %}{% endblock %} + + <br /><br /><p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p> + </div> + </div> +</body> +</html>
\ No newline at end of file diff --git a/reports/brpt/reports/templates/clients/client-nodebox.html b/reports/brpt/reports/templates/clients/client-nodebox.html new file mode 100644 index 000000000..12b53d899 --- /dev/null +++ b/reports/brpt/reports/templates/clients/client-nodebox.html @@ -0,0 +1,62 @@ +{% if client %} + <a name="{{client.name}}"></a> + <div class="nodebox" name="{{client.name}}"> + <span class="notebox">Time Ran: {{interaction.timestamp}}</span> + <span class="configbox">(-Insert Profile Name Here-)</span> + + <table class="invisitable"> + <tr><td width="43%"><h2>Node: <span class="nodename"> + <a href="/clients/{{client.name}}/{{interaction.id}}">{{client.name}}</a></span></h2></td> + <td width="23%"> + {% if interaction.repo_revision %}Revision: {{interaction.repo_revision}}{% endif %} + </td> + <td width="33%"><div class="statusborder"> + <div class="greenbar" style="width: {{interaction.percentgood}}%;"> </div> + <div class="redbar" style="width: {{interaction.percentbad}}%;"> </div> + </div> + </td></tr> + </table> + {% if interaction.isclean %} + <div class="clean"> + <span class="nodelisttitle">Node is clean; Everything has been satisfactorily configured.</span> + </div> + {% endif %} + {% if interaction.isstale %} + <div class="warning"> + <span class="nodelisttitle">This node did not run within the last 24 hours-- it may be out of date.</span> + </div> + {% endif %} + {% if interaction.bad_items.all %} + <div class="bad"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-bad');" title="Click to expand" class="commentLink">{{interaction.bad_items.count}}</a> items did not verify and are considered Dirty.<br /></span> + <div class="items" id="{{client.name}}-bad"><ul class="plain"> + {% for bad in interaction.bad_items.all %} {% comment %}HOWDOI? order_by('kind', 'name'){% endcomment %} + <li><strong>{{bad.kind}}: </strong><tt>{{bad.name}}</tt></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if interaction.modified_items.all %} + <div class="modified"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-modified');" title="Click to expand" class="commentLink">{{interaction.modified_items.count}}</a> items were modified in the last run.<br /></span> + <div class="items" id="{{client.name}}-modified"><ul class="plain"> + {% for modified in interaction.modified_items.all %} {% comment %}HOWDOI? order_by('kind', 'name'){% endcomment %} + <li><strong>{{modified.kind}}: </strong><tt>{{modified.name}}</tt></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if interaction.extra_items.all %} + <div class="extra"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('{{client.name}}-extra');" title="Click to expand" class="commentLink">{{interaction.extra_items.count}}</a> extra configuration elements on the node.<br /></span> + <div class="items" id="{{client.name}}-extra"><ul class="plain"> + {% for extra in interaction.extra_items.all %} {% comment %}HOWDOI? order_by('kind', 'name'){% endcomment %} + <li><strong>{{extra.kind}}: </strong><tt>{{extra.name}}</tt></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + </div> +{% else %} + <p>No record could be found for this client.</p> +{% endif %} diff --git a/reports/brpt/reports/templates/clients/detail.html b/reports/brpt/reports/templates/clients/detail.html new file mode 100644 index 000000000..4ac2123c1 --- /dev/null +++ b/reports/brpt/reports/templates/clients/detail.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}Info for: {{client.name}}{% endblock %} + +{% block content %} +<b>Select time: </b> +<select name=quick onChange="MM_jumpMenu('parent',this,0)"> + {% for i in client.interactions.all %} + <option {% ifequal i.id interaction.id %}selected {% endifequal %} value="/clients/{{client.name}}/{{i.id}}/"> {{i.timestamp}} + {% endfor %} +</select> + +{% include "clients/client-nodebox.html" %} +{% endblock %} diff --git a/reports/brpt/reports/templates/clients/index.html b/reports/brpt/reports/templates/clients/index.html new file mode 100644 index 000000000..a474667b3 --- /dev/null +++ b/reports/brpt/reports/templates/clients/index.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %}Client Index Listing{% endblock %} + +{% block content %} +{% if client_list %} + <ul> + {% for client in client_list %} + <li><a href="{{client.name}}/">{{ client.name }}</a></li> + {% endfor %} + </ul> +{% else %} + <p>No client records are available.</p> +{% endif %} +{% endblock %} diff --git a/reports/brpt/reports/templates/displays/index.html b/reports/brpt/reports/templates/displays/index.html new file mode 100644 index 000000000..5d1d3bf76 --- /dev/null +++ b/reports/brpt/reports/templates/displays/index.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block title %}Display Index Listing{% endblock %} +{% block pagebanner %} + <div class="header"> + <h1>BCFG Display Index</h1> + {% comment %} <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>{% endcomment %} + </div> + <br/> +{% endblock %} + +{% block content %} +<ul> +<li><a href="/displays/sys-view/">System View</a></li> +<li><a href="/displays/summary/">Summary Only</a></li> +<li><a href="/displays/timing/">Timing</a></li> +</ul> +{% endblock %} diff --git a/reports/brpt/reports/templates/displays/summary-block-direct-links.html b/reports/brpt/reports/templates/displays/summary-block-direct-links.html new file mode 100644 index 000000000..a218e12b6 --- /dev/null +++ b/reports/brpt/reports/templates/displays/summary-block-direct-links.html @@ -0,0 +1,7 @@ +{% extends "displays/summary-block.html" %} +{% block linkprefix1 %}/clients/{% endblock %} +{% block linkprefix2 %}/clients/{% endblock %} +{% block linkprefix3 %}/clients/{% endblock %} +{% block linkprefix4 %}/clients/{% endblock %} +{% block linkprefix5 %}/clients/{% endblock %} +{% block linkprefix6 %}/clients/{% endblock %}
\ No newline at end of file diff --git a/reports/brpt/reports/templates/displays/summary-block.html b/reports/brpt/reports/templates/displays/summary-block.html new file mode 100644 index 000000000..3632cc870 --- /dev/null +++ b/reports/brpt/reports/templates/displays/summary-block.html @@ -0,0 +1,90 @@ +{% load django_templating_sigh %} + + <div class="nodebox"> + <h2>Summary:</h2> + <p class="indented">{{client_list|length }} Nodes were included in your report.</p> + {% if clean_client_list %} + <div class="clean"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('goodsummary');" title="Click to Expand" class="commentLink">{{clean_client_list|length}}</a> nodes are clean.<br /></span> + <div class="items" id="goodsummary"><ul class="plain"> + {% for client in clean_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix1 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if bad_client_list %} + <div class="bad"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('badsummary');" title="Click to Expand" class="commentLink">{{bad_client_list|length}}</a> nodes are bad.<br /></span> + <div class="items" id="badsummary"><ul class="plain"> + {% for client in bad_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix2 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if modified_client_list %} + <div class="modified"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('modifiedsummary');" title="Click to Expand" class="commentLink">{{modified_client_list|length}}</a> nodes were modified in the previous run.<br /></span> + <div class="items" id="modifiedsummary"><ul class="plain"> + {% for client in modified_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix3 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if extra_client_list %} + <div class="extra"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('extrasummary');" title="Click to Expand" class="commentLink">{{extra_client_list|length}}</a> nodes have extra configuration. (includes both good and bad nodes)<br /></span> + <div class="items" id="extrasummary"><ul class="plain"> + {% for client in extra_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix4 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if stale_up_client_list %} + <div class="warning"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('vstalesummary');" title="Click to Expand" class="commentLink">{{stale_up_client_list|length}}</a> nodes did not run within the last 24 hours but were pingable.<br /></span> + <div class="items" id="vstalesummary"><ul class="plain"> + {% for client in stale_up_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix5 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if stale_all_client_list %} + <div class="all-warning"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('stalesummary');" title="Click to Expand" class="commentLink">{{stale_all_client_list|length}}</a> nodes did not run within the last 24 hours. (includes nodes up and down)<br /></span> + <div class="items" id="stalesummary"><ul class="plain"> + {% for client in stale_all_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="{% block linkprefix6 %}#{% endblock %}{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + {% if down_client_list %} + <div class="down"> + <span class="nodelisttitle"><a href="javascript:toggleLayer('unpingablesummary');" title="Click to Expand" class="commentLink">{{down_client_list|length}}</a> nodes were down.<br /></span> + <div class="items" id="unpingablesummary"><ul class="plain"> + {% for client in down_client_list %} + {% set_interaction "foo" %} + <li><b>Node: </b></tt> + <tt><a href="#{{client.name}}">{{client.name}}</a></tt><span class="mini-date">{{interaction.timestamp}}</span></li> + {% endfor %} + </ul></div> + </div> + {% endif %} + </div>
\ No newline at end of file diff --git a/reports/brpt/reports/templates/displays/summary.html b/reports/brpt/reports/templates/displays/summary.html new file mode 100644 index 000000000..f3c3c1339 --- /dev/null +++ b/reports/brpt/reports/templates/displays/summary.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}Display Index Listing{% endblock %} +{% block pagebanner %} + <div class="header"> + <h1>BCFG Clients Summary</h1> + <span class="notebox">Report Run @ {% now "F j, Y P"%}</span> + </div> + <br/> +{% endblock %} + +{% block content %} + {% include "displays/summary-block-direct-links.html" %} +{% endblock %} diff --git a/reports/brpt/reports/templates/displays/sys_view.html b/reports/brpt/reports/templates/displays/sys_view.html new file mode 100644 index 000000000..bf80f545d --- /dev/null +++ b/reports/brpt/reports/templates/displays/sys_view.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% load django_templating_sigh %} + +{% block title %}System-View Display{% endblock %} +{% block pagebanner %} + <div class="header"> + <h1>BCFG Performance Timings</h1> + <span class="notebox">Report Run @ {% now "F j, Y P"%}</span> + </div> + <br/> +{% endblock %} +{% block content %} + {% include "displays/summary-block.html" %} + {% for client in client_list %} + {% set_interaction "foo" %} + {% include "clients/client-nodebox.html" %} + {% endfor %} +{% endblock %} diff --git a/reports/brpt/reports/templates/displays/timing.html b/reports/brpt/reports/templates/displays/timing.html new file mode 100644 index 000000000..c3573851a --- /dev/null +++ b/reports/brpt/reports/templates/displays/timing.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block extra_header_info %} +<script type="text/javascript" src="/site_media/sorttable.js"> +</script>{% endblock%} +{% comment %} THIS ABOVE PART MAY BE SITE DEPENDENT-- CHANGE {% endcomment %} +{% block title %}Display Index Listing{% endblock %} + +{% block content %} + <div class="header"> + <h1>BCFG Performance Timings</h1> + <span class="notebox">Report Run @ {% now "F j, Y P"%}</span> + </div> + <br/> + <center> + <table id="t1" class="sortable"> + <tr> + <th class="sortable">Hostname</th> + <th class="sortable">Parse</th> + <th class="sortable">Probe</th> + <th class="sortable">Inventory</th> + <th class="sortable">Install</th> + <th class="sortable">Config</th> + <th class="sortable">Total</th> + </tr> + {% for dict_unit in stats_list %} + <tr> + <td class="sortable"><a href="/clients/{{dict_unit.name}}/">{{dict_unit.name}}</a></td> + <td class="sortable">{{dict_unit.parse}}</td> + <td class="sortable">{{dict_unit.probe}}</td> + <td class="sortable">{{dict_unit.inventory}}</td> + <td class="sortable">{{dict_unit.install}}</td> + <td class="sortable">{{dict_unit.config}}</td> + <td class="sortable">{{dict_unit.total}}</td> + </tr> + {% endfor %} + </table> + </center> +{% endblock %}
\ No newline at end of file diff --git a/reports/brpt/reports/templates/index.html b/reports/brpt/reports/templates/index.html new file mode 100644 index 000000000..002a3f770 --- /dev/null +++ b/reports/brpt/reports/templates/index.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block pagebanner %} + <div class="header"> + <h1>BCFG Reports</h1> + {% comment %} <span class="notebox">Report Run @ {% now "F j, Y P"%}</span>{% endcomment %} + </div> + <br/> +{% endblock %} +{% block content %} +<h1>Welcome to the Bcfg2 Reporting System</h1> +<p> +Please use the links at the left to navigate. +</p> +{% endblock %} diff --git a/reports/brpt/reports/templatetags/__init__.py b/reports/brpt/reports/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/reports/brpt/reports/templatetags/__init__.py diff --git a/reports/brpt/reports/templatetags/__init__.pyc b/reports/brpt/reports/templatetags/__init__.pyc Binary files differnew file mode 100644 index 000000000..c1161f868 --- /dev/null +++ b/reports/brpt/reports/templatetags/__init__.pyc diff --git a/reports/brpt/reports/templatetags/django_templating_sigh.py b/reports/brpt/reports/templatetags/django_templating_sigh.py new file mode 100644 index 000000000..146b2e0f9 --- /dev/null +++ b/reports/brpt/reports/templatetags/django_templating_sigh.py @@ -0,0 +1,24 @@ +from django import template +from brpt.reports.models import Client, Interaction, Bad, Modified, Extra + +register = template.Library() + +def set_interaction(parser, token): + try: + # Splitting by None == splitting by spaces. + tag_name, format_string = token.contents.split(None, 1) + except ValueError: + raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0] + if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): + raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name + return SetInteraction(format_string[1:-1]) + + +class SetInteraction(template.Node): + def __init__(self, times): + self.times = times#do soemthing to select different interaction with host + def render(self, context): + context['interaction'] = context['client'].interactions.order_by('-timestamp')[0] + return '' + +register.tag('set_interaction', set_interaction) diff --git a/reports/brpt/reports/templatetags/django_templating_sigh.pyc b/reports/brpt/reports/templatetags/django_templating_sigh.pyc Binary files differnew file mode 100644 index 000000000..f985dbdd8 --- /dev/null +++ b/reports/brpt/reports/templatetags/django_templating_sigh.pyc diff --git a/reports/brpt/reports/views.py b/reports/brpt/reports/views.py new file mode 100644 index 000000000..2edf43e1c --- /dev/null +++ b/reports/brpt/reports/views.py @@ -0,0 +1,121 @@ +# Create your views here. +#from django.shortcuts import get_object_or_404, render_to_response +from django.template import Context, loader +from django.http import HttpResponseRedirect, HttpResponse +from django.shortcuts import render_to_response, get_object_or_404 +from brpt.reports.models import Client, Interaction, Bad, Modified, Extra +from datetime import datetime + + +def index(request): + return render_to_response('index.html') + +def client_index(request): + client_list = Client.objects.all().order_by('name') + return render_to_response('clients/index.html',{'client_list': client_list}) + +def client_detail(request, hostname = -1, pk = -1): + #SETUP error pages for when you specify a client or interaction that doesn't exist + client = get_object_or_404(Client, name=hostname) + if(pk == -1): + interaction = client.interactions.order_by('-timestamp')[0] + else: + interaction = client.interactions.get(pk=pk) + + return render_to_response('clients/detail.html',{'client': client, 'interaction': interaction}) + +def display_sys_view(request): + client_lists = prepare_client_lists(request) + return render_to_response('displays/sys_view.html', client_lists) + +def display_summary(request): + client_lists = prepare_client_lists(request) + return render_to_response('displays/summary.html', client_lists) + +def display_timing(request): + #We're going to send a list of dictionaries. Each dictionary will be a row in the table + #+------+-------+----------------+-----------+---------+----------------+-------+ + #| name | parse | probe download | inventory | install | cfg dl & parse | total | + #+------+-------+----------------+-----------+---------+----------------+-------+ + client_list = Client.objects.all().order_by('-name') + stats_list = [] + #if we have stats for a client, go ahead and add it to the list(wrap in TRY) + for client in client_list:#Go explicitly to an interaction ID! (new item in dictionary) + performance_items = client.interactions.order_by('-timestamp')[0].performance_items#allow this to be selectable(hist) + dict_unit = {} + try: + dict_unit["name"] = client.name #node name + except: + dict_unit["name"] = "n/a" + try: + dict_unit["parse"] = performance_items.get(metric="config_parse").value - performance_items.get(metric="config_download").value #parse + except: + dict_unit["parse"] = "n/a" + try: + dict_unit["probe"] = performance_items.get(metric="probe_upload").value - performance_items.get(metric="start").value #probe + except: + dict_unit["probe"] = "n/a" + try: + dict_unit["inventory"] = performance_items.get(metric="inventory").value - performance_items.get(metric="initialization").value #inventory + except: + dict_unit["inventory"] = "n/a" + try: + dict_unit["install"] = performance_items.get(metric="install").value - performance_items.get(metric="inventory").value #install + except: + dict_unit["install"] = "n/a" + try: + dict_unit["config"] = performance_items.get(metric="config_parse").value - performance_items.get(metric="probe_upload").value#config download & parse + except: + dict_unit["config"] = "n/a" + try: + dict_unit["total"] = performance_items.get(metric="finished").value - performance_items.get(metric="start").value #total + except: + dict_unit["total"] = "n/a" + + #make sure all is formatted as such: #.## + stats_list.append(dict_unit) + + + return render_to_response('displays/timing.html',{'client_list': client_list, 'stats_list': stats_list}) + +def display_index(request): + return render_to_response('displays/index.html') + +def prepare_client_lists(request): + client_list = Client.objects.all().order_by('name')#change this to order by interaction's state + clean_client_list = [] + bad_client_list = [] + extra_client_list = [] + modified_client_list = [] + stale_up_client_list = [] + stale_all_client_list = [] + down_client_list = [] + for client in client_list:#but we need clientlist for more than just this loop + i = client.interactions.order_by('-timestamp')[0] +# if i.state == 'good': + if i.isclean(): + clean_client_list.append(client) + else: + bad_client_list.append(client) + if i.isstale(): + if i.pingable: + stale_up_client_list.append(client) + stale_all_client_list.append(client) + else: + stale_all_client_list.append(client) + if not i.pingable: + down_client_list.append(client) + if len(i.modified_items.all()) > 0: + modified_client_list.append(client) + if len(i.extra_items.all()) > 0: + extra_client_list.append(client) + + #if the list is empty set it to None? + return {'client_list': client_list, + 'clean_client_list': clean_client_list, + 'bad_client_list': bad_client_list, + 'extra_client_list': extra_client_list, + 'modified_client_list': modified_client_list, + 'stale_up_client_list': stale_up_client_list, + 'stale_all_client_list': stale_all_client_list, + 'down_client_list': down_client_list} diff --git a/reports/brpt/reports/views.pyc b/reports/brpt/reports/views.pyc Binary files differnew file mode 100644 index 000000000..0b163a1be --- /dev/null +++ b/reports/brpt/reports/views.pyc diff --git a/reports/brpt/settings.py b/reports/brpt/settings.py new file mode 100644 index 000000000..bcdcdbd0b --- /dev/null +++ b/reports/brpt/settings.py @@ -0,0 +1,75 @@ +# Django settings for brpt project. + + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + ('Joey Hagedorn', 'hagedorn@mcs.anl.gov'), +) + +MANAGERS = ADMINS + +DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. +DATABASE_NAME = '/Users/joey/anl-mcs/dev/bcfg2/reports/brpt-db' # Or path to database file if using sqlite3. +DATABASE_USER = '' # Not used with sqlite3. +DATABASE_PASSWORD = '' # Not used with sqlite3. +DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. +DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. + +# Local time zone for this installation. All choices can be found here: +# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes +# http://blogs.law.harvard.edu/tech/stories/storyReader$15 +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. +# Example: "http://media.lawrence.com" +MEDIA_URL = '' + +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a +# trailing slash. +# Examples: "http://foo.com/media/", "/media/". +ADMIN_MEDIA_PREFIX = '/media/' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'eb5+y%oy-qx*2+62vv=gtnnxg1yig_odu0se5$h0hh#pc*lmo7' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + 'django.template.loaders.app_directories.load_template_source', +# 'django.template.loaders.eggs.load_template_source', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.middleware.doc.XViewMiddleware', +) + +ROOT_URLCONF = 'brpt.urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates". + # Always use forward slashes, even on Windows. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.admin', + 'brpt.reports' +) diff --git a/reports/brpt/settings.pyc b/reports/brpt/settings.pyc Binary files differnew file mode 100644 index 000000000..393fe8e27 --- /dev/null +++ b/reports/brpt/settings.pyc diff --git a/reports/brpt/urls.py b/reports/brpt/urls.py new file mode 100644 index 000000000..3f284cc6c --- /dev/null +++ b/reports/brpt/urls.py @@ -0,0 +1,30 @@ +from django.conf.urls.defaults import * + +urlpatterns = patterns('', + # Example: + # (r'^brpt/', include('brpt.apps.foo.urls.foo')), + (r'^/*$','brpt.reports.views.index'), + (r'^clients/(?P<hostname>\S+)/(?P<pk>\d+)/$', 'brpt.reports.views.client_detail'), + (r'^clients/(?P<hostname>\S+)/$', 'brpt.reports.views.client_detail'), + (r'^clients/(?P<hostname>\S+)$', 'brpt.reports.views.client_detail'), + #hack because hostnames have periods and we still want to append slash + (r'^clients/$','brpt.reports.views.client_index'), + + (r'^displays/sys-view/$','brpt.reports.views.display_sys_view'), + (r'^displays/summary/$','brpt.reports.views.display_summary'), + (r'^displays/timing/$','brpt.reports.views.display_timing'), + (r'^displays/$','brpt.reports.views.display_index'), + + # Uncomment this for admin: + (r'^admin/', include('django.contrib.admin.urls')), + + + + + #Remove this when not doing DEVELOPMENT + #and i quote: + #Using this method is inefficient and insecure. Do not use this in a production setting. Use this only for development. + (r'^site_media/(.*)$', 'django.views.static.serve', {'document_root': '/Users/joey/anl-mcs/dev/bcfg2/reports/site_media/'}), + + +) diff --git a/reports/brpt/urls.pyc b/reports/brpt/urls.pyc Binary files differnew file mode 100644 index 000000000..0bf6eff8b --- /dev/null +++ b/reports/brpt/urls.pyc diff --git a/reports/site_media/base.css b/reports/site_media/base.css new file mode 100644 index 000000000..50ac79832 --- /dev/null +++ b/reports/site_media/base.css @@ -0,0 +1,5 @@ + +/* Import other styles */ +@import url('global.css'); +@import url('layout.css'); +@import url('boxypastel.css);
\ No newline at end of file diff --git a/reports/site_media/boxypastel.css b/reports/site_media/boxypastel.css new file mode 100644 index 000000000..896c8c428 --- /dev/null +++ b/reports/site_media/boxypastel.css @@ -0,0 +1,214 @@ +/* body */ +/*body {*/ +/* background-color: #fff;*/ +/* color: #000;*/ +/* font: 12px 'Lucida Grande', Arial, Helvetica, sans-serif;*/ +/* margin-left:25px;*/ +/* margin-right:100px;*/ +/* }*/ + + + +/* links */ +a:link { + color: #00f; + text-decoration: none; + } +a:visited { + color: #00a; + text-decoration: none; + } +a:hover { + color: #00a; + text-decoration: underline; + } +a:active { + color: #00a; + text-decoration: underline; + } +/* divs*/ +div.bad { + border: 1px solid #660000; + background: #FF6A6A; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.modified { + border: 1px solid #CC9900; + background: #FFEC8B; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.clean { + border: 1px solid #006600; + background: #9AFF9A; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.extra { + border: 1px solid #006600; + background: #6699CC; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.warning { + border: 1px solid #CC3300; + background: #FF9933; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.all-warning { + border: 1px solid #DD5544; + background: #FFD9A2; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.down { + border: 1px solid #999; + background-color: #DDD; + margin: 10px 0; + padding: 8px; + text-align: left; + margin-left:50px; + margin-right:50px; + } +div.items { + display: none; + } +div.nodebox { + border: 1px solid #c7cfd5; + background: #f1f5f9; + margin: 20px 0; + padding: 8px 8px 16px 8px; + text-align: left; + position:relative; + } +div.header { + background-color: #DDD; + padding: 8px; + text-indent:50px; + position:relative; + } +/*Divs For Statusbar*/ +div.redbar { + border: 0px solid #660000; + background: #FF6666; + margin: 0px; + float: left; + } + +div.greenbar { + border: 0px solid #006600; + background: #66FF66; + margin: 0px; + float: left; + } +div.statusborder { + border: 1px solid #000000; + background: #FF6666; + margin: 0px; + float: right; + width: 100%; + } + /*invisitable*/ +table.invisitable { + width: 100%; + border: 0px; + cell-padding: 0px; + padding: 0px; + border-width: 0px; + } +/*Spans*/ +span.nodename { + font-style: italic; + } +span.nodelisttitle { + font-size: 14px; + } +span.mini-date { + font-size: 10px; + position: absolute; + right: 65px; + } + +h2 { + font-size: 16px; + color: #000; + } + +ul.plain { + list-style-type:none; + text-align: left; + } + +.notebox { + position: absolute; + top: 0px; + right: 0px; + padding: 1px; + text-indent:0px; + border: 1px solid #FFF; + background: #999; + color: #FFF; + } + +.configbox { + position: absolute; + bottom: 0px; + right: 0px; + padding: 1px; + text-indent:0px; + border: 1px solid #999; + background: #FFF; + color: #999; + } + +p.indented{ + text-indent: 50px + } + +/* Sortable tables */ +table.sortable a.sortheader { + background-color:#dfd; + font-weight: bold; + text-decoration: none; + display: block; + +} +table.sortable { + padding: 2px 4px 2px 4px; + border: 1px solid #000000; + border-spacing: 0px +} +td.sortable{ + padding: 2px 8px 2px 8px; +} + +th.sortable{ + background-color:#F3DD91; + border: 1px solid #FFFFFF; +} +tr.tablelist { + background-color:#EDF3FE; +} +tr.tablelist-alt{ + background-color:#FFFFFF; +} diff --git a/reports/site_media/global.css b/reports/site_media/global.css new file mode 100644 index 000000000..1dc57f3ca --- /dev/null +++ b/reports/site_media/global.css @@ -0,0 +1,9 @@ + +body { + margin:0; + padding:0; + font-size:12px; + font-family:"Lucida Grande","Bitstream Vera Sans",Verdana,Arial,sans-serif; + color:#000; + background:#fff; + } diff --git a/reports/site_media/layout.css b/reports/site_media/layout.css new file mode 100644 index 000000000..f6f08098c --- /dev/null +++ b/reports/site_media/layout.css @@ -0,0 +1,30 @@ +/* Page Structure */ +#container { position:absolute; top: 3em; margin-left:1em; margin-right:2em; padding:0; margin-top:1.5em; min-width: 650px; } +#header { width:100%; } +#content-main { float:left; } + +/* HEADER */ +#header { background:#000; color:#ffc; position:absolute;} +#header a:link, #header a:visited { color:white; } +#header a:hover { text-decoration:underline; } +#branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; } +#branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; } +#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; } + +/*SIDEBAR*/ +#sidebar {float: left; position: relative; width: auto; height: 100%; margin-top: 3em; padding-right: 1.5em; padding-left: 1.5em; padding-top: 1em; padding-bottom:3em; background: #000; color:ffc; } +a.sidebar:link {color: #fff;} +a.sidebar:active {color: #fff;} +a.sidebar:visited {color: #fff;} +a.sidebar:hover {color: #fff;} +ul.sidebar { + color: #ffc; + text-decoration: none; + list-style-type: none; + text-indent: -1em; +} +ul.sidebar-level2 { + text-indent: -2em; + list-style-type: none; + font-size: 11px; +}
\ No newline at end of file diff --git a/reports/site_media/main.js b/reports/site_media/main.js new file mode 100644 index 000000000..556130466 --- /dev/null +++ b/reports/site_media/main.js @@ -0,0 +1,27 @@ +function toggleLayer(whichLayer) + { + if (document.getElementById) + { + // this is the way the standards work + var style2 = document.getElementById(whichLayer).style; + style2.display = style2.display? "":"block"; + } + else if (document.all) + { + // this is the way old msie versions work + var style2 = document.all[whichLayer].style; + style2.display = style2.display? "":"block"; + } + else if (document.layers) + { + // this is the way nn4 works + var style2 = document.layers[whichLayer].style; + style2.display = style2.display? "":"block"; + } + } + +function MM_jumpMenu(targ,selObj,restore) +{ //v3.0 + eval(targ+".location='"+selObj.options[selObj.selectedIndex].value+"'"); + if (restore) selObj.selectedIndex=0; +}
\ No newline at end of file diff --git a/reports/site_media/sorttable.js b/reports/site_media/sorttable.js new file mode 100644 index 000000000..83c87708e --- /dev/null +++ b/reports/site_media/sorttable.js @@ -0,0 +1,203 @@ + +// +// Sourced originally from: +// +// http://www.kryogenix.org/code/browser/sorttable/ + + + +addEvent(window, "load", sortables_init); + +var SORT_COLUMN_INDEX; + +function sortables_init() { + // Find all tables with class sortable and make them sortable + if (!document.getElementsByTagName) return; + tbls = document.getElementsByTagName("table"); + for (ti=0;ti<tbls.length;ti++) { + thisTbl = tbls[ti]; + if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) { + //initTable(thisTbl.id); + ts_makeSortable(thisTbl); + } + } +} + +function ts_makeSortable(table) { + if (table.rows && table.rows.length > 0) { + var firstRow = table.rows[0]; + } + if (!firstRow) return; + + // Assign classes to the rows when the table's first loaded + for (i=1;i<table.rows.length;i++) { + if (i%2 == 0) table.rows[i].className='tablelist'; + else table.rows[i].className='tablelist tablelist-alt'; + } + + // We have a first row: assume it's the header, and make its contents clickable links + for (var i=0;i<firstRow.cells.length;i++) { + var cell = firstRow.cells[i]; + var txt = ts_getInnerText(cell); + cell.innerHTML = '<a href="#" onclick="ts_resortTable(this, '+i+');return false;">'+txt+'<span class="sortarrow"></span></a>'; + } +} + +function ts_getInnerText(el) { + if (typeof el == "string") return el; + if (typeof el == "undefined") { return el }; + if (el.innerText) return el.innerText; //Not needed but it is faster + var str = ""; + + var cs = el.childNodes; + var l = cs.length; + for (var i = 0; i < l; i++) { + switch (cs[i].nodeType) { + case 1: //ELEMENT_NODE + str += ts_getInnerText(cs[i]); + break; + case 3: //TEXT_NODE + str += cs[i].nodeValue; + break; + } + } + return str; +} + +function ts_resortTable(lnk, clid) { + // get the span + var span; + for (var ci=0;ci<lnk.childNodes.length;ci++) { + if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci]; + } + var spantext = ts_getInnerText(span); + var td = lnk.parentNode; + var column = clid || td.cellIndex; + var table = getParent(td,'TABLE'); + + // Work out a type for the column + if (table.rows.length <= 1) return; + var itm = ts_getInnerText(table.rows[1].cells[column]); + sortfn = ts_sort_caseinsensitive; + if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date; + if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date; + + if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric; + SORT_COLUMN_INDEX = column; + var firstRow = new Array(); + var newRows = new Array(); + for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; } + for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; } + + newRows.sort(sortfn); + + if (span.getAttribute("sortdir") == 'down') { + ARROW = ''; + newRows.reverse(); + span.setAttribute('sortdir','up'); + } else { + ARROW = ''; + span.setAttribute('sortdir','down'); + } + + // Assign updated classes to the rows when the sort's finished + for (i=0;i<newRows.length;i++) { + if (i%2 == 1) newRows[i].className='tablelist'; + else newRows[i].className='tablelist tablelist-alt'; + } + + // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones + // don't do sortbottom rows + for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);} + // do sortbottom rows only + for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);} + + // Delete any other arrows there may be showing + var allspans = document.getElementsByTagName("span"); + for (var ci=0;ci<allspans.length;ci++) { + if (allspans[ci].className == 'sortarrow') { + if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us? + allspans[ci].innerHTML = ''; + } + } + } + + span.innerHTML = ARROW; +} + +function getParent(el, pTagName) { + if (el == null) return null; + else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase + return el; + else + return getParent(el.parentNode, pTagName); +} +function ts_sort_date(a,b) { + // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX + aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); + bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); + if (aa.length == 10) { + dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2); + } else { + yr = aa.substr(6,2); + if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } + dt1 = yr+aa.substr(3,2)+aa.substr(0,2); + } + if (bb.length == 10) { + dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2); + } else { + yr = bb.substr(6,2); + if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } + dt2 = yr+bb.substr(3,2)+bb.substr(0,2); + } + if (dt1==dt2) return 0; + if (dt1<dt2) return -1; + return 1; +} + +function ts_sort_currency(a,b) { + aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); + bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); + return parseFloat(aa) - parseFloat(bb); +} + +function ts_sort_numeric(a,b) { + aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX])); + if (isNaN(aa)) aa = 0; + bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); + if (isNaN(bb)) bb = 0; + return aa-bb; +} + +function ts_sort_caseinsensitive(a,b) { + aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase(); + bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase(); + if (aa==bb) return 0; + if (aa<bb) return -1; + return 1; +} + +function ts_sort_default(a,b) { + aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); + bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); + if (aa==bb) return 0; + if (aa<bb) return -1; + return 1; +} + + +function addEvent(elm, evType, fn, useCapture) +// addEvent and removeEvent +// cross-browser event handling for IE5+, NS6 and Mozilla +// By Scott Andrew +{ + if (elm.addEventListener){ + elm.addEventListener(evType, fn, useCapture); + return true; + } else if (elm.attachEvent){ + var r = elm.attachEvent("on"+evType, fn); + return r; + } else { + alert("Handler could not be removed"); + } +} |