[cig-commits] r11824 - in cs/portal/trunk: . seismo/SeismoWebPortal seismo/SeismoWebPortal/designs/plone seismo/SeismoWebPortal/static/pics seismo/SeismoWebPortal/templates/SeismoWebPortal
leif at geodynamics.org
leif at geodynamics.org
Thu Apr 17 12:47:51 PDT 2008
Author: leif
Date: 2008-04-17 12:47:51 -0700 (Thu, 17 Apr 2008)
New Revision: 11824
Added:
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.js
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.py
cs/portal/trunk/seismo/SeismoWebPortal/static/pics/barbers_pole.gif
cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_bar.gif
cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_box.gif
cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/job_progress_form.html
Modified:
cs/portal/trunk/daemon.py
cs/portal/trunk/mineos.py
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.html
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.py
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/__init__.py
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.css
cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.py
cs/portal/trunk/seismo/SeismoWebPortal/models.py
cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/seismogram_table.html
cs/portal/trunk/seismo/SeismoWebPortal/views.py
Log:
Finally implemented the progress bars that I've been imagining since
this project began. They are animated using JavaScript.
Modified: cs/portal/trunk/daemon.py
===================================================================
--- cs/portal/trunk/daemon.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/daemon.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -198,7 +198,8 @@
def argvForJob(self, job):
- return [job.resSpec['executable']] + job.resSpec['arguments']
+ return ([job.resSpec['executable']] + job.resSpec['arguments'] +
+ ["--progress-url=%s" % job.progressUrl])
def uploadOutputFilesForJob(self, job):
@@ -514,7 +515,7 @@
'--stations=' + self.simulation.stations,
"--scheduler.wait=True",
"--job.name=run%05d" % self.id,
- #"--portal-run-id=%d" % self.id,
+ "--macros.run.id=%05d" % self.id,
#"--job.walltime=2*hour",
"--job.stdout=stdout.txt",
"--job.stderr=stderr.txt",
@@ -637,6 +638,7 @@
fields = self.jobFields(job, run)
response = self.postStatusChange(url, fields)
portalId = eval(response)
+ job.progressUrl = self.portal.jobProgressUrl % portalId
stackless.tasklet(self.jobWatcher)(job, portalId, run)
def jobWatcher(self, job, portalId, run):
@@ -771,6 +773,7 @@
# jobs
self.jobCreateUrl = self.urlRoot + 'jobs/create/'
self.jobUpdateUrl = self.urlRoot + 'jobs/%d/update/'
+ self.jobProgressUrl = self.urlPrefix + 'jobs/%d/progress/'
# output
self.outputCreateUrl = self.urlRoot + 'output/create/'
Modified: cs/portal/trunk/mineos.py
===================================================================
--- cs/portal/trunk/mineos.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/mineos.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -4,7 +4,7 @@
from pyre.applications import Script
from pyre.units.SI import milli, hertz
from pyre.units.length import km
-import os, sys, stat
+import os, sys, stat, popen2, time
from os.path import basename, dirname, splitext
mHz = milli*hertz
@@ -34,11 +34,12 @@
class Mineos(object):
- def __init__(self, model, event, stations):
+ def __init__(self, model, event, stations, progressUrl):
self.bin = prefix + "/bin"
self.model = model
self.event = event
self.stations = stations
+ self.progressUrl = progressUrl
self.eigcon_out = []
self.green_out = "green"
return
@@ -80,19 +81,31 @@
def green(self, fmin, fmax, nsamples):
+ nStations = self.lineCount(self.stations + ".site")
s = open("db_list", "w")
for dbname in self.eigcon_out:
print >>s, dbname
- green_in = "green.in"
- s = open(green_in, "w")
- print >>s, self.stations
- print >>s, "db_list"
- print >>s, self.event
- print >>s, fmin, fmax
- print >>s, nsamples
- print >>s, self.green_out
- s.close()
- self.run("green", stdin=green_in)
+ green_in = open("green.in", "w")
+ child = popen2.Popen4([os.path.join(self.bin, "green")])
+ for s in [green_in, child.tochild]:
+ print >>s, self.stations
+ print >>s, "db_list"
+ print >>s, self.event
+ print >>s, fmin, fmax
+ print >>s, nsamples
+ print >>s, self.green_out
+ s.close()
+ stationTally = 0
+ self.postProgress(0.0)
+ lastPostTime = time.time()
+ for line in child.fromchild:
+ print line,
+ if line.startswith(" green: Station: "):
+ stationTally += 1
+ now = time.time()
+ if now - lastPostTime >= 60.0:
+ self.postProgress(float(stationTally) / float(nStations))
+ lastPostTime = now
return
@@ -162,6 +175,36 @@
return
+ def lineCount(self, filename):
+ tally = 0
+ s = open(filename, 'r')
+ for line in s:
+ tally += 1
+ return tally
+
+
+ def postProgress(self, progress):
+ import urllib, urlparse
+ scheme, host, path = urlparse.urlparse(self.progressUrl)[0:3]
+ fields = { 'progress': "%.2f" % progress }
+ body = urllib.urlencode(fields)
+ headers = {"Content-Type": "application/x-www-form-urlencoded",
+ "Accept": "text/plain"}
+ import httplib
+ if scheme == "http":
+ conn = httplib.HTTPConnection(host)
+ elif scheme == "https":
+ conn = httplib.HTTPSConnection(host)
+ else:
+ assert False # not scheme in ["http", "https"]
+ conn.request("POST", path, body, headers)
+ response = conn.getresponse()
+ data = response.read()
+ conn.close()
+ return data
+
+
+
class MineosScript(Script):
name = "mineos"
@@ -220,7 +263,12 @@
plane = pyre.int("plane", default=0) # use CMT tensor components as-is
datatype = pyre.int("datatype", default=3) # displacement in nm
+ #------------------------------------------------------------------------
+ # misc.
+ progressUrl = pyre.str("progress-url")
+
+
def main(self, *args, **kwds):
self._info.activate()
@@ -258,7 +306,7 @@
def runMineos(self, model, enabledModes):
- mineos = Mineos(model, self.event, self.stations)
+ mineos = Mineos(model, self.event, self.stations, self.progressUrl)
# minos_bran
for mode in enabledModes:
@@ -308,12 +356,13 @@
def main(*args, **kwds):
- # Redirect all output -- our journal output, and the output of
- # our children -- to a file.
- fd = os.open("output_mineos.txt", os.O_CREAT | os.O_WRONLY, mode)
- os.dup2(fd, 1)
- os.dup2(fd, 2)
- os.close(fd)
+ if True:
+ # Redirect all output -- our journal output, and the output of
+ # our children -- to a file.
+ fd = os.open("output_mineos.txt", os.O_CREAT | os.O_WRONLY, mode)
+ os.dup2(fd, 1)
+ os.dup2(fd, 2)
+ os.close(fd)
mineos = MineosScript()
mineos.run(*args, **kwds)
Modified: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.html
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.html 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.html 2008-04-17 19:47:51 UTC (rev 11824)
@@ -3,6 +3,7 @@
<head>
<script type="text/javascript" src="http://www.geodynamics.org/cig/portal_javascripts/Plone%20Default/ploneScripts3133.js"></script>
<script type="text/javascript" src="http://www.geodynamics.org/cig/portal_javascripts/Plone%20Default/ploneScripts1044.js"></script>
+ <script type="text/javascript" src="$root/designs/plone/script.js"></script>
<style type="text/css"><!-- @import url(http://www.geodynamics.org/cig/portal_css/Plone%20Default/ploneStyles8697.css); --></style>
<style type="text/css" media="screen"><!-- @import url(http://www.geodynamics.org/cig/portal_css/Plone%20Default/ploneStyles4087.css); --></style>
<link rel="alternate stylesheet"
Modified: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/Document.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -33,10 +33,10 @@
currentTime=time.time
__CHEETAH_version__ = '2.0rc7'
__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 7)
-__CHEETAH_genTime__ = 1207258007.506633
-__CHEETAH_genTimestamp__ = 'Thu Apr 3 14:26:47 2008'
+__CHEETAH_genTime__ = 1208308360.6628461
+__CHEETAH_genTimestamp__ = 'Tue Apr 15 18:12:40 2008'
__CHEETAH_src__ = 'Document.html'
-__CHEETAH_srcLastModified__ = 'Thu Apr 3 14:18:05 2008'
+__CHEETAH_srcLastModified__ = 'Tue Apr 15 17:52:37 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
@@ -88,6 +88,10 @@
<head>
<script type="text/javascript" src="http://www.geodynamics.org/cig/portal_javascripts/Plone%20Default/ploneScripts3133.js"></script>
<script type="text/javascript" src="http://www.geodynamics.org/cig/portal_javascripts/Plone%20Default/ploneScripts1044.js"></script>
+ <script type="text/javascript" src="''')
+ _v = VFFSL(SL,"root",True) # '$root' on line 6, col 41
+ if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 6, col 41.
+ write('''/designs/plone/script.js"></script>
<style type="text/css"><!-- @import url(http://www.geodynamics.org/cig/portal_css/Plone%20Default/ploneStyles8697.css); --></style>
<style type="text/css" media="screen"><!-- @import url(http://www.geodynamics.org/cig/portal_css/Plone%20Default/ploneStyles4087.css); --></style>
<link rel="alternate stylesheet"
@@ -104,17 +108,17 @@
<style type="text/css" media="all">@import url(http://www.geodynamics.org/cig/IEFixes.css);</style>
<![endif]-->
<link href="''')
- _v = VFFSL(SL,"root",True) # '$root' on line 21, col 17
- if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 21, col 17.
+ _v = VFFSL(SL,"root",True) # '$root' on line 22, col 17
+ if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 22, col 17.
write('/designs/plone/style.css" type="text/css" rel="stylesheet" media="all" />\n <title>')
- _v = VFFSL(SL,"title",True) # '$title' on line 22, col 12
- if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 22, col 12.
+ _v = VFFSL(SL,"title",True) # '$title' on line 23, col 12
+ if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 23, col 12.
write('''</title>
</head>
<body>
''')
- _v = VFFSL(SL,"body",True) # '$body' on line 25, col 5
- if _v is not None: write(_filter(_v, rawExpr='$body')) # from line 25, col 5.
+ _v = VFFSL(SL,"body",True) # '$body' on line 26, col 5
+ if _v is not None: write(_filter(_v, rawExpr='$body')) # from line 26, col 5.
write('''
</body>
</html>
Modified: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/__init__.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/__init__.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/__init__.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -3,6 +3,7 @@
from Desktop import Desktop
from Document import Document
from style import style
+from script import script
import SeismoWebPortal.config as config
@@ -79,10 +80,16 @@
if not path: raise Http404
name = path.pop(0)
if path: raise Http404
- if name != "style.css":
+ index = {
+ "script.js": (script, "text/javascript"),
+ "style.css": (style, "text/css"),
+ }
+ entry = index.get(name)
+ if entry is None:
raise Http404
- template = style()
+ TemplateClass, mimetype = entry
+ template = TemplateClass()
template.root = config.root
response = HttpResponse(content = str(template),
- mimetype = "text/css")
+ mimetype = mimetype)
return response
Added: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.js
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.js (rev 0)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.js 2008-04-17 19:47:51 UTC (rev 11824)
@@ -0,0 +1,112 @@
+
+// progress bars
+
+var progressBars = new Array();
+var liveProgressBarTally = 0;
+var progressInterval = 0;
+
+var barberOffset = -40;
+
+
+function activateProgressBars() {
+ if (!W3CDOM) {return false;}
+
+ var query = cssQuery('span.progress');
+ for (var i = 0; i < query.length; i++) {
+ progressBar = new Object();
+ progressBar.element = query[i];
+ progressBar.isBarberPole = false;
+ progressBar.poll = -1;
+ progressBars.push(progressBar);
+ interpretProgressFromServer(progressBar);
+ }
+}
+
+registerPloneFunction(activateProgressBars);
+
+
+function interpretProgressFromServer(progressBar) {
+ var html = progressBar.element.innerHTML;
+ var oldPoll = progressBar.poll;
+
+ if (html.indexOf("barbers_pole") != -1) {
+ progressBar.isBarberPole = true;
+ progressBar.poll = 60000;
+ } else if (html.indexOf("progress_bar") != -1) {
+ progressBar.isBarberPole = false;
+ progressBar.poll = 60000;
+ } else {
+ progressBar.isBarberPole = false;
+ progressBar.poll = -1;
+ }
+
+ if (oldPoll < 0 && progressBar.poll >= 0) {
+ ++liveProgressBarTally;
+ if (liveProgressBarTally == 1) {
+ progressInterval = setInterval("animateProgressBars()", 100);
+ }
+ } else if (oldPoll >= 0 && progressBar.poll < 0) {
+ --liveProgressBarTally;
+ if (liveProgressBarTally == 0) {
+ clearInterval(progressInterval);
+ }
+ }
+}
+
+
+function makeProgressRequest(progressBar) {
+ var request = null;
+ callback = makeProgressCallback(progressBar);
+ if (typeof window.ActiveXObject != 'undefined') {
+ request = new ActiveXObject("Microsoft.XMLHTTP");
+ request.onreadystatechange = callback;
+ } else {
+ request = new XMLHttpRequest();
+ request.onload = callback;
+ }
+ var a = progressBar.element.id.split('-')
+ request.open("GET", "$root/runs/" + a[1] + "/status.html", true);
+ request.send(null);
+ progressBar.request = request;
+}
+
+
+function makeProgressCallback(progressBar) {
+ function callback() {
+ request = progressBar.request;
+ if (request.readyState != 4) return;
+ progressBar.element.innerHTML = request.responseText;
+ interpretProgressFromServer(progressBar);
+ }
+ return callback;
+}
+
+
+function animateProgressBars() {
+ ++barberOffset;
+ if (barberOffset >= -20) {
+ barberOffset = -40;
+ }
+
+ var bar = '<img src="$root/pics/progress_box.gif" style="background: white url($root/pics/barbers_pole.gif) top left no-repeat; background-position: ' + barberOffset + 'px 0px;">';
+
+ for (var i = 0; i < progressBars.length; i++) {
+ progressBar = progressBars[i];
+
+ if (progressBar.isBarberPole) {
+ var innerHTML = progressBar.element.innerHTML;
+ var index = innerHTML.indexOf("<img");
+ if (index != -1) {
+ progressBar.element.innerHTML = innerHTML.substr(0, index) + bar;
+ }
+ }
+
+ if (progressBar.poll > 0) {
+ progressBar.poll -= 100;
+ if (progressBar.poll <= 0) {
+ progressBar.poll = 0;
+ makeProgressRequest(progressBar);
+ }
+ }
+ }
+}
Added: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.py (rev 0)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/script.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+from os.path import getmtime, exists
+import time
+import types
+import __builtin__
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import DummyTransaction
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+try:
+ True, False
+except NameError:
+ True, False = (1==1), (1==0)
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.0rc7'
+__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 7)
+__CHEETAH_genTime__ = 1208377227.3609331
+__CHEETAH_genTimestamp__ = 'Wed Apr 16 13:20:27 2008'
+__CHEETAH_src__ = 'script.js'
+__CHEETAH_srcLastModified__ = 'Wed Apr 16 13:20:20 2008'
+__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+ raise AssertionError(
+ 'This template was compiled with Cheetah version'
+ ' %s. Templates compiled before version %s must be recompiled.'%(
+ __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class script(Template):
+
+ ##################################################
+ ## CHEETAH GENERATED METHODS
+
+
+ def __init__(self, *args, **KWs):
+
+ Template.__init__(self, *args, **KWs)
+ if not self._CHEETAH__instanceInitialized:
+ cheetahKWArgs = {}
+ allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+ for k,v in KWs.items():
+ if k in allowedKWs: cheetahKWArgs[k] = v
+ self._initCheetahInstance(**cheetahKWArgs)
+
+
+ def respond(self, trans=None):
+
+
+
+ ## CHEETAH: main method generated for this template
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+ write('''
+// progress bars
+
+var progressBars = new Array();
+var liveProgressBarTally = 0;
+var progressInterval = 0;
+
+var barberOffset = -40;
+
+
+function activateProgressBars() {
+ if (!W3CDOM) {return false;}
+
+ var query = cssQuery('span.progress');
+ for (var i = 0; i < query.length; i++) {
+ progressBar = new Object();
+ progressBar.element = query[i];
+ progressBar.isBarberPole = false;
+ progressBar.poll = -1;
+ progressBars.push(progressBar);
+ interpretProgressFromServer(progressBar);
+ }
+}
+
+registerPloneFunction(activateProgressBars);
+
+
+function interpretProgressFromServer(progressBar) {
+ var html = progressBar.element.innerHTML;
+ var oldPoll = progressBar.poll;
+
+ if (html.indexOf("barbers_pole") != -1) {
+ progressBar.isBarberPole = true;
+ progressBar.poll = 60000;
+ } else if (html.indexOf("progress_bar") != -1) {
+ progressBar.isBarberPole = false;
+ progressBar.poll = 60000;
+ } else {
+ progressBar.isBarberPole = false;
+ progressBar.poll = -1;
+ }
+
+ if (oldPoll < 0 && progressBar.poll >= 0) {
+ ++liveProgressBarTally;
+ if (liveProgressBarTally == 1) {
+ progressInterval = setInterval("animateProgressBars()", 100);
+ }
+ } else if (oldPoll >= 0 && progressBar.poll < 0) {
+ --liveProgressBarTally;
+ if (liveProgressBarTally == 0) {
+ clearInterval(progressInterval);
+ }
+ }
+}
+
+
+function makeProgressRequest(progressBar) {
+ var request = null;
+ callback = makeProgressCallback(progressBar);
+ if (typeof window.ActiveXObject != 'undefined') {
+ request = new ActiveXObject("Microsoft.XMLHTTP");
+ request.onreadystatechange = callback;
+ } else {
+ request = new XMLHttpRequest();
+ request.onload = callback;
+ }
+ var a = progressBar.element.id.split('-')
+ request.open("GET", "''')
+ _v = VFFSL(SL,"root",True) # '$root' on line 68, col 26
+ if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 68, col 26.
+ write('''/runs/" + a[1] + "/status.html", true);
+ request.send(null);
+ progressBar.request = request;
+}
+
+
+function makeProgressCallback(progressBar) {
+ function callback() {
+ request = progressBar.request;
+ if (request.readyState != 4) return;
+ progressBar.element.innerHTML = request.responseText;
+ interpretProgressFromServer(progressBar);
+ }
+ return callback;
+}
+
+
+function animateProgressBars() {
+ ++barberOffset;
+ if (barberOffset >= -20) {
+ barberOffset = -40;
+ }
+
+ var bar = '<img src="''')
+ _v = VFFSL(SL,"root",True) # '$root' on line 91, col 26
+ if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 91, col 26.
+ write('/pics/progress_box.gif" style="background: white url(')
+ _v = VFFSL(SL,"root",True) # '$root' on line 91, col 84
+ if _v is not None: write(_filter(_v, rawExpr='$root')) # from line 91, col 84.
+ write('''/pics/barbers_pole.gif) top left no-repeat; background-position: ' + barberOffset + 'px 0px;">';
+
+ for (var i = 0; i < progressBars.length; i++) {
+ progressBar = progressBars[i];
+
+ if (progressBar.isBarberPole) {
+ var innerHTML = progressBar.element.innerHTML;
+ var index = innerHTML.indexOf("<img");
+ if (index != -1) {
+ progressBar.element.innerHTML = innerHTML.substr(0, index) + bar;
+ }
+ }
+
+ if (progressBar.poll > 0) {
+ progressBar.poll -= 100;
+ if (progressBar.poll <= 0) {
+ progressBar.poll = 0;
+ makeProgressRequest(progressBar);
+ }
+ }
+ }
+}
+''')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+ ##################################################
+ ## CHEETAH GENERATED ATTRIBUTES
+
+
+ _CHEETAH__instanceInitialized = False
+
+ _CHEETAH_version = __CHEETAH_version__
+
+ _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+ _CHEETAH_genTime = __CHEETAH_genTime__
+
+ _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+ _CHEETAH_src = __CHEETAH_src__
+
+ _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+ _mainCheetahMethod_for_script= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(script, '_initCheetahAttributes'):
+ templateAPIClass = getattr(script, '_CHEETAH_templateClass', Template)
+ templateAPIClass._addCheetahPlumbingCodeToClass(script)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+ from Cheetah.TemplateCmdLineIface import CmdLineIface
+ CmdLineIface(templateObj=script()).run()
+
+
Modified: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.css
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.css 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.css 2008-04-17 19:47:51 UTC (rev 11824)
@@ -500,7 +500,7 @@
}
fieldset fieldset legend {
- font-size: normal;
+ font-size: medium;
}
form div {
Modified: cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/designs/plone/style.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -33,10 +33,10 @@
currentTime=time.time
__CHEETAH_version__ = '2.0rc7'
__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 7)
-__CHEETAH_genTime__ = 1208286939.0294361
-__CHEETAH_genTimestamp__ = 'Tue Apr 15 12:15:39 2008'
+__CHEETAH_genTime__ = 1208375419.645751
+__CHEETAH_genTimestamp__ = 'Wed Apr 16 12:50:19 2008'
__CHEETAH_src__ = 'style.css'
-__CHEETAH_srcLastModified__ = 'Tue Apr 15 12:15:34 2008'
+__CHEETAH_srcLastModified__ = 'Wed Apr 16 12:50:11 2008'
__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
@@ -591,7 +591,7 @@
}
fieldset fieldset legend {
- font-size: normal;
+ font-size: medium;
}
form div {
Modified: cs/portal/trunk/seismo/SeismoWebPortal/models.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/models.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/models.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -836,6 +836,9 @@
code = models.IntegerField(choices=CODE_CHOICES)
parameterData = models.TextField()
+ # the user who made the request
+ requestor = models.ForeignKey(User)
+
def _getParameters(self):
if not hasattr(self, '_parameters'):
import base64
@@ -874,6 +877,19 @@
started = models.DateTimeField(auto_now_add=True, editable=False)
finished = models.DateTimeField(null=True, blank=True)
+ def isDead(self):
+ return self.status in ['done', 'error']
+
+ def _getActiveJob(self):
+ if self.isDead():
+ return None
+ if not hasattr(self, '_activeJob'):
+ self._activeJob = None
+ for job in self.job_set.all():
+ self._activeJob = job
+ return self._activeJob
+ activeJob = property(_getActiveJob)
+
def outputList(self):
l = []
for job in self.job_set.all():
@@ -891,6 +907,8 @@
task = models.CharField(maxlength=100)
status = models.CharField(maxlength=100)
+ progress = models.FloatField(max_digits=19, decimal_places=10, default=-1.0)
+
created = models.DateTimeField(auto_now_add=True, editable=False)
started = models.DateTimeField(null=True, blank=True)
finished = models.DateTimeField(null=True, blank=True)
Added: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/barbers_pole.gif
===================================================================
(Binary files differ)
Property changes on: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/barbers_pole.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_bar.gif
===================================================================
(Binary files differ)
Property changes on: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_bar.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_box.gif
===================================================================
(Binary files differ)
Property changes on: cs/portal/trunk/seismo/SeismoWebPortal/static/pics/progress_box.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/job_progress_form.html
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/job_progress_form.html (rev 0)
+++ cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/job_progress_form.html 2008-04-17 19:47:51 UTC (rev 11824)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <title>Job Progress</title>
+ </head>
+
+ <body>
+
+ <h1>Job Progress</h1>
+
+ {% if form.has_errors %}
+ <p>{{ form.error_dict }}
+ {% endif %}
+
+ <form method="post" action="{{ action }}">
+
+ <p><label for="id_status">progress</label> {{ form.progress }}
+
+ <p><input type="submit" value="Save">
+
+ </form>
+
+ </body>
+</html>
Modified: cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/seismogram_table.html
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/seismogram_table.html 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/seismogram_table.html 2008-04-17 19:47:51 UTC (rev 11824)
@@ -51,22 +51,7 @@
<td>{{ ps.fmin }}</td>
<td>{{ ps.fmax }}</td>
<td>{{ ps.step }}</td>
-
- <td>
- {% if ps.request %}
- {% if ps.request.run.outputList %}
- <ul class=output>
- {% for file in ps.request.run.outputList %}
- <li><a href="{{ file.url }}">{{ file.name }}</a>
- {% endfor %}
- </ul>
- {% else %}
- {{ ps.request.run.status }}
- {% endif %}
- {% else %}
- {{ ps.requestForm }}
- {% endif %}
- </td>
+ <td>{{ ps.outputStatus }}</td>
</tr>
{% endfor %}
</tbody>
@@ -110,22 +95,7 @@
<td><img src="{{ root }}/pics/icon-{% if ps.model.ellipticity %}yes{% else %}no{% endif %}.gif" alt="{{ ps.model.ellipticity }}"></td>
<td>{{ ps.mesh }}</td>
<td><img src="{{ root }}/pics/icon-{% if ps.receivers_can_be_buried %}yes{% else %}no{% endif %}.gif" alt="{{ ps.receivers_can_be_buried }}"></td>
-
- <td>
- {% if ps.request %}
- {% if ps.request.run.outputList %}
- <ul class=output>
- {% for file in ps.request.run.outputList %}
- <li><a href="{{ file.url }}">{{ file.name }}</a>
- {% endfor %}
- </ul>
- {% else %}
- {{ ps.request.run.status }}
- {% endif %}
- {% else %}
- {{ ps.requestForm }}
- {% endif %}
- </td>
+ <td>{{ ps.outputStatus }}</td>
</tr>
{% endfor %}
</tbody>
Modified: cs/portal/trunk/seismo/SeismoWebPortal/views.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/views.py 2008-04-17 17:17:38 UTC (rev 11823)
+++ cs/portal/trunk/seismo/SeismoWebPortal/views.py 2008-04-17 19:47:51 UTC (rev 11824)
@@ -719,10 +719,50 @@
objId = intOr404(name)
if not path: raise Http404
name = path.pop(0)
- if path or name != "status": raise Http404
+ if path: raise Http404
+ if name == "status.html":
+ run = get_object_or_404(Run, id=objId)
+ return HttpResponse(runOutputStatus(run, innerHTML=True), mimetype='text/html')
+ if name != "status": raise Http404
return update_run_status(request, object_id = objId)
+def runOutputList(run):
+ html = ''
+ for file in run.outputList():
+ html += '<li><a href="%s">%s</a>' % (file.url(), file.name)
+ return '<ul class=output>%s</ul>' % html
+
+
+def runOutputStatus(run, innerHTML=False):
+
+ if run.status == 'done':
+ return runOutputList(run)
+ if run.status == 'error':
+ # NYI: separate error page
+ return '<span class=error>%s</span> %s' % (run.status, runOutputList(run))
+
+ if run.activeJob:
+ progress = run.activeJob.progress
+ else:
+ progress = -1.0
+
+ if progress >= 0.0:
+ imageWidth = 154
+ offset = imageWidth - int(float(imageWidth) * progress)
+ bar = '<img src="%s/pics/progress_box.gif" style="background: white url(%s/pics/progress_bar.gif) top left no-repeat; background-position: -%dpx 0px;">' % (
+ config.root, config.root, offset)
+ else:
+ bar = '<img src="%s/pics/progress_box.gif" style="background: white url(%s/pics/barbers_pole.gif) top left no-repeat; background-position: -40px 0px;">' % (config.root, config.root)
+
+ html = '<small>%s</small> %s' % (run.status, bar)
+ if innerHTML:
+ return html
+
+ # Wrap the status in a 'progress' span so that the JavaScript can find it.
+ return '<span id="progress-%d" class=progress>%s</span>' % (run.id, html)
+
+
def update_run_status(request, object_id):
from forms import RunStatusManipulator
import datetime
@@ -752,7 +792,7 @@
stream.write(content)
stream.close()
run.status = new_data['status']
- if run.status in ['done', 'error']:
+ if run.isDead():
run.finished = datetime.datetime.now()
if run.status == 'error':
notify_admins_of_failed_run(run)
@@ -814,23 +854,50 @@
return
+class JobProgressManipulator(forms.Manipulator):
+ def __init__(self, object_id, **kwds):
+ self.job = get_object_or_404(Job, id = object_id)
+ self.fields = [
+ forms.FloatField('progress', max_digits=19, decimal_places=10, is_required=True),
+ ]
+ return
+ def flatten_data(self):
+ return {}
+ def save(self, new_data):
+ self.job.progress = new_data['progress']
+ self.job.save()
+ return self.job
+
def jobs(request, path, desktop):
- return daemon_post(request, path, Job, "SeismoWebPortal/job_form.html")
+ follow = {'progress': False}
+ return daemon_post(request, path,
+ (Job.AddManipulator, "SeismoWebPortal/job_form.html", follow),
+ update = (Job.ChangeManipulator, "SeismoWebPortal/job_form.html", follow),
+ progress = (JobProgressManipulator, "SeismoWebPortal/job_progress_form.html", None),
+ )
def output(request, path, desktop):
- return daemon_post(request, path, OutputFile, "SeismoWebPortal/outputfile_form.html")
+ return daemon_post(request, path,
+ (OutputFile.AddManipulator, "SeismoWebPortal/outputfile_form.html", None),
+ update = (OutputFile.ChangeManipulator, "SeismoWebPortal/outputfile_form.html", None),
+ )
-def daemon_post(request, path, Model, template):
+def daemon_post(request, path, (AddManipulator, add_template, add_follow), **kwds):
if not path: raise Http404
name = path.pop(0)
if name == "create":
if path: raise Http404
- manipulator = Model.AddManipulator()
+ manipulator = AddManipulator(follow = add_follow)
+ template = add_template
action = "create"
else:
object_id = intOr404(name)
- if len(path) != 1 or path[0] != "update": raise Http404
- manipulator = Model.ChangeManipulator(object_id)
+ if len(path) != 1: raise Http404
+ name = path[0]
+ Manipulator = kwds.get(name)
+ if Manipulator is None: raise Http404
+ Manipulator, template, follow = Manipulator
+ manipulator = Manipulator(object_id, follow = follow)
action = "update"
if request.method == 'POST':
@@ -1295,13 +1362,6 @@
raise Http404
-def progressBar(percentage):
- imageWidth = 154
- offset = imageWidth - int(float(imageWidth) * percentage)
- return '<img src="%s/pics/progress_box.gif"" style="background: white url(%s/pics/progress_bar.gif) top left no-repeat; background-position: -%dpx 0px;">' % (
- config.root, config.root, offset)
-
-
def seismogramTable(workspace, url, request, path, appWindow, desktop):
from django.template import Context
@@ -1335,10 +1395,10 @@
for ps in parameterSetList[ParameterClass]:
parameters = ps.snapshot(workspace)
ps.request = None
- ps.requestForm = requestForm(workspace, ps)
+ ps.outputStatus = requestForm(workspace, ps)
for request in requests[ParameterClass.code]:
if request.parameters == parameters:
- ps.request = request
+ ps.outputStatus = runOutputStatus(request.run)
t = loader.get_template('SeismoWebPortal/seismogram_table.html')
c = Context({'root': config.root,
@@ -1357,7 +1417,7 @@
print >>html, '<input type="hidden" name="workspace" value="%d"/>' % workspace.id
print >>html, '<input type="hidden" name="code" value="%d"/>' % parameters.code
print >>html, '<input type="hidden" name="parameters" value="%d"/>' % parameters.id
- print >>html, '<input type="submit" value="Request" />'
+ print >>html, '<input type="submit" value="Request" style="font-size: small; padding: 0 0 0 0;" />'
print >>html, '</form>'
return html.getvalue()
@@ -1410,20 +1470,22 @@
else:
raise Http404
- request = Request()
+ req = Request()
event = workspace.event
- request.event = requestEventId(event)
- request.stations = workspace.stations
- request.record_length = workspace.record_length
+ req.event = requestEventId(event)
+ req.stations = workspace.stations
+ req.record_length = workspace.record_length
parameterData = parameters.snapshot(workspace)
- request.code = code
- request.parameterData = Request.encodeParameters(parameterData)
+ req.code = code
+ req.parameterData = Request.encodeParameters(parameterData)
- request.save()
+ req.requestor = request.user
+ req.save()
+
Run.objects.create(
- request = request,
+ request = req,
status = "new",
)
@@ -2249,7 +2311,9 @@
desktop.selectWindow(appWindow)
navtree = appWindow.root
url = config.root + "/admin/"
-
+
+ userIcon = img("http://www.geodynamics.org/cig/user.gif", width=16, height=16)
+
if not path:
child = gui.ChildWindow(url, "Administration")
child.content = navtree.iconView(url)
@@ -2301,7 +2365,9 @@
html = StringIO()
print >>html, '<h2>Request %04d</h2>' % objId
- print >>html, '<p class=infobar>%s</p>' % CODE_CHOICES[obj.code-1][1]
+ print >>html, '<table class=infobar width="100%%"><tr><td><b>requestor:</b> %s%s</td><td><b>code:</b> %s</td></tr></table>' % (
+ userIcon, obj.requestor.username, CODE_CHOICES[obj.code-1][1])
+ print >>html, '<p></p>'
print >>html, '<table rules="groups" class="cool">'
print >>html, '<thead>'
print >>html, '<tr><th></th><th>run</th><th>status</th><th>output</th></tr>'
@@ -2330,13 +2396,13 @@
print >>html, '<h2>Requests</h2>'
print >>html, '<table rules="groups" class="cool">'
print >>html, '<thead>'
- print >>html, '<tr><th>id</th><th>code</th><th>status</th><th>output</th></tr>'
+ print >>html, '<tr><th>id</th><th>requestor</th><th>code</th><th>status</th><th>output</th></tr>'
print >>html, '</thead>'
print >>html, '<tbody>'
for i, obj in enumerate(Request.objects.all().order_by('-id')):
id = '<a href="%s%d/">%04d</a>' % (url, obj.id, obj.id)
- print >>html, '<tr class=%s><td>%s</td><td>%s</td><td>%s</td><td>%s</td>' % (
- (i % 2 and 'even' or 'odd'), id, CODE_CHOICES[obj.code-1][1],
+ print >>html, '<tr class=%s><td>%s</td><td>%s%s</td><td>%s</td><td>%s</td><td>%s</td>' % (
+ (i % 2 and 'even' or 'odd'), id, userIcon, obj.requestor.username, CODE_CHOICES[obj.code-1][1],
obj.run.status, runOutputList(obj.run)
)
print >>html, '</tbody>'
@@ -2357,7 +2423,7 @@
users = User.objects.all()
- icon = img("http://www.geodynamics.org/cig/user.gif", width=16, height=16)
+ na = '<span class=notApplicable>n/a</span>'
html = StringIO()
print >>html, '<h2>Users</h2>'
@@ -2369,10 +2435,14 @@
print >>html, '</thead>'
print >>html, '<tbody>'
for i, user in enumerate(users):
+ try:
+ invite, approved = user.userinfo.invite, yesNo(user.userinfo.approved)
+ except UserInfo.DoesNotExist:
+ invite, approved = na, na
print >>html, ('<tr class=%s><td>%s%s</td><td>%s</td><td>%s</td><td>%s</td>' +
'<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>') % (
- (i % 2 and 'even' or 'odd'), icon, user.username, mailto(user.email), user.first_name, user.last_name,
- yesNo(user.is_staff), user.userinfo.invite, yesNo(user.userinfo.approved), user.last_login.date())
+ (i % 2 and 'even' or 'odd'), userIcon, user.username, mailto(user.email), user.first_name, user.last_name,
+ yesNo(user.is_staff), invite, approved, user.last_login.date())
print >>html, '</tbody>'
print >>html, '</table>'
More information about the cig-commits
mailing list