Author: justi9
Date: 2008-03-06 23:59:23 -0500 (Thu, 06 Mar 2008)
New Revision: 1769
Modified:
mgmt/Makefile
mgmt/cumin/python/cumin/broker.py
mgmt/cumin/python/cumin/broker.strings
mgmt/cumin/python/cumin/queue.py
mgmt/cumin/python/cumin/queue.strings
mgmt/cumin/python/cumin/widgets.py
mgmt/cumin/python/cumin/widgets.strings
mgmt/cumin/python/wooly/__init__.py
mgmt/cumin/python/wooly/__init__.strings
mgmt/cumin/python/wooly/forms.py
mgmt/cumin/python/wooly/forms.strings
mgmt/cumin/python/wooly/server.py
mgmt/misc/boneyard.py
mgmt/misc/boneyard.strings
Log:
Phase 1 of the form overhaul.
Takes the error attr and error renderering off of Widget. That was
dubious idea to start with.
Introduces form fields, a type of form in put with a title, a slot for
errors, and which can server in a special kind of field-oriented form.
Moves some dead code to the boneyard.
Modified: mgmt/Makefile
===================================================================
--- mgmt/Makefile 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/Makefile 2008-03-07 04:59:23 UTC (rev 1769)
@@ -1,5 +1,8 @@
-.PHONY: dist clean
+.PHONY: help dist clean
+help:
+ @echo Targets: dist, clean, tags
+
dist: clean
mkdir -p dist/lib/python/mint
mkdir -p dist/lib/python/wooly
Modified: mgmt/cumin/python/cumin/broker.py
===================================================================
--- mgmt/cumin/python/cumin/broker.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/broker.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -143,9 +143,6 @@
self.add_mode(self.remove)
self.set_remove_mode(self.remove)
- self.prop = BrokerConfigPropertyForm(app, "prop")
- self.add_mode(self.prop)
-
self.queue = QueueFrame(app, "queue")
self.add_mode(self.queue)
@@ -161,11 +158,6 @@
self.clients_close = ClientSetClose(app, "clientsclose")
self.add_mode(self.clients_close)
- def show_config_property(self, session, prop):
- self.prop.set_config_property(session, prop)
- self.page().set_current_frame(session, self.prop)
- return self.show_mode(session, self.prop)
-
def show_queue(self, session, queue):
self.queue.set_object(session, queue)
self.page().set_current_frame(session, self.queue)
@@ -192,87 +184,6 @@
def get_title(self, session, broker):
return "Broker '%s'" % broker.name
-class BrokerConfigPropertyForm(CuminForm, Frame):
- def __init__(self, app, name):
- super(BrokerConfigPropertyForm, self).__init__(app, name)
-
- self.param = ConfigPropertyParameter(app, "param")
- self.add_parameter(self.param)
-
- self.source = Parameter(app, "source")
- self.source.set_default("local")
- self.add_parameter(self.source)
-
- self.profile = RadioInput(app, "profile", self)
- self.profile.set_parameter(self.source)
- self.profile.set_value("profile")
- self.add_child(self.profile)
-
- self.pvalue = TextInput(app, "profile_value", self)
- self.pvalue.set_disabled(True)
- self.add_child(self.pvalue)
-
- self.broker = RadioInput(app, "broker", self)
- self.broker.set_parameter(self.source)
- self.broker.set_value("broker")
- self.add_child(self.broker)
-
- self.svalue = TextInput(app, "broker_value", self)
- self.svalue.set_disabled(True)
- self.add_child(self.svalue)
-
- self.local = RadioInput(app, "local", self)
- self.local.set_parameter(self.source)
- self.local.set_value("local")
- self.add_child(self.local)
-
- self.lvalue = TextInput(app, "local_value", self)
- self.add_child(self.lvalue)
-
- def get_title(self, session, prop):
- return "Edit Property '%s'" % prop.name
-
- def get_object(self, session, object):
- return self.param.get(session)
-
- def set_config_property(self, session, prop):
- return self.param.set(session, prop)
-
- def process_cancel(self, session, prop):
- branch = session.branch()
- self.page().show_broker(branch, prop.get_broker()).show_view(branch)
- self.page().set_redirect_url(session, branch.marshal())
-
- def process_submit(self, session, prop):
- source = self.source.get(session)
-
- if source == "profile":
- prop.value = get_profile_value(prop)
- elif source == "broker":
- prop.value = prop.broker_value
- elif source == "local":
- prop.value = self.lvalue.get(session)
- else:
- raise Exception()
-
- self.process_cancel(session, prop)
-
- def process_display(self, session, prop):
- self.pvalue.set(session, get_profile_value(prop))
- self.svalue.set(session, prop.broker_value)
- self.lvalue.set(session, prop.value)
-
-def get_profile_value(prop):
- profile = prop.get_broker().get_broker_profile()
- value = None
-
- if profile:
- for p in profile.config_property_items():
- if p.name == prop.name:
- value = p.value
-
- return value
-
class BrokerStatus(CuminStatus):
pass
@@ -297,10 +208,6 @@
self.tabs.add_tab(self.BrokerQueueTab(app, "queues"))
self.tabs.add_tab(self.BrokerExchangeTab(app, "exchanges"))
self.tabs.add_tab(self.BrokerClientTab(app, "clients"))
- #self.config = self.BrokerConfigTab(app, "config")
- #self.tabs.add_tab(self.config)
- #self.tabs.add_tab(self.BrokerStatsTab(app, "stats"))
- #self.tabs.add_tab(self.BrokerLogTab(app, "log"))
self.missing = self.BrokerMissing(app, "missing")
self.body.add_mode(self.missing)
@@ -319,8 +226,7 @@
def do_process(self, session, reg):
if reg.broker:
- vhost = Vhost.selectBy(broker=reg.broker, name="/")[0]
- self.vhost.set(session, vhost)
+ self.vhost.set(session, reg.getDefaultVhost())
else:
self.body.show_mode(session, self.missing)
@@ -363,15 +269,25 @@
else:
return fmt_none()
- class BrokerQueueTab(QueueSet):
+ class BrokerQueueTab(Widget):
+ def __init__(self, app, name):
+ super(BrokerView.BrokerQueueTab, self).__init__(app, name)
+
+ self.__queues = QueueSet(app, "items")
+ self.add_child(self.__queues)
+
def get_object(self, session, reg):
return self.parent.parent.parent.vhost.get(session)
- def get_title(self, session, broker):
- vhost = self.parent.parent.parent.vhost.get(session)
- return super(BrokerView.BrokerQueueTab, self).get_title \
- (session, vhost)
+ def get_title(self, session, reg):
+ vhost = reg.getDefaultVhost()
+ return "Queues %s" % fmt_count(vhost.queues.count())
+ def render_add_queue_href(self, session, object):
+ branch = session.branch()
+ self.frame().show_queue(branch, None).show_add(branch)
+ return branch.marshal()
+
class BrokerExchangeTab(ExchangeSet):
def get_object(self, session, reg):
return self.parent.parent.parent.vhost.get(session)
@@ -390,33 +306,6 @@
return super(BrokerView.BrokerClientTab, self).get_title \
(session, vhost)
- class BrokerConfigTab(ConfigPropertySet):
- def get_title(self, session, broker):
- return "Configuration"
-
- def do_get_items(self, session, broker):
- return broker.properties
-
- def maybe_highlight(self, value, comparedto):
- if str(value) != str(comparedto):
- value = "<span class=\"BrokerConfigTab
diff\">%s</span>" \
- % value
-
- return value
-
- def render_item_broker_value(self, session, prop):
- return self.maybe_highlight(prop.broker_value, prop.value)
-
- def render_item_profile_value(self, session, prop):
- value = get_profile_value(prop)
- return self.maybe_highlight(value, prop.value)
-
- def render_item_edit_href(self, session, prop):
- branch = session.branch()
- frame = self.page().show_broker(branch, prop.get_broker())
- frame.show_config_property(branch, prop)
- return branch.marshal()
-
class BrokerStatsTab(Widget):
def get_title(self, session, broker):
return "Statistics"
Modified: mgmt/cumin/python/cumin/broker.strings
===================================================================
--- mgmt/cumin/python/cumin/broker.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/broker.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -39,87 +39,6 @@
{hidden_inputs}
</form>
-[BrokerConfigTab.css]
-.BrokerConfigTab.diff {
- background-color: #ff9;
-}
-
-[BrokerSetGroupInput.html]
-<select name="{name}" tabindex="{tab_index}" {disabled_attr}
onchange="getElementById('{submit_id}').click()">
- <option value="">Choose Group...</option>
- {items}
-</select>
-
-[BrokerConfigTab.html]
-<ul class="actions">
- <li><a class="nav" href="{href}">Add
Property</a></li>
- <li><a href="{href}">Apply Configuration to
Broker</a></li>
-</ul>
-
-<table class="mobjects">
- <tr>
- <th>Name</th>
- <th>Configured Value</th>
- <th>Broker Value</th>
- <th>Profile Value</th>
- <th></th>
- </tr>
-
- {items}
-</table>
-
-[BrokerConfigTab.item_html]
-<tr>
- <td>{item_name}</td>
- <td>{item_value}</td>
- <td>{item_broker_value}</td>
- <td>{item_profile_value}</td>
- <td><a class="action"
href="{item_edit_href}">Edit</a></td>
-</tr>
-
-[BrokerConfigPropertyForm.css]
-.BrokerConfigPropertyForm div.value {
- margin: 1em 2em;
-}
-
-[BrokerConfigPropertyForm.html]
-<form id="{id}" class="BrokerConfigPropertyForm mform"
method="post" action="?">
- <div class="head">
- <h1>{title}</h1>
- </div>
- <div class="body">
- <span class="legend">Value</span>
- <fieldset>
- <div class="field">
- {profile} Use the value from the broker profile
- <div class="value">{profile_value}</div>
- </div>
- <div class="field">
- {broker} Use the value currently set on the broker
- <div class="value">{broker_value}</div>
- </div>
- <div class="field">
- {local} Set a new value
- <div class="value">{local_value}</div>
- </div>
- </fieldset>
-
- {hidden_inputs}
- </div>
- <div class="foot">
- <div style="float:
left;"><button>Help</button></div>
- {submit}
- {cancel}
- </div>
-</form>
-<script defer="defer">
-(function() {
- var elem = wooly.doc().elembyid("{id}").node.elements[1];
- elem.focus();
- elem.select();
-}())
-</script>
-
[BrokerView.javascript]
function updateBroker(data) {
var model = data.objectify();
@@ -172,6 +91,13 @@
window.setInterval(updateTimer, 1000);
</script>
+[BrokerQueueTab.html]
+<ul class="actions">
+ <li><a class="nav" href="{add_queue_href}">Add
Queue</a></li>
+</ul>
+
+{items}
+
[BrokerBrowser.html]
<table class="browser">
<tr>
Modified: mgmt/cumin/python/cumin/queue.py
===================================================================
--- mgmt/cumin/python/cumin/queue.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/queue.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -1,3 +1,5 @@
+import pdb
+
from mint import *
from wooly import *
from wooly.widgets import *
@@ -58,7 +60,7 @@
self.add_child(self.__purge)
def get_title(self, session, vhost):
- return "Queues %s" % fmt_count(vhost.queues.count())
+ return "Queues %s" % fmt_count(Queue.select().count())
def render_sql_where(self, session, vhost):
elems = list()
@@ -167,6 +169,10 @@
self.add_mode(self.view)
self.set_view_mode(self.view)
+ self.add = QueueAdd(app, "add")
+ self.add_mode(self.add)
+ self.set_add_mode(self.add)
+
self.purge = QueuePurge(app, "purge")
self.add_mode(self.purge)
@@ -181,7 +187,10 @@
return queue
def get_title(self, session, queue):
- return "Queue '%s'" % queue.name
+ if queue:
+ return "Queue '%s'" % queue.name
+ else:
+ return "Queue"
class QueueStatus(CuminStatus):
def render_consumers(self, session, queue):
@@ -289,124 +298,41 @@
def render_item_name(self, session, binding):
return binding.exchange.name or "<em>Default</em>"
-class QueueForm(CuminForm):
+class QueueForm(CuminFieldForm, Frame):
def __init__(self, app, name):
super(QueueForm, self).__init__(app, name)
- self.queue_name = TextInput(app, "queue_name", self)
- self.add_child(self.queue_name)
+ self.namef = NameField(app, "name", self)
+ self.add_field(self.namef)
- self.latency_priority = Parameter(app, "tuning")
- self.latency_priority.set_default("m")
- self.add_parameter(self.latency_priority)
+ self.durable = DurabilityField(app, "durable", self)
+ self.add_field(self.durable)
- self.latency = RadioInput(app, "latency", self)
- self.latency.set_parameter(self.latency_priority)
- self.latency.set_value("h")
- self.add_child(self.latency)
-
- self.balanced = RadioInput(app, "balanced", self)
- self.balanced.set_parameter(self.latency_priority)
- self.balanced.set_value("m")
- self.add_child(self.balanced)
-
- self.throughput = RadioInput(app, "throughput", self)
- self.throughput.set_parameter(self.latency_priority)
- self.throughput.set_value("l")
- self.add_child(self.throughput)
-
- def validate(self, session):
- error = None
-
- name = self.queue_name.get(session)
-
- if name == "":
- error = EmptyInputError(self.queue_name)
- self.queue_name.add_error(session, error)
- elif " " in name:
- error = Error("""
- The queue name is invalid; allowed characters are
- letters, digits, ".", and "_"
- """)
- self.queue_name.add_error(session, error)
-
- return error is None
-
class QueueAdd(QueueForm):
- def process_cancel(self, session, vhost):
- branch = session.branch()
- self.page().show_broker(branch, vhost.broker).show_view(branch)
- self.page().set_redirect_url(session, branch.marshal())
+ def process_submit(self, session, object):
+ errors = self.validate(session)
- def process_submit(self, session, vhost):
- if self.validate(session):
- queue = Queue()
- queue.name = self.queue_name.get(session)
+ if errors:
+ pass
+ else:
+ reg = self.frame().frame().get_object(session, None)
+ vhost = reg.getDefaultVhost()
- vhost.addQueue(queue)
+ name = self.namef.get(session)
+ durable = self.durable.get(session)
+
+ print "XXX add queue", name, self.durable.get(session)
branch = session.branch()
- self.page().show_queue(branch, queue).show_view(branch)
+ #self.frame().frame().show_queue(branch, queue).show_view(branch)
+ self.page().pop_current_frame(branch)
+ self.page().pop_current_frame(branch).show_view(branch)
self.page().set_redirect_url(session, branch.marshal())
- def get_title(self, session, vhost):
- return "Add Queue to Host Template '%s'" % vhost.name
-
-class QueueEdit(QueueForm):
- def process_cancel(self, session, queue):
- branch = session.branch()
- self.page().show_queue(branch, queue).show_view(branch)
- self.page().set_redirect_url(session, branch.marshal())
+ def get_title(self, session, object):
+ reg = self.frame().frame().get_object(session, None)
+ return "Add Queue to Broker '%s'" % reg.name
- def process_submit(self, session, queue):
- if self.validate(session):
- queue.lock()
- try:
- queue.name = self.queue_name.get(session)
- queue.latency_priority = self.latency_priority.get(session)
- finally:
- queue.unlock()
-
- branch = session.branch()
- self.page().show_queue(branch, queue).show_view(branch)
- self.process_cancel(session, queue)
-
- def process_display(self, session, queue):
- self.queue_name.set(session, queue.name)
- self.latency_priority.set(session, queue.latency_priority)
-
- def get_title(self, session, queue):
- return "Edit Queue '%s'" % queue.name
-
-class QueueRemove(CuminConfirmForm):
- def get_title(self, session, queue):
- return "Remove Queue '%s'" % queue.name
-
- def process_cancel(self, session, queue):
- branch = session.branch()
- self.page().show_queue(branch, queue).show_view(branch)
- self.page().set_redirect_url(session, branch.marshal())
-
- def process_submit(self, session, queue):
- vhost = queue.get_virtual_host()
-
- queue.remove()
-
- branch = session.branch()
- self.page().show_broker(branch, vhost.get_broker()).show_view(branch)
- self.page().set_redirect_url(session, branch.marshal())
-
- def render_submit_content(self, session, queue):
- return "Yes, Remove Queue '%s'" % queue.name
-
- def render_cancel_content(self, session, queue):
- return "No, Cancel"
-
-def doit(error, args):
- pass
- #print error, args
- #print "did it!"
-
class QueuePurge(CuminConfirmForm):
def get_title(self, session, queue):
return "Purge Queue '%s'" % queue.name
Modified: mgmt/cumin/python/cumin/queue.strings
===================================================================
--- mgmt/cumin/python/cumin/queue.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/queue.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -59,50 +59,6 @@
{hidden_inputs}
</form>
-[QueueForm.html]
-<form id="{id}" class="mform" method="post"
action="?">
- <div class="head">
- <h1>{title}</h1>
- </div>
- <div class="body">
- <span class="legend">Name</span>
- <fieldset>
- <div class="field">{queue_name}</div>
- </fieldset>
-
- <span class="legend">Latency Tuning</span>
- <fieldset>
- <div class="field">
- {latency}
- <em>Lower Latency:</em> Tune for shorter delays, with reduced volume
- </div>
- <div class="field">
- {balanced}
- <em>Balanced</em>
- </div>
- <div class="field">
- {throughput}
- <em>Higher Throughput:</em> Tune for increased volume, with longer
- delays
- </div>
- </fieldset>
-
- {hidden_inputs}
- </div>
- <div class="foot">
- <div style="display: block; float:
left;"><button>Help</button></div>
- {submit}
- {cancel}
- </div>
-</form>
-<script defer="defer">
-(function() {
- var elem = wooly.doc().elembyid("{id}").node.elements[1];
- elem.focus();
- elem.select();
-}())
-</script>
-
[QueueStatus.javascript]
function updateQueueStatus(id, queue) {
updateStatus(id, queue);
Modified: mgmt/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/cumin/python/cumin/widgets.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/widgets.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -149,6 +149,9 @@
def render_content(self, session, object):
return self.parent.render_submit_content(session, object)
+class CuminFieldForm(CuminForm, FieldForm):
+ pass
+
class CuminConfirmForm(CuminForm):
def __init__(self, app, name):
super(CuminConfirmForm, self).__init__(app, name)
@@ -526,3 +529,59 @@
def render_elem_name(self, session, object):
return self.column.ids.path()
+
+class NameField(StringField):
+ def __init__(self, app, name, form):
+ super(NameField, self).__init__(app, name, form)
+
+ self.required = True
+ self.illegal_chars = ""
+ self.legal_chars_desc = None
+
+ def get_title(self, session, object):
+ return "Name"
+
+ def do_validate(self, session, errors):
+ name = self.get(session)
+
+ if name == "":
+ errors.append(MissingValueError())
+ else:
+ for char in self.illegal_chars:
+ if char in name:
+ msg = "The name contains illegal characters"
+ if self.legal_chars_desc:
+ msg = msg + "; " + self.legal_chars_desc
+
+ errors.append(Error(msg))
+
+ break
+
+class DurabilityField(RadioField):
+ def __init__(self, app, name, form):
+ super(DurabilityField, self).__init__(app, name, form)
+
+ param = Parameter(app, "param")
+ param.default = "durable"
+ self.add_parameter(param)
+ self.set_parameter(param)
+
+ self.add_option(self.Durable(app, "durable", form))
+ self.add_option(self.Transient(app, "transient", form))
+
+ def get_title(self, session, object):
+ return "Durable?"
+
+ class Durable(RadioFieldOption):
+ def get_value(self, session, object):
+ return "durable"
+
+ def get_title(self, session, object):
+ return "Durable"
+
+ class Transient(RadioFieldOption):
+ def get_value(self, session, object):
+ return "transient"
+
+ def get_title(self, session, object):
+ return "Transient"
Modified: mgmt/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/cumin/python/cumin/widgets.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/cumin/widgets.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -1,3 +1,17 @@
+[CuminFieldForm.html]
+<form id="{id}" class="mform" method="post"
action="?">
+ <div class="head">{title}</div>
+ <div class="body">{fields}</div>
+ <div class="foot">
+ {submit}
+ {cancel}
+ </div>
+ {hidden_inputs}
+</form>
+<script>
+ wooly.doc().elembyid("{id}").node.elements[0].focus();
+</script>
+
[CuminConfirmForm.html]
<form id="{id}" class="mform" method="post"
action="?">
<div class="head">
Modified: mgmt/cumin/python/wooly/__init__.py
===================================================================
--- mgmt/cumin/python/wooly/__init__.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/wooly/__init__.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -101,12 +101,7 @@
self.html_class = None
self.__main_tmpl = Template(self, "html")
- self.__errors_tmpl = Template(self, "errors_html")
- self.__error_message_tmpl = Template(self, "error_message_html")
- self.__errors = self.ErrorsAttribute(app, "errors")
- self.add_attribute(self.__errors)
-
self.args = self.ArgsAttribute(app, "args")
self.add_attribute(self.args)
@@ -123,10 +118,6 @@
if cls is Widget:
break
- class ErrorsAttribute(Attribute):
- def get_default(self, session):
- return list()
-
class ArgsAttribute(Attribute):
def get_default(self, session):
if self.widget.parent:
@@ -219,12 +210,6 @@
if str:
return str
- def get_errors(self, session):
- return self.__errors.get(session)
-
- def add_error(self, session, error):
- self.__errors.get(session).append(error)
-
def get(self, session, name):
return self.args.get(session).get(name)
@@ -306,25 +291,6 @@
return writer.to_string()
- def render_errors(self, session, object):
- writer = Writer()
-
- if self.get_errors(session):
- self.__errors_tmpl.render(session, object, writer)
-
- return writer.to_string()
-
- def render_error_messages(self, session, object):
- writer = Writer()
-
- for error in self.get_errors(session):
- self.__error_message_tmpl.render(session, error, writer)
-
- return writer.to_string()
-
- def render_error_message(self, session, error):
- return error.message
-
def prt(self):
print self
@@ -666,6 +632,13 @@
return "%s(trunk=%s,app=%s)" % \
(self.__class__.__name__, self.trunk, self.app)
+class Error(object):
+ def __init__(self, message=None):
+ self.message = message
+
+ def get_message(self, session):
+ return self.message
+
class StringIOWriter(object):
def __init__(self):
self.writer = StringIO()
@@ -693,10 +666,6 @@
class Writer(StringIOWriter):
pass
-class Error(object):
- def __init__(self, message):
- self.message = message
-
class Template(object):
def __init__(self, widget, key):
self.widget = widget
Modified: mgmt/cumin/python/wooly/__init__.strings
===================================================================
--- mgmt/cumin/python/wooly/__init__.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/wooly/__init__.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -1,8 +1,2 @@
[Widget.html]
{content}
-
-[Widget.errors_html]
-<ul class="errors">{error_messages}</ul>
-
-[Widget.error_message_html]
-<li>{error_message}</li>
Modified: mgmt/cumin/python/wooly/forms.py
===================================================================
--- mgmt/cumin/python/wooly/forms.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/wooly/forms.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -74,7 +74,7 @@
return self.param.get_default(session)
def set_default(self, default):
- self.param.set_default(default)
+ return self.param.set_default(default)
def set_tab_index(self, tab_index):
self.tab_index = tab_index
@@ -94,12 +94,17 @@
def render_disabled_attr(self, session, object):
return self.disabled and "disabled=\"disabled\"" or None
+class MissingValueError(Error):
+ def get_message(self, session):
+ return "This value is required"
+
class EmptyInputError(Error):
- def __init__(self, input):
- message = "Input '%s' is empty; it is required" % input.name
+ def __init__(self):
+ message = "This value is required"
super(EmptyInputError, self).__init__(message)
+# XXX rename to ScalarInput. it's less confusing v-a-v StringInput
class TextInput(FormInput):
def __init__(self, app, name, form):
super(TextInput, self).__init__(app, name, form)
@@ -151,16 +156,20 @@
self.value = None
- def set_value(self, value):
+ def xxx_set_value(self, value):
self.value = value
+ def get_value(self, session, object):
+ pass
+
def render_value(self, session, object):
- return self.value
+ return self.get_value(session, object)
def render_checked_attr(self, session, object):
value = self.get(session)
- return value and value == self.value and
"checked=\"checked\""
+ if value and value == self.get_value(session, object):
+ return "checked=\"checked\""
class FormButton(FormInput):
def __init__(self, app, name, form):
@@ -205,3 +214,170 @@
def render_item_selected_attr(self, session, object):
return None
+
+class FieldSet(Widget):
+ def __init__(self, app, name):
+ super(FieldSet, self).__init__(app, name)
+
+ self.fields = list()
+
+ def add_field(self, field):
+ assert isinstance(field, FormField)
+
+ self.fields.append(field)
+ self.add_child(field)
+
+ def render_fields(self, session, object):
+ writer = Writer()
+
+ for field in self.fields:
+ writer.write(field.render(session, object))
+
+ return writer.to_string()
+
+class FormField(Widget):
+ def __init__(self, app, name, form):
+ super(FormField, self).__init__(app, name)
+
+ self.__form = form
+ self.__param = None
+
+ self.__errors = FormFieldErrors(app, "errors")
+ self.add_child(self.__errors)
+
+ def get_parameter(self):
+ return self.__param
+
+ def set_parameter(self, param):
+ assert isinstance(param, Parameter)
+
+ self.__param = param
+ return param
+
+ def get(self, session):
+ return self.__param.get(session)
+
+ def set(self, session, value):
+ return self.__param.set(session, value)
+
+ def validate(self, session):
+ errors = self.__errors.attr.get(session)
+
+ self.do_validate(session, errors)
+
+ return errors
+
+ def do_validate(self, session, errors):
+ pass
+
+ def render_errors(self, session, object):
+ if self.__errors.attr.get(session):
+ return self.__errors.render(session, object)
+
+class FormFieldErrors(ItemSet):
+ def __init__(self, app, name):
+ super(FormFieldErrors, self).__init__(app, name)
+
+ self.attr = self.Errors(app, "attr")
+ self.add_attribute(self.attr)
+
+ def get_items(self, session, object):
+ return self.attr.get(session)
+
+ def render_item_content(self, session, item):
+ return item.get_message(session)
+
+ class Errors(Attribute):
+ def get_default(self, session):
+ return list()
+
+class ScalarField(FormField):
+ def __init__(self, app, name, form):
+ super(ScalarField, self).__init__(app, name, form)
+
+ self.__input = None
+
+ def get_input(self):
+ return self.__input
+
+ def set_input(self, input):
+ assert isinstance(input, FormInput)
+
+ self.set_parameter(input.get_parameter())
+ self.__input = input
+ return input
+
+ def render_content(self, session, object):
+ return self.__input.render(session, object)
+
+class StringField(ScalarField):
+ def __init__(self, app, name, form):
+ super(StringField, self).__init__(app, name, form)
+
+ input = TextInput(app, "input", form)
+ self.add_child(input)
+ self.set_input(input)
+
+class IntegerField(ScalarField):
+ def __init__(self, app, name, form):
+ super(IntegerInputField, self).__init__(app, name, form)
+
+ input = Integer(app, "input", form)
+ self.add_child(input)
+ self.set_input(input)
+
+class RadioField(FormField):
+ def __init__(self, app, name, form):
+ super(RadioField, self).__init__(app, name, form)
+
+ self.options = list()
+
+ def add_option(self, option):
+ assert isinstance(option, RadioFieldOption)
+
+ option.set_parameter(self.get_parameter())
+ self.options.append(option)
+ self.add_child(option)
+
+ def render_content(self, session, object):
+ writer = Writer()
+
+ for option in self.options:
+ writer.write(option.render(session, object))
+
+ return writer.to_string()
+
+class RadioFieldOption(RadioInput):
+ pass
+
+class ButtonForm(Form):
+ def __init__(self, app, name):
+ super(ButtonForm. self).__init__(app, name)
+
+ self.buttons = list()
+
+ def add_button(self, button):
+ assert type(button) is FormButton
+
+ self.buttons.append(button)
+ self.add_child(button)
+
+ def render_buttons(self, session, object):
+ writer = Writer()
+
+ for button in self.buttons:
+ writer.write(button.render(session, object))
+
+ return writer.to_string()
+
+class FieldForm(Form, FieldSet):
+ def __init__(self, app, name):
+ super(FieldForm, self).__init__(app, name)
+
+ def validate(self, session):
+ errors = list()
+
+ for field in self.fields:
+ errors.extend(field.validate(session))
+
+ return errors
Modified: mgmt/cumin/python/wooly/forms.strings
===================================================================
--- mgmt/cumin/python/wooly/forms.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/wooly/forms.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -2,7 +2,6 @@
<button class="{class}" id="{id}" type="submit"
name="{name}" value="{value}" tabindex="{tab_index}"
{disabled_attr}>{content}</button>
[TextInput.html]
-{errors}
<input type="text" name="{name}" value="{value}"
tabindex="{tab_index}" {disabled_attr} size="{size}"/>
[CheckboxInput.html]
@@ -12,22 +11,67 @@
<input type="radio" name="{name}" value="{value}"
tabindex="{tab_index}" {checked_attr} {disabled_attr}/>
[CheckboxInputSet.html]
-{errors}{items}
+{items}
[CheckboxInputSet.item_html]
<input type="checkbox" name="{name}"
value="{item_value}" tabindex="{tab_index}" {item_checked_attr}
{disabled_attr}/>
{item_content}
[RadioInputSet.html]
-{errors}{items}
+{items}
[RadioInputSet.item_html]
<input type="radio" name="{name}" value="{item_value}"
tabindex="{tab_index}" {item_checked_attr} {disabled_attr}/>
{item_content}
[OptionInputSet.html]
-{errors}
<select name="{name}" tabindex="{tab_index}"
{disabled_attr}>{items}</select>
[OptionInputSet.item_html]
<option value="{item_value}"
{item_selected_attr}>{item_content}</option>
+
+[FieldSet.html]
+<div class="fieldset">
+ <div class="title">{title}</div>
+ <div class="fields">{fields}</div>
+</div>
+
+[FormField.css]
+div.field {
+ padding: 0;
+ margin: 0;
+}
+
+div.field div.title {
+ font-weight: bold;
+ margin: 0 0 1em 0;
+}
+
+div.field div.content {
+ margin: 0 0 1em 1em;
+}
+
+[FormField.html]
+<div class="field">
+ <div class="title">{title}</div>
+ {errors}
+ <div class="content">{content}</div>
+</div>
+
+[FormFieldErrors.html]
+<ul class="errors">{items}</ul>
+
+[FormFieldErrors.item_html]
+<li>{item_content}</li>
+
+[RadioFieldOption.html]
+<div>
+ <input type="radio" name="{name}" value="{value}"
+ tabindex="{tab_index}" {checked_attr} {disabled_attr}/>
+ {title}
+</div>
+
+[FieldForm.html]
+<form id="{id}">
+ {fields}
+</form>
Modified: mgmt/cumin/python/wooly/server.py
===================================================================
--- mgmt/cumin/python/wooly/server.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/cumin/python/wooly/server.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -32,11 +32,6 @@
self.__server.stop()
def service(self, env, respond):
- if False and env["PATH_INFO"].endswith(".html"):
- print "------------------------------------"
- for key in sorted(env):
- print key, env[key]
-
session = Session(self.app)
session.unmarshal_page(env["PATH_INFO"])
session.unmarshal_url_vars(env["QUERY_STRING"])
Modified: mgmt/misc/boneyard.py
===================================================================
--- mgmt/misc/boneyard.py 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/misc/boneyard.py 2008-03-07 04:59:23 UTC (rev 1769)
@@ -138,3 +138,111 @@
def render_none(self, session, model):
return none()
+
+class BrokerConfigPropertyForm(CuminForm, Frame):
+ def __init__(self, app, name):
+ super(BrokerConfigPropertyForm, self).__init__(app, name)
+
+ self.param = ConfigPropertyParameter(app, "param")
+ self.add_parameter(self.param)
+
+ self.source = Parameter(app, "source")
+ self.source.set_default("local")
+ self.add_parameter(self.source)
+
+ self.profile = RadioInput(app, "profile", self)
+ self.profile.set_parameter(self.source)
+ self.profile.set_value("profile")
+ self.add_child(self.profile)
+
+ self.pvalue = TextInput(app, "profile_value", self)
+ self.pvalue.set_disabled(True)
+ self.add_child(self.pvalue)
+
+ self.broker = RadioInput(app, "broker", self)
+ self.broker.set_parameter(self.source)
+ self.broker.set_value("broker")
+ self.add_child(self.broker)
+
+ self.svalue = TextInput(app, "broker_value", self)
+ self.svalue.set_disabled(True)
+ self.add_child(self.svalue)
+
+ self.local = RadioInput(app, "local", self)
+ self.local.set_parameter(self.source)
+ self.local.set_value("local")
+ self.add_child(self.local)
+
+ self.lvalue = TextInput(app, "local_value", self)
+ self.add_child(self.lvalue)
+
+ def get_title(self, session, prop):
+ return "Edit Property '%s'" % prop.name
+
+ def get_object(self, session, object):
+ return self.param.get(session)
+
+ def set_config_property(self, session, prop):
+ return self.param.set(session, prop)
+
+ def process_cancel(self, session, prop):
+ branch = session.branch()
+ self.page().show_broker(branch, prop.get_broker()).show_view(branch)
+ self.page().set_redirect_url(session, branch.marshal())
+
+ def process_submit(self, session, prop):
+ source = self.source.get(session)
+
+ if source == "profile":
+ prop.value = get_profile_value(prop)
+ elif source == "broker":
+ prop.value = prop.broker_value
+ elif source == "local":
+ prop.value = self.lvalue.get(session)
+ else:
+ raise Exception()
+
+ self.process_cancel(session, prop)
+
+ def process_display(self, session, prop):
+ self.pvalue.set(session, get_profile_value(prop))
+ self.svalue.set(session, prop.broker_value)
+ self.lvalue.set(session, prop.value)
+
+class BrokerConfigTab(ConfigPropertySet):
+ def get_title(self, session, broker):
+ return "Configuration"
+
+ def do_get_items(self, session, broker):
+ return broker.properties
+
+ def maybe_highlight(self, value, comparedto):
+ if str(value) != str(comparedto):
+ value = "<span class=\"BrokerConfigTab
diff\">%s</span>" \
+ % value
+
+ return value
+
+ def render_item_broker_value(self, session, prop):
+ return self.maybe_highlight(prop.broker_value, prop.value)
+
+ def render_item_profile_value(self, session, prop):
+ value = get_profile_value(prop)
+ return self.maybe_highlight(value, prop.value)
+
+ def render_item_edit_href(self, session, prop):
+ branch = session.branch()
+ frame = self.page().show_broker(branch, prop.get_broker())
+ frame.show_config_property(branch, prop)
+ return branch.marshal()
+
+def get_profile_value(prop):
+ profile = prop.get_broker().get_broker_profile()
+ value = None
+
+ if profile:
+ for p in profile.config_property_items():
+ if p.name == prop.name:
+ value = p.value
+
+ return value
Modified: mgmt/misc/boneyard.strings
===================================================================
--- mgmt/misc/boneyard.strings 2008-03-07 00:34:26 UTC (rev 1768)
+++ mgmt/misc/boneyard.strings 2008-03-07 04:59:23 UTC (rev 1769)
@@ -80,3 +80,84 @@
[ClusterBrowser.item_html]
<li>{item_link}</li>
+
+[BrokerConfigTab.css]
+.BrokerConfigTab.diff {
+ background-color: #ff9;
+}
+
+[BrokerSetGroupInput.html]
+<select name="{name}" tabindex="{tab_index}" {disabled_attr}
onchange="getElementById('{submit_id}').click()">
+ <option value="">Choose Group...</option>
+ {items}
+</select>
+
+[BrokerConfigTab.html]
+<ul class="actions">
+ <li><a class="nav" href="{href}">Add
Property</a></li>
+ <li><a href="{href}">Apply Configuration to
Broker</a></li>
+</ul>
+
+<table class="mobjects">
+ <tr>
+ <th>Name</th>
+ <th>Configured Value</th>
+ <th>Broker Value</th>
+ <th>Profile Value</th>
+ <th></th>
+ </tr>
+
+ {items}
+</table>
+
+[BrokerConfigTab.item_html]
+<tr>
+ <td>{item_name}</td>
+ <td>{item_value}</td>
+ <td>{item_broker_value}</td>
+ <td>{item_profile_value}</td>
+ <td><a class="action"
href="{item_edit_href}">Edit</a></td>
+</tr>
+
+[BrokerConfigPropertyForm.css]
+.BrokerConfigPropertyForm div.value {
+ margin: 1em 2em;
+}
+
+[BrokerConfigPropertyForm.html]
+<form id="{id}" class="BrokerConfigPropertyForm mform"
method="post" action="?">
+ <div class="head">
+ <h1>{title}</h1>
+ </div>
+ <div class="body">
+ <span class="legend">Value</span>
+ <fieldset>
+ <div class="field">
+ {profile} Use the value from the broker profile
+ <div class="value">{profile_value}</div>
+ </div>
+ <div class="field">
+ {broker} Use the value currently set on the broker
+ <div class="value">{broker_value}</div>
+ </div>
+ <div class="field">
+ {local} Set a new value
+ <div class="value">{local_value}</div>
+ </div>
+ </fieldset>
+
+ {hidden_inputs}
+ </div>
+ <div class="foot">
+ <div style="float:
left;"><button>Help</button></div>
+ {submit}
+ {cancel}
+ </div>
+</form>
+<script defer="defer">
+(function() {
+ var elem = wooly.doc().elembyid("{id}").node.elements[1];
+ elem.focus();
+ elem.select();
+}())
+</script>