Author: croberts
Date: 2011-08-31 20:30:52 +0000 (Wed, 31 Aug 2011)
New Revision: 4943
Modified:
trunk/cumin/model/cumin.xml
trunk/cumin/python/cumin/grid/tags.py
trunk/cumin/python/cumin/util.py
Log:
First pass at assigning features to tags. Also, moved the truncate_text logic into util.
Modified: trunk/cumin/model/cumin.xml
===================================================================
--- trunk/cumin/model/cumin.xml 2011-08-31 18:09:29 UTC (rev 4942)
+++ trunk/cumin/model/cumin.xml 2011-08-31 20:30:52 UTC (rev 4943)
@@ -58,6 +58,7 @@
<property name="Name" type="sstr"/>
<property name="Tags" type="sstr"/>
<property name="Checkin" type="sstr"/>
+ <property name="Features" type="sstr"/>
</class>
Modified: trunk/cumin/python/cumin/grid/tags.py
===================================================================
--- trunk/cumin/python/cumin/grid/tags.py 2011-08-31 18:09:29 UTC (rev 4942)
+++ trunk/cumin/python/cumin/grid/tags.py 2011-08-31 20:30:52 UTC (rev 4943)
@@ -1,7 +1,7 @@
import logging
from wooly import Widget, Attribute
-from wooly.util import StringCatalog, Writer
+from wooly.util import StringCatalog, Writer, escape_amp, escape_entity
from wooly.datatable import DataAdapterOptions, DataAdapterField, DataTableColumn,
DataTable, DataAdapter
from wooly.widgets import RadioModeSet, WidgetSet
from wooly.template import WidgetTemplate
@@ -85,9 +85,10 @@
data = []
try:
wallaby_tags = self.app.wallaby.get_data(WBTypes.TAGS)
+ wallaby_features = self.app.wallaby.get_data(WBTypes.FEATURES)
for i, tag in enumerate(wallaby_tags):
- data.append({'Tag':str(tag.name),
'Nodes':self.app.wallaby.get_node_names(tag)})
+ data.append({'Tag':str(tag.name),
'Nodes':self.app.wallaby.get_node_names(tag), 'Features':tag.features})
except Exception, e:
log.exception(e)
@@ -100,7 +101,7 @@
records = list()
if results:
for result in results:
- records.append([result['Tag'], result['Nodes']])
+ records.append([result['Tag'], result['Nodes'],
result['Features']])
return records
@@ -142,6 +143,7 @@
super(TagsFrame, self).__init__(app, name, cls)
self.set_tags = TagsNodeEditTask(app, self)
self.set_nodes = TagsTagEditTask(app, self)
+ self.set_features = TagsFeatureEditTask(app, self)
class TagInventory(ObjectSelectorNoCheckboxes):
'''
@@ -160,10 +162,16 @@
link = TaskLink(app, "tag_remove", remove_node_tags_task)
self.links.add_child(link)
- col = self.TagColumn(app, "tagcol", cls.Tags)
+ col = self.TagColumn(app, "tagcol", cls.Tags)
+ col.width = "20%"
self.add_column(col)
- self.add_search_filter(col)
+ self.add_search_filter(col)
+ col = self.FeatureColumn(app, "featcol", cls.Features)
+ col.width = "80%"
+ self.add_column(col)
+ #self.add_search_filter(col)
+
def render_title(self, session):
return "Tags"
@@ -181,6 +189,28 @@
self.frame.tag.set_nodes.form.tags.set(session, tags)
href = self.frame.tag.set_nodes.get_href(session)
return fmt_link(href, tags)
+
+ class FeatureColumn(ObjectTableColumn):
+ '''
+ This column will display the features that are currently assigned to a tag.
+ If a tag has no features on it, <add features to this tag> will be
displayed instead.
+ '''
+ def render_cell_content(self, session, data):
+ tags = data[0]
+ feature_list = data[2]
+ features = ""
+ if feature_list:
+ for feature in feature_list:
+ features = features + "," + str(feature)
+ features = features[1:]
+ #here we set some info that will be used in the display of the target form
+ self.frame.tag.set_features.form.feature_name.set(session, features)
+ self.frame.tag.set_features.form.tags.set(session, tags)
+ href = self.frame.tag.set_features.get_href(session)
+ if not features or features == "":
+ features = escape_entity("<add features to this tag>")
+ features = truncate_text(features, 50, True)
+ return fmt_link(href, features)
class NodeInventory(ObjectSelectorNoCheckboxes):
@@ -242,9 +272,7 @@
for tag in tags_list:
tags = tags + "," + str(tag)
tags = tags[1:]
- retval = len(tags) > 0 and tags or ""
- if(len(tags) > 50):
- retval = tags[:50] + "..." #indicate that we truncated the
name
+ retval = truncate_text(tags, 50, True)
return retval
class NodeColumn(ObjectTableColumn):
@@ -342,7 +370,7 @@
tags_string = ""
for i, tag in enumerate(items):
- tags_string = tags_string + "<option id='" + str(i) +
"' name='" + tag.title + "' value='" + tag.title +
"'" + ">" + tag.title + "</option>"
+ tags_string = tags_string + "<option id='" + str(i) +
"' name=\"" + tag.title + "\" value=\"" + tag.title
+ "\"" + ">" + tag.title + "</option>"
return tags_string
@@ -572,10 +600,8 @@
'''
Show the initial value passed-in, truncated to trunc_length characters
'''
- trunc_length = 50
value = self.input.get(session)
- if(len(value) > trunc_length):
- value = value[:trunc_length] + "..." #indicate truncated value
+ value = truncate_text(value, 50, True)
return value
class DisabledInput(StringInput):
@@ -665,9 +691,7 @@
def render_inputs(self, session, *args):
value = self.input.get(session)
- trunc_length = 50
- if(len(value) > trunc_length):
- value = value[:trunc_length] + "..." #indicate truncated value
+ value = truncate_text(value, 50, True)
return value
def render_title(self, session):
@@ -693,6 +717,117 @@
class DisabledInput(StringInput):
pass
+class EditTagFeaturesForm(ObjectFrameTaskFeedbackForm):
+ '''
+ This form will allow the editing of nodes for a single given tag
+ '''
+ def __init__(self, app, name, task):
+ super(EditTagFeaturesForm, self).__init__(app, name, task)
+
+ self.tags = self.Tags(app, "tags")
+ self.add_field(self.tags)
+
+ self.feature_name = self.FeatureName(app, "feature_name")
+ self.add_field(self.feature_name)
+
+ self.possible_features = self.FeatureList(app, "pfeat")
+ self.add_field(self.possible_features)
+
+ self.update_enabled = False
+
+
+ def process_submit(self, session):
+ tag = self.tags.input.get(session)
+ features_value = self.possible_features.get(session)
+
+ self.tags.validate(session)
+ if not self.errors.get(session):
+ self.tags.set(session, tag)
+
+ self.task.invoke(session, None, tag, features_value)
+ self.task.exit_with_redirect(session)
+
+ def render_form_class(self, session):
+ return " ".join((super(EditTagFeaturesForm,
self).render_form_class(session), "mform"))
+
+ class FeatureList(PageableFilteredSelect):
+ def __init__(self, app, name):
+ super(EditTagFeaturesForm.FeatureList, self).__init__(app, name)
+
+ def render_items(self, session):
+ items = self.do_get_items(session)
+ features_string = ""
+
+ given_tag = self.form.tags.input.param.get(session)
+ tag_object = self.app.wallaby.get_tag_by_name(given_tag)
+ selected_features = tag_object.features
+
+ for i, feature in enumerate(items):
+ selected = ""
+ if(selected_features and feature.title in selected_features):
+ selected = " selected='selected' "
+ features_string = features_string + "<option id='" +
str(i) + "' name='" + feature.title + "' value='" +
feature.title + "'" + selected + ">" + feature.title +
"</option>"
+
+ return features_string
+
+ def do_get_items(self, session):
+ features = fetchFeatures(self, session)
+ items = list()
+
+ if features:
+ for feature in features:
+ item = CheckboxItem(feature)
+ item.title = feature
+ items.append(item)
+
+ return items
+
+ def render_title(self, session):
+ return "Update features"
+
+ class FeatureName(StringField):
+ def __init__(self, app, name):
+ super(EditTagFeaturesForm.FeatureName, self).__init__(app, name)
+
+ self.input = self.DisabledInput(app, "input")
+ self.replace_child(self.input)
+
+ def get(self,session):
+ value = self.input.get(session)
+
+ if not value or value == "":
+ value = "No features currently selected"
+
+ return value
+
+ def render_inputs(self, session, *args):
+ value = self.input.get(session)
+ value = truncate_text(value, 50, True)
+ return value
+
+ def render_title(self, session):
+ return "Current features"
+
+ class DisabledInput(StringInput):
+ pass
+
+ class Tags(StringField):
+ def __init__(self, app, name):
+ super(EditTagFeaturesForm.Tags, self).__init__(app, name)
+
+ self.input = self.DisabledInput(app, "input")
+ self.replace_child(self.input)
+
+ def render_title(self, session):
+ return "Tag"
+
+ def get(self,session):
+ value = self.input.get(session)
+ return value
+
+ class DisabledInput(StringInput):
+ pass
+
class TagsNodeEditTask(ObjectFrameTask):
'''
On invocation, this task will take a node and reset the tags for that node to a
@@ -763,6 +898,38 @@
invoc.end()
+class TagsFeatureEditTask(ObjectFrameTask):
+ '''
+ This is the task that will take a tag and a set of nodes and make the
+ necessary assignments or unassignments.
+ '''
+ def __init__(self, app, frame):
+ super(TagsFeatureEditTask, self).__init__(app, frame)
+
+ self.form = EditTagFeaturesForm(app, self.name, self)
+
+ def get_title(self, session):
+ return "Change features for this tag "
+
+ def do_enter(self, session, osession):
+ self.form.tags.set(session, self.form.tags.get(osession))
+ self.form.feature_name.set(session, self.form.feature_name.get(osession))
+
+ def do_invoke(self, invoc, negotiator, tag, chosen_features):
+ '''
+ if the node is on the current_nodes list and is on the chosen_nodes passed in,
nothing to do
+ ** if the node is NOT on the current_nodes list and is on the chosen_nodes passed
in, add this tag to that node
+ ** if the node is on the current_nodes list and is NOT on the chosen_nodes passed
in, update that node sans this tag
+ if the node is NOT on the current_nodes list and is NOT on the chosen_nodes
passed in, nothing to do
+ '''
+ try:
+ call_async(invoc.make_callback(), self.app.wallaby.edit_features, tag,
*chosen_features)
+ except Exception, e:
+ invoc.status = invoc.FAILED
+ log.exception(e)
+
+ invoc.end()
+
class AddTags(Task):
'''
This task is used to create a tag in wallaby without assigning it to any nodes.
@@ -888,4 +1055,18 @@
node_list.append(str(node.name))
node_list.sort()
- return node_list
\ No newline at end of file
+ return node_list
+
+def fetchFeatures(self, session):
+ '''
+ fetch the list of nodes from wallaby
+ '''
+ wallaby_features = self.app.wallaby.get_data(WBTypes.FEATURES)
+ feature_list = list()
+
+ for feature in wallaby_features:
+ feature_list.append(str(feature.name))
+ feature_list.sort()
+
+ return feature_list
+
\ No newline at end of file
Modified: trunk/cumin/python/cumin/util.py
===================================================================
--- trunk/cumin/python/cumin/util.py 2011-08-31 18:09:29 UTC (rev 4942)
+++ trunk/cumin/python/cumin/util.py 2011-08-31 20:30:52 UTC (rev 4943)
@@ -244,3 +244,17 @@
hList.append(n.rjust(2, '0').upper())
return "".join(hList)
+
+def truncate_text(text, length, indicator):
+ ''' Quick truncation of text at specified length
+
+ text: the text to be truncated
+ length: the length at which to truncate the text
+ indicator: If true, add "..." to the truncated text to indicate that
truncation happened
+ '''
+ retval = len(text) > 0 and text or ""
+ if(len(retval) > length):
+ retval = retval[:length]
+ if indicator:
+ retval = retval + "..."
+ return retval