Author: eallen
Date: 2008-09-03 12:15:10 -0400 (Wed, 03 Sep 2008)
New Revision: 2390
Modified:
mgmt/trunk/cumin/python/cumin/job.py
mgmt/trunk/cumin/python/cumin/job.strings
mgmt/trunk/cumin/python/cumin/widgets.py
mgmt/trunk/cumin/python/cumin/widgets.strings
Log:
Modified the way job ads are viewed and edited.
Modified: mgmt/trunk/cumin/python/cumin/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.py 2008-09-03 16:13:28 UTC (rev 2389)
+++ mgmt/trunk/cumin/python/cumin/job.py 2008-09-03 16:15:10 UTC (rev 2390)
@@ -296,10 +296,10 @@
return self.frame.get_args(session)
def render_title(self, session, job):
- return "Ads"
+ return "Ad"
-class JobEditAds(CuminForm):
+class JobEditAds(CuminForm, CuminEditableProperties):
def __init__(self, app, name):
super(JobEditAds, self).__init__(app, name)
@@ -308,16 +308,55 @@
self.add_parameter(self.ads)
self.add_form_parameter(self.ads)
- # the widget that gets/saves the data and draws the form
- self.props = JobAdsEditor(app, "properties", self.ads)
- self.add_child(self.props)
+ self.__items = JobAdsSet(app, name)
+ self.add_child(self.__items)
+ self.props = CuminProperties(app, "properties")
+ #self.add_child(props)
+
def get_args(self, session):
return self.frame.get_args(session)
def render_title(self, session, job):
- return "Ads"
+ return "Ad"
+ def do_get_items(self, session, job):
+ cls = self.app.model.get_class_by_object(job)
+ ads = self.ads.get(session)
+ if len(ads):
+ keys = ads.keys()
+ keys.sort()
+ return [self.gen_item(x, ads[x]["value"], cls,
dtype=ads[x]["type"], error=ads[x]) for x in keys]
+ else:
+ items = self.__items.do_get_items(session, job)
+ return [self.gen_item(x[0], x[1], cls) for x in items]
+
+ def gen_item(self, name, value, cls, dtype=None, error=None):
+ idict = dict()
+ ilist = list()
+ idict["name"] = name
+ idict["value"] = value
+ if dtype:
+ idict["type"] = dtype
+ if dtype == "number":
+ nval = convertStr(value)
+ if nval:
+ idict["value"] = nval
+ else:
+ idict["type"] = self.get_type(value)
+ if error:
+ if "error" in error:
+ idict["error"] = error["error"]
+
+ if name in cls.ad_properties_by_name:
+ idict["property"] = cls.ad_properties_by_name[name]
+ ilist.append(idict)
+ ilist.append(self.ads.path)
+ return ilist
+
+ def get_type(self, value):
+ return isinstance(value, int) and "number" or "string"
+
def process_submit(self, session, job):
ads = self.ads.get(session)
errors = False
@@ -346,10 +385,36 @@
self.ads.clear()
super(JobEditAds, self).process_cancel(session, job)
+class JobPropertyRenderer(TemplateRenderer):
+ def render_ad_title(self, session, prop):
+ return escape_amp(prop[0])
+
+ def render_ad_value(self, session, prop):
+ name, value, props = self.decode_props(prop)
+ if props and props.renderer:
+ value = props.renderer(session, value)
+ return escape_amp(value)
+
+ def render_ad_help(self, session, prop):
+ name, value, props = self.decode_props(prop)
+ if props and props.description:
+ return props.description
+
+ def decode_props(self, prop):
+ name = prop[0]
+ value = prop[1]
+ cls = prop[2]
+ if name in cls.ad_properties_by_name:
+ props = cls.ad_properties_by_name[name]
+ else:
+ props = None
+ return name, value, props
+
class JobAdsSet(PropertySet):
def __init__(self, app, name):
- super(JobAdsSet, self).__init__(app, name)
+ super(JobAdsSet, self).__init__(app, name, )
# self.got_data = False
+ self.item_renderer = JobPropertyRenderer(self, "ad_html")
def get_args(self, session):
return self.frame.get_args(session)
@@ -443,14 +508,11 @@
u'NumJobStarts': 0,
u'Out': u'/dev/null'}
+ cls = self.app.model.get_class_by_object(job)
keys = ads.keys()
keys.sort()
- return [[x, {"value":str(ads[x]),
- "type":self.get_type(ads[x])}] for x in keys]
+ return [[x, ads[x], cls] for x in keys]
- def get_type(self, value):
- return isinstance(value, int) and "number" or "string"
-
class JobAdsViewer(JobAdsSet):
def __init__(self, app, name):
super(JobAdsViewer, self).__init__(app, name)
@@ -459,35 +521,13 @@
return self.frame.get_args(session)
def do_get_items(self, session, job):
- items = super(JobAdsViewer, self).do_get_items(session, job)
- return [[item[0], item[1]["value"]] for item in items]
+ return super(JobAdsViewer, self).do_get_items(session, job)
- def render_edit_ads_link(self, session, job):
+ def render_edit_ads_url(self, session, job):
branch = session.branch()
self.frame.show_ads_edit(branch)
- return fmt_olink(branch, job, name="Edit Ads")
+ return branch.marshal()
-class JobAdsEditor(CuminEditableProperties):
- def __init__(self, app, name, params):
- super(JobAdsEditor, self).__init__(app, name, params)
-
- self.__items = JobAdsSet(app, name)
- self.add_child(self.__items)
-
- self.params = params
-
- def get_args(self, session):
- return self.frame.get_args(session)
-
- def do_get_items(self, session, job):
- ads = self.params.get(session)
- if len(ads):
- keys = ads.keys()
- keys.sort()
- return [[x, ads[x]] for x in keys]
- else:
- return self.__items.do_get_items(session, job)
-
class JobOutput(TabbedModeSet):
def __init__(self, app, name):
super(JobOutput, self).__init__(app, name)
Modified: mgmt/trunk/cumin/python/cumin/job.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.strings 2008-09-03 16:13:28 UTC (rev 2389)
+++ mgmt/trunk/cumin/python/cumin/job.strings 2008-09-03 16:15:10 UTC (rev 2390)
@@ -107,34 +107,35 @@
[JobAdsViewer.html]
+<ul class="actions">
+ <li><a class="nav" href="{edit_ads_url}">Edit Job
Ad</a></li>
+</ul>
<table class="CuminDetails">
<tbody>
<tr>
<td>
- <h2>Ads</h2>
+ <h2>Ad</h2>
<table class="PropertySet">
<thead>
<tr>
- <th style="width: 50%;">Name</th>
- <th style="width: 50%;">Value</th>
+ <th style="width: 33%;">Name</th>
+ <th style="width: 33%;">Value</th>
+ <th style="width: 33%;"> </th>
</tr>
</thead>
<tbody>{items}</tbody>
</table>
</td>
- <td>
- <h2>Actions</h2>
- <ul class="ActionSet">
- <li>{edit_ads_link}</li>
- </ul>
- </td>
</tr>
</tbody>
</table>
+<ul class="actions">
+ <li><a class="nav" href="{edit_ads_url}">Edit Job
Ad</a></li>
+</ul>
[JobAdsViewer.ad_html]
<tr>
- <th>{ad_title}</th><td>{ad_value}</td>
+ <th>{ad_title}</th><td>{ad_value}</td><td>{ad_help}</td>
</tr>
@@ -150,28 +151,27 @@
[JobEditAds.html]
<form id="{id}" class="mform editform" method="post"
action="?">
+{help} {submit} {cancel}
+
<table class="CuminDetails">
<tbody>
<tr>
<td>
- <h2>Edit Job Ads</h2>
- {properties}
+ <h2>Edit Job Ad</h2>
+ <table class="PropertySet Editable">
+ <thead>
+ <tr>
+ <th style="width: 33%;">Name</th>
+ <th style="width: 33%;">Value</th>
+ <th style="width: 33%;"> </th>
+ </tr>
+ </thead>
+ <tbody>{items}</tbody>
+ </table>
</td>
- <td>
- <div class="inline_help">
- <h2>Actions</h2>
- {help}
- {submit}
- {cancel}
- <h2 class="legend">Legend</h2>
- <ul class="legend">
- <li><span class="edit_string">String input
expected</span></li>
- <li><span class="edit_number">Numeric input
expected</span></li>
- </ul>
- </div>
- </td>
</tr>
</tbody>
</table>
+{help} {submit} {cancel}
<div>{hidden_inputs}</div>
</form>
Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py 2008-09-03 16:13:28 UTC (rev 2389)
+++ mgmt/trunk/cumin/python/cumin/widgets.py 2008-09-03 16:15:10 UTC (rev 2390)
@@ -274,44 +274,49 @@
class CuminEditableProperties(PropertySet):
+ def __init__(self, app, name):
+ self.item_renderer=EditablePropertyRenderer(self, "property_html")
+ super(CuminEditableProperties, self).__init__(app, name,
item_renderer=self.item_renderer)
+
+class EditablePropertyRenderer(TemplateRenderer, Widget):
"""Display input fields for editing properties
Parent class needs to override do_get_items() and return a list of items.
Each item should be another list.
- item[0] should be the property name
- item[1] should be the a dict:
- item[1]["value"] is required and should be the value to edit
- item[1]["type"] is required and should be an input type
<"number" | "string">
- item[1]["error"] is optional and should be the error text to
display for that item
-
- The dict_param that is passed in should be a object derived from DictParameter.
- dict_param.path will be used to generate the input field name
+ item[0] should be the a dict:
+ item[0]["name"] is required and should be the display label
+ item[0]["value"] is required and should be the value to edit
+ item[0]["type"] is required and should be an input type
<"number" | "string">
+ item[0]["error"] is optional and should be the error text to
display for that item
+ item[0]["help"] is optional help to be displayed for the item
+ item[0]["writable"] is optional and assumed to be True if missing
+ item[1] should be a the path that will be prepended to the file names
"""
-
- def __init__(self, app, name, dict_param):
- self.item_renderer=EditablePropertyRenderer(self, "property_html",
dict_param)
- super(CuminEditableProperties, self).__init__(app, name,
item_renderer=self.item_renderer)
-
-class EditablePropertyRenderer(TemplateRenderer, Widget):
- def __init__(self, widget, template_key, dict_param):
+ def __init__(self, widget, template_key):
super(EditablePropertyRenderer, self).__init__(widget, template_key)
self.__bool_template = Template(self, "bool_html")
self.__string_template = Template(self, "string_html")
self.__bigstring_template = Template(self, "bigstring_html")
self.__number_template = Template(self, "number_html")
+ self.__readonly_template = Template(self, "readonly_html")
- self.dict_param = dict_param
-
def render_title(self, session, propval):
- title = propval[0]
+ title = propval[0]["name"]
return escape_amp(title)
def render_value(self, session, propval):
- value = propval[1]["value"]
- type = propval[1]["type"]
+ value = propval[0]["value"]
+ type = propval[0]["type"]
+ writable = True
+ property = "property" in propval[0] and
propval[0]["property"] or None
+ if property:
+ writable = property.writable
+
writer = Writer()
- if type == "number":
+ if not writable:
+ self.__readonly_template.render(writer, session, propval)
+ elif type == "number":
self.__number_template.render(writer, session, propval)
else:
uvalue = value.upper()
@@ -327,34 +332,55 @@
def render_pname(self, session, propval):
return DictParameter.sep().join(
- (self.dict_param.path, escape_entity(propval[0]), "value"))
+ (propval[1], escape_entity(propval[0]["name"]),
"value"))
def render_ptype_name(self, session, propval):
return DictParameter.sep().join(
- (self.dict_param.path, escape_entity(propval[0]), "type"))
+ (propval[1], escape_entity(propval[0]["name"]),
"type"))
def render_ptype_value(self, session, propval):
- return propval[1]["type"]
+ return propval[0]["type"]
def render_val(self, session, propval):
+ value = self.get_val(session, propval)
+ return escape_entity(str(value))
+
+ def render_display_val(self, session, propval):
+ value = self.get_val(session, propval)
+ property = "property" in propval[0] and
propval[0]["property"] or None
+ if property:
+ renderer = property.renderer
+ if renderer:
+ value = renderer(session, value)
+
+ return escape_amp(str(value))
+
+ def get_val(self, session, propval):
try:
- value = propval[1]["value"]
+ value = propval[0]["value"]
except KeyError:
value = ""
- return escape_entity(str(value))
-
+ return value
+
def render_error(self, session, propval):
- if "error" in propval[1]:
- return "<div class=\"error\">%s</div>" %
propval[1]["error"]
+ if "error" in propval[0]:
+ return "<div class=\"error\">%s</div>" %
propval[0]["error"]
+
+ def render_inline_help(self, session, propval):
+ property = "property" in propval[0] and
propval[0]["property"] or None
+ if property:
+ example = property.example or ""
+ description = property.description or ""
+ return " ".join((example, description))
def render_false_selected(self, session, propval):
- return propval[1]["value"].upper() == "FALSE" and
"checked=\"checked\"" or ""
+ return propval[0]["value"].upper() == "FALSE" and
"checked=\"checked\"" or ""
def render_true_selected(self, session, propval):
- return propval[1]["value"].upper() == "TRUE" and
"checked=\"checked\"" or ""
+ return propval[0]["value"].upper() == "TRUE" and
"checked=\"checked\"" or ""
def render_edit_number_class(self, session, propval):
- return "error" in propval[1] and "numeric_error" or
"edit_number"
+ return "error" in propval[0] and "numeric_error" or
"edit_number"
class CuminProperties(PropertySet):
def get_args(self, session):
Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings 2008-09-03 16:13:28 UTC (rev 2389)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings 2008-09-03 16:15:10 UTC (rev 2390)
@@ -317,6 +317,10 @@
div.inline_help span.numeric_error {
border: 1px dashed #FF0000;
}
+table.Editable span.edit_readonly {
+ background-color: #FFFFFF;
+ color: #444444;
+}
table.Editable input.edit_string,
table.Editable input.edit_number,
@@ -349,6 +353,13 @@
div.inline_help ul.legend li {
line-height: 1.75em;
}
+span.prop_example {
+ font-size: 0.9em;
+}
+span.prop_example:before {
+ content: "Example:";
+ padding-right: 0.25em;
+}
[CuminEditableProperties.html]
<table class="PropertySet Editable">
@@ -363,7 +374,7 @@
[CuminEditableProperties.property_html]
<tr>
- <th>{title}</th><td>{value}</td>
+ <th>{title}</th><td>{value}</td><td>{inline_help}</td>
</tr>
[EditablePropertyRenderer.bool_html]
@@ -383,6 +394,9 @@
<input class="{edit_number_class}" type="text"
name="{pname}" value="{val}" />{error}
<input type="hidden" name="{ptype_name}"
value="{ptype_value}"/>
+[EditablePropertyRenderer.readonly_html]
+<span class="edit_readonly">{display_val}</span><input
type="hidden" name="{ptype_name}"
value="{ptype_value}"/><input type="hidden"
name="{pname}" value="{val}"/>
+
[StateSwitch.item_html]
<li>{item_link}</li>