r4982 - trunk/cumin/python/cumin
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-19 14:24:13 +0000 (Mon, 19 Sep 2011)
New Revision: 4982
Modified:
trunk/cumin/python/cumin/task.strings
Log:
Addressing RFE BZ https://bugzilla.redhat.com/show_bug.cgi?id=739217 by moving the "dismiss all" link to the right and changing the text to "Dismiss all notifications" for clarity and to make the "dismiss all" link stand out more from the other "dismiss" links.
Modified: trunk/cumin/python/cumin/task.strings
===================================================================
--- trunk/cumin/python/cumin/task.strings 2011-09-16 20:21:36 UTC (rev 4981)
+++ trunk/cumin/python/cumin/task.strings 2011-09-19 14:24:13 UTC (rev 4982)
@@ -18,13 +18,9 @@
font-size: 0.9em;
}
-div.TaskInvocationSet a.dismissall {
- font-size: 0.9em;
-}
-
[TaskInvocationSet.html]
<div id="{id}" class="{class}">
- <a class="dismissall" href="{dismiss_all_href}">Dismiss all</a>
+ <a class="dismiss" href="{dismiss_all_href}">Dismiss all notifications</a><br/>
<ul>{items}</ul>
</div>
12 years, 8 months
r4981 - trunk/cumin/python/cumin/grid
by tmckay@fedoraproject.org
Author: tmckay
Date: 2011-09-16 20:21:36 +0000 (Fri, 16 Sep 2011)
New Revision: 4981
Modified:
trunk/cumin/python/cumin/grid/job.py
trunk/cumin/python/cumin/grid/submission.py
Log:
Prepend the working directory path to input, output, error, and log file
names on job submission if the files are specified and do not already give
absolute paths. This will allow Aviary to have the proper information for
a lookup if/when files are requested.
BZ731065
Modified: trunk/cumin/python/cumin/grid/job.py
===================================================================
--- trunk/cumin/python/cumin/grid/job.py 2011-09-16 19:52:21 UTC (rev 4980)
+++ trunk/cumin/python/cumin/grid/job.py 2011-09-16 20:21:36 UTC (rev 4981)
@@ -1,4 +1,5 @@
import logging
+import os
from datetime import datetime
from cumin.objectframe import ObjectView, ObjectFrameTaskForm, ObjectFrame,\
@@ -948,13 +949,8 @@
def do_process(self, session):
def add_path(path, filename):
- # If filename does not begin with an absolute
- # path, prepend the path value to filename
- if filename is not None and \
- not filename.startswith("/"):
- if not path.endswith("/"):
- path += "/"
- filename = path + filename
+ if path is not None and filename not in (None, ""):
+ return os.path.join(path, filename)
return filename
out_file = None
Modified: trunk/cumin/python/cumin/grid/submission.py
===================================================================
--- trunk/cumin/python/cumin/grid/submission.py 2011-09-16 19:52:21 UTC (rev 4980)
+++ trunk/cumin/python/cumin/grid/submission.py 2011-09-16 20:21:36 UTC (rev 4981)
@@ -330,6 +330,19 @@
request_mem_MB=None,
request_disk_KB=None,
attrs={}):
+
+ def add_path(path, filename):
+ if path is not None and filename not in (None, ""):
+ return os.path.join(path, filename)
+ return filename
+
+ # fixup paths for in, out, err, log
+ if iwd is not None:
+ stdin = add_path(iwd, stdin)
+ stdout = add_path(iwd, stdout)
+ stderr = add_path(iwd, stderr)
+ usrlog = add_path(iwd, usrlog)
+
ad = dict()
ad["Submission"] = description
12 years, 8 months
r4980 - trunk/cumin/python/cumin/grid
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 19:52:21 +0000 (Fri, 16 Sep 2011)
New Revision: 4980
Modified:
trunk/cumin/python/cumin/grid/tags.py
Log:
Changes to allow smooth handling of tags with quotes and other potentially problematic characters in them.
Modified: trunk/cumin/python/cumin/grid/tags.py
===================================================================
--- trunk/cumin/python/cumin/grid/tags.py 2011-09-16 19:51:22 UTC (rev 4979)
+++ trunk/cumin/python/cumin/grid/tags.py 2011-09-16 19:52:21 UTC (rev 4980)
@@ -1,7 +1,7 @@
import logging
from wooly import Widget, Attribute
-from wooly.util import StringCatalog, Writer, escape_amp, escape_entity
+from wooly.util import StringCatalog, Writer, escape_amp, escape_entity, unescape_entity
from wooly.datatable import DataAdapterOptions, DataAdapterField, DataTableColumn, DataTable, DataAdapter
from wooly.widgets import RadioModeSet, WidgetSet
from wooly.template import WidgetTemplate
@@ -88,7 +88,7 @@
wallaby_features = self.app.wallaby.get_data(WBTypes.FEATURES)
for i, tag in enumerate(wallaby_tags):
- data.append({'Tag':str(tag.name), 'Features':tag.features, 'NumHosts':len(self.app.wallaby.get_node_names(tag)), 'Host':self.app.wallaby.get_node_names(tag)} )
+ data.append({'Tag':str(escape_entity(tag.name)), 'Features':tag.features, 'NumHosts':len(self.app.wallaby.get_node_names(tag)), 'Host':self.app.wallaby.get_node_names(tag)} )
except Exception, e:
log.exception(e)
@@ -302,7 +302,7 @@
class TagColumn(ObjectLinkColumn):
def render_cell_href(self, session, record):
- id = record[self.id_field.index]
+ id = unescape_entity(record[self.id_field.index])
frame = self.page.page_widgets_by_path[self.frame_path]
if isinstance(frame, TagObjectFrame):
@@ -524,8 +524,8 @@
def get_selection(self, session):
''' return the set of checkboxes from the ObjectSelector that were set in self.ids '''
ids = self.ids.get(session)
-
- selection = list(ids)
+ selection = [escape_entity(id) for id in ids]
+
self.selection.set(session, selection)
return selection
@@ -1204,7 +1204,7 @@
def invoke(self, session, selection):
self.invoc = self.start(session, selection)
-
+ selection = [unescape_entity(text) for text in selection]
try:
self.do_invoke(self.invoc, selection)
except Exception, e:
12 years, 8 months
r4979 - trunk/wooly/python/wooly
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 19:51:22 +0000 (Fri, 16 Sep 2011)
New Revision: 4979
Modified:
trunk/wooly/python/wooly/forms.py
Log:
escaping values before writing them out to ensure valid XML output.
Modified: trunk/wooly/python/wooly/forms.py
===================================================================
--- trunk/wooly/python/wooly/forms.py 2011-09-16 19:49:56 UTC (rev 4978)
+++ trunk/wooly/python/wooly/forms.py 2011-09-16 19:51:22 UTC (rev 4979)
@@ -49,7 +49,7 @@
def write_hidden_input(self, name, value, writer):
writer.write("<input type=\"hidden\" name=\"%s\" value=\"%s\"/>" \
- % (name, value))
+ % (name, escape_entity(value)))
class FormError(object):
def __init__(self, message):
12 years, 8 months
r4978 - trunk/wooly/python/wooly
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 19:49:56 +0000 (Fri, 16 Sep 2011)
New Revision: 4978
Modified:
trunk/wooly/python/wooly/util.py
Log:
Adding unescape_entity utility method.
Modified: trunk/wooly/python/wooly/util.py
===================================================================
--- trunk/wooly/python/wooly/util.py 2011-09-16 18:43:07 UTC (rev 4977)
+++ trunk/wooly/python/wooly/util.py 2011-09-16 19:49:56 UTC (rev 4978)
@@ -1,4 +1,5 @@
import htmlentitydefs as entity
+import re
import logging
import math
import os
@@ -42,6 +43,35 @@
t += i
return t
+##
+# Removes HTML or XML character references and entities from a text string.
+#
+# @param text The HTML (or XML) source text.
+# @return The plain text, as a Unicode string, if necessary.
+# from Fredrik Lundh
+# http://effbot.org/zone/re-sub.htm#unescape-html
+##
+def unescape_entity(text):
+ def fixup(m):
+ text = m.group(0)
+ if text[:2] == "&#":
+ # character reference
+ try:
+ if text[:3] == "&#x":
+ return unichr(int(text[3:-1], 16))
+ else:
+ return unichr(int(text[2:-1]))
+ except ValueError:
+ pass
+ else:
+ # named entity
+ try:
+ text = unichr(entity.name2codepoint[text[1:-1]])
+ except KeyError:
+ pass
+ return text # leave as is
+ return re.sub("&#?\w+;", fixup, text)
+
class Writer(object):
def __init__(self):
self.writer = StringIO()
12 years, 8 months
r4977 - trunk/cumin/python/cumin/inventory
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 18:43:07 +0000 (Fri, 16 Sep 2011)
New Revision: 4977
Modified:
trunk/cumin/python/cumin/inventory/system.py
Log:
Fixing-up sorting by both sesame and wallaby columns in the system table.
Modified: trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- trunk/cumin/python/cumin/inventory/system.py 2011-09-16 16:40:24 UTC (rev 4976)
+++ trunk/cumin/python/cumin/inventory/system.py 2011-09-16 18:43:07 UTC (rev 4977)
@@ -1,3 +1,4 @@
+from operator import itemgetter
from cumin.grid.slot import SlotMap, SlotMapPage
from cumin.objectselector import ObjectSelector, ObjectLinkColumn, ObjectTable, ObjectTableColumn
@@ -209,11 +210,9 @@
class WallabyAndSqlAdapter(ObjectSqlAdapter):
def get_data(self, values, options):
- #first, fetch all the sql data
- if not isinstance(options.sort_field, ObjectSqlField):
- ##do some magic to handle non-sql sort fields
- ##but for now, don't bother to sort
- options.sort_field = None
+ #first, fetch all the sql data, unsorted since we will sort it after merging the wallaby data
+ requested_sort_field = options.sort_field
+ options.sort_field = None
sqldata = super(WallabyAndSqlAdapter, self).get_data(values, options)
#now get the wallaby data
@@ -241,10 +240,22 @@
for node in wallaby_nodes:
data_row = tuple(["", node.name, "", "", "", 0, self.app.wallaby.get_tag_names(node), node.last_checkin])
data.append(data_row)
+
+ options.sort_field = requested_sort_field
+ data = self.sort_rows(data, options)
return data
+ def sort_rows(self, rows, options):
+ if len(rows) > 10000:
+ return rows
+ sort_field = options.sort_field
+ rev = options.sort_ascending == False
+
+ return sorted(rows, key=itemgetter(sort_field.index), reverse=rev)
+
+
class DerivedTableColumn(ObjectTableColumn):
def __init__(self, app, name):
super(DerivedTableColumn, self).__init__(app, name, None)
12 years, 8 months
r4976 - trunk/cumin/python/cumin/grid
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 16:40:24 +0000 (Fri, 16 Sep 2011)
New Revision: 4976
Modified:
trunk/cumin/python/cumin/grid/tags.py
Log:
Setting up proper callbacks for the async wallaby calls. The results will now be properly reflected in our invocation status [yellow] banner.
Modified: trunk/cumin/python/cumin/grid/tags.py
===================================================================
--- trunk/cumin/python/cumin/grid/tags.py 2011-09-16 13:18:27 UTC (rev 4975)
+++ trunk/cumin/python/cumin/grid/tags.py 2011-09-16 16:40:24 UTC (rev 4976)
@@ -998,6 +998,7 @@
self.form = EditNodeTagsForm(app, self.name, self)
self.visible = False
+ self.invoc = None
def get_title(self, session):
return "Change tags associated with this host"
@@ -1006,15 +1007,20 @@
self.form.tags.set(session, self.form.tags.get(osession))
self.form.node_name.set(session, self.form.node_name.get(osession))
+ def callback(self, result):
+ if result == False:
+ self.invoc.status = self.invoc.FAILED
+ self.invoc.end()
+
def do_invoke(self, invoc, negotiator, node_name, tags):
+ self.invoc = invoc
try:
- call_async(invoc.make_callback(), self.app.wallaby.edit_tags, node_name, *tags)
+ call_async(self.callback, self.app.wallaby.edit_tags, node_name, *tags)
except Exception, e:
invoc.status = invoc.FAILED
log.exception(e)
+ invoc.end()
- invoc.end()
-
class TagsTagEditTask(ObjectFrameTask):
'''
This is the task that will take a tag and a set of nodes and make the
@@ -1024,6 +1030,8 @@
super(TagsTagEditTask, self).__init__(app, frame)
self.form = EditTagNodesForm(app, self.name, self)
+ self.invoc = None
+ self.call_count = 0
def get_title(self, session):
return "Edit hosts"
@@ -1038,6 +1046,13 @@
nodes = ", ".join(node_list)
self.form.node_name.set(session, nodes)
+ def callback(self, result):
+ self.call_count -= 1
+ if result == False:
+ self.invoc.status = self.invoc.FAILED
+ if(self.call_count <= 0):
+ self.invoc.end()
+
def do_invoke(self, invoc, negotiator, tag, chosen_nodes):
'''
if the node is on the current_nodes list and is on the chosen_nodes passed in, nothing to do
@@ -1045,24 +1060,27 @@
** 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
'''
+ self.invoc = invoc
current_nodes = self.app.wallaby.get_node_names(tag)
try:
for node in chosen_nodes:
if node not in current_nodes:
#we need to add the new tag to the existing tags for each node in the list
current_tags = self.app.wallaby.get_tag_names(node)
- current_tags.append(tag)
- call_async(invoc.make_callback(), self.app.wallaby.edit_tags, node, *current_tags)
+ current_tags.append(tag)
+ self.call_count += 1
+ call_async(self.callback, self.app.wallaby.edit_tags, node, *current_tags)
for node in current_nodes:
if node not in chosen_nodes:
current_tags = self.app.wallaby.get_tag_names(node)
current_tags.remove(tag)
- call_async(invoc.make_callback(), self.app.wallaby.edit_tags, node, *current_tags)
+ self.call_count += 1
+ call_async(self.callback, self.app.wallaby.edit_tags, node, *current_tags)
except Exception, e:
+ self.call_count = 0
invoc.status = invoc.FAILED
log.exception(e)
-
- invoc.end()
+ invoc.end()
class TagsFeatureEditTask(ObjectFrameTask):
'''
@@ -1073,6 +1091,7 @@
super(TagsFeatureEditTask, self).__init__(app, frame)
self.form = EditTagFeaturesForm(app, self.name, self)
+ self.invoc = None
def get_title(self, session):
return "Edit features"
@@ -1086,6 +1105,11 @@
features = ", ".join(feature_list)
self.form.feature_name.set(session, features)
+ def callback(self, result):
+ if result == False:
+ self.invoc.status = self.invoc.FAILED
+ self.invoc.end()
+
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
@@ -1093,14 +1117,14 @@
** 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
'''
+ self.invoc = invoc
try:
- call_async(invoc.make_callback(), self.app.wallaby.edit_features, tag, *chosen_features)
+ call_async(self.callback, self.app.wallaby.edit_features, tag, *chosen_features)
except Exception, e:
invoc.status = invoc.FAILED
- log.exception(e)
+ log.exception(e)
+ invoc.end()
- invoc.end()
-
class ActivateConfigTask(Task):
'''
This task is used to activate the wallaby configuration.
@@ -1109,27 +1133,25 @@
super(ActivateConfigTask, self).__init__(app)
cls = app.model.com_redhat_cumin_grid.Node
self.form = ActivateConfigurationForm(app, self.name, self, cls)
+ self.invoc = None
def get_title(self, session, object):
return "Activate wallaby configuration"
+ def callback(self, results):
+ if len(results[0]) != 0 or len(results[1]) != 0:
+ self.invoc.status = self.invoc.FAILED
+ self.invoc.end()
+
def do_invoke(self, session, object, invoc):
-
+ self.invoc = invoc
try:
- results = self.app.wallaby.activate_configuration()
+ call_async(self.callback, self.app.wallaby.activate_configuration)
except Exception, e:
invoc.status = invoc.FAILED
log.exception(e)
+ invoc.end()
- if len(results[0]) > 0:
- #process the map
- log.debug("Results from validate_configuration:")
- if len(results[1]) > 0:
- #process the list
- log.debug("Results from validate_configuration: %s" % results[1][0])
-
- invoc.end()
-
class AddTags(Task):
'''
This task is used to create a tag in wallaby without assigning it to any nodes.
@@ -1138,28 +1160,32 @@
super(AddTags, self).__init__(app)
cls = app.model.com_redhat_cumin_grid.Node
self.form = CreateTags(app, self.name, self, cls)
+ self.invoc = None
+ self.calls = 0
def get_title(self, session, object):
return "Create tags"
+
+ def callback(self, result):
+ self.calls -= 1
+ if result == False:
+ self.invoc.status = self.invoc.FAILED
+ if(self.calls <= 0):
+ self.invoc.end()
def do_invoke(self, session, object, invoc, tag):
+ self.invoc = invoc
tags = [x.strip() for x in tag.split(',')]
- max_retries = 5
+ max_retries = 1
try:
for new_tag in tags:
- retries = 0
- while not self.app.wallaby.create_tag(new_tag) and retries < max_retries:
- retries += 1
- if retries < max_retries:
- log.info("Create tag: %s failed, retrying." % new_tag)
- else:
- log.error("Create tag: %s failed." % new_tag)
+ self.calls += 1
+ call_async(self.callback, self.app.wallaby.create_tag, new_tag)
except Exception, e:
invoc.status = invoc.FAILED
log.exception(e)
-
- invoc.end()
+ invoc.end()
class RemoveNodeTags(ObjectSelectorTask):
'''
@@ -1171,24 +1197,30 @@
super(RemoveNodeTags, self).__init__(app, selector)
cls = app.model.com_redhat_cumin_grid.Node
self.form = RemoveTags(app, self.name, self, cls)
+ self.invoc = None
def get_title(self, session):
return "Delete tags"
def invoke(self, session, selection):
- invoc = self.start(session, selection)
-
+ self.invoc = self.start(session, selection)
+
try:
- self.do_invoke(invoc, selection)
+ self.do_invoke(self.invoc, selection)
except Exception, e:
- invoc.exception = e
- invoc.status = invoc.FAILED
- invoc.end()
+ self.invoc.exception = e
+ self.invoc.status = self.invoc.FAILED
+ self.invoc.end()
+ def callback(self, result):
+ if result == False:
+ self.invoc.status = self.invoc.FAILED
+ self.invoc.end()
+
def do_invoke(self, invoc, tags):
try:
for tag_to_kill in tags:
- call_async(invoc.make_callback(), self.app.wallaby.remove_tag, tag_to_kill)
+ call_async(self.callback, self.app.wallaby.remove_tag, tag_to_kill)
except Exception, e:
invoc.status = invoc.FAILED
log.exception(e)
12 years, 8 months
r4975 - trunk/cumin/python/cumin/inventory
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-16 13:18:27 +0000 (Fri, 16 Sep 2011)
New Revision: 4975
Modified:
trunk/cumin/python/cumin/inventory/system.strings
Log:
Bringing the system::configuration view in-line with our standard property view
Modified: trunk/cumin/python/cumin/inventory/system.strings
===================================================================
--- trunk/cumin/python/cumin/inventory/system.strings 2011-09-15 21:03:59 UTC (rev 4974)
+++ trunk/cumin/python/cumin/inventory/system.strings 2011-09-16 13:18:27 UTC (rev 4975)
@@ -100,21 +100,18 @@
//]]>
</script>
-[SystemTagSet.css]
-table.topalign td {
- vertical-align: top;
-}
-
[SystemTagSet.html]
-<table class="{class} topalign">
+<table id="{id}" class="{class} PropertySet TagPropertySet">
+ <thead>
+ <tr>
+ <td>Property</td>
+ <td>Value</td>
+ </tr>
+ </thead>
<tbody>
- <tr>
- <th>
- Tags:
- </th>
- <td align="left">
- {tags}
- </td>
- </tr>
+ <tr class="item" title="">
+ <th>Tags:</th>
+ <td class="{class}">{tags}</td>
+ </tr>
</tbody>
</table>
\ No newline at end of file
12 years, 8 months
r4974 - trunk/cumin/python/cumin/inventory
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-15 21:03:59 +0000 (Thu, 15 Sep 2011)
New Revision: 4974
Modified:
trunk/cumin/python/cumin/inventory/system.py
Log:
Some more work on dealing with sesame/wallaby (one or the other) data merging. Also, making the tags column on the system table a bit smaller. This seems to fit nicely on my tablet, which ought to be close to, if not the lowest common denominator.
Modified: trunk/cumin/python/cumin/inventory/system.py
===================================================================
--- trunk/cumin/python/cumin/inventory/system.py 2011-09-15 20:42:58 UTC (rev 4973)
+++ trunk/cumin/python/cumin/inventory/system.py 2011-09-15 21:03:59 UTC (rev 4974)
@@ -218,18 +218,31 @@
#now get the wallaby data
wallaby_nodes = self.app.wallaby.get_data(WBTypes.NODES)
+
+ data = list()
- #now merge them
- for i, node in enumerate(wallaby_nodes):
- match_index = [i for i, y in enumerate(sqldata) if y[1] == node.name]
- if len(match_index) > 0:
- ## merge-in the wallaby data to the matched node entry in sqldata
- new_record = list(sqldata[match_index[0]])
- new_record.append(self.app.wallaby.get_tag_names(node))
- new_record.append(node.last_checkin)
- sqldata[match_index[0]] = tuple(new_record)
-
- return sqldata
+ if len(sqldata) > 0 and len(wallaby_nodes) > 0: #means that we have both sesame and wallaby data
+ #now merge them
+ for i, node in enumerate(wallaby_nodes):
+ match_index = [i for i, y in enumerate(sqldata) if y[1] == node.name]
+ if len(match_index) > 0:
+ ## merge-in the wallaby data to the matched node entry in sqldata
+ new_record = list(sqldata[match_index[0]])
+ new_record.append(self.app.wallaby.get_tag_names(node))
+ new_record.append(node.last_checkin)
+ sqldata[match_index[0]] = tuple(new_record)
+ data = sqldata
+ elif len(sqldata) > 0: # we only have sesame data
+ for node in sqldata:
+ node_data = list(node)
+ data_row = tuple([node_data[0], node_data[1], node_data[2], node_data[3], node_data[4], node_data[5], [], ""])
+ data.append(data_row)
+ else: # we have only wallaby data
+ for node in wallaby_nodes:
+ data_row = tuple(["", node.name, "", "", "", 0, self.app.wallaby.get_tag_names(node), node.last_checkin])
+ data.append(data_row)
+
+ return data
class DerivedTableColumn(ObjectTableColumn):
@@ -254,7 +267,7 @@
try:
value = record[self.index]
value = ",".join(value)
- value = truncate_text(value, 40, True)
+ value = truncate_text(value, 30, True)
except Exception, e:
pass
return value
12 years, 8 months
r4973 - trunk/cumin/python/cumin/grid
by croberts@fedoraproject.org
Author: croberts
Date: 2011-09-15 20:42:58 +0000 (Thu, 15 Sep 2011)
New Revision: 4973
Modified:
trunk/cumin/python/cumin/grid/tags.strings
Log:
Cleaning up styles by removing redundancy.
Modified: trunk/cumin/python/cumin/grid/tags.strings
===================================================================
--- trunk/cumin/python/cumin/grid/tags.strings 2011-09-15 20:33:19 UTC (rev 4972)
+++ trunk/cumin/python/cumin/grid/tags.strings 2011-09-15 20:42:58 UTC (rev 4973)
@@ -12,29 +12,18 @@
[TagGeneral.css]
-table.PropertySet {
- width: 100%;
- font-size: 0.9em;
- text-align: left;
- border-collapse; collapse;
-}
-
-table.PropertySet tbody td {
- border-top: 1px dotted #ccc;
-}
-
-table.PropertySet tbody th {
+table.TagPropertySet tbody th {
width:5%;
}
-table.PropertySet thead td {
+table.TagPropertySet thead td {
color: #666;
font-weight: normal;
font-style: italic;
}
[TagGeneral.html]
-<table id="{id}" class="PropertySet">
+<table id="{id}" class="PropertySet TagPropertySet">
<thead>
<tr>
<td>Property</td>
12 years, 8 months