summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1441bf6)
raw | patch | inline | side by side (parent: 1441bf6)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sun, 21 Oct 2001 04:44:50 +0000 (04:44 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sun, 21 Oct 2001 04:44:50 +0000 (04:44 +0000) |
This also prompted me to fix a fairly long-standing usability issue -
that of being able to turn off certain filters.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@322 57a73879-2fb5-44c3-a270-3262357dd7e2
that of being able to turn off certain filters.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@322 57a73879-2fb5-44c3-a270-3262357dd7e2
CHANGES.txt | patch | blob | history | |
roundup/cgi_client.py | patch | blob | history | |
roundup/htmltemplate.py | patch | blob | history | |
roundup/hyperdb.py | patch | blob | history |
diff --git a/CHANGES.txt b/CHANGES.txt
index 3dc98a97268383df849de09878a06c71b6207f65..23bcb266bbf7a7cbfa014ee24dd2ddc84d3b8724 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
2001-10-?? - 0.3.0
Feature:
+ . MailGW now moves 'unread' to 'chatting' on receiving e-mail for an issue.
Admin Tool (roundup-admin):
. Interactive mode for running multiple (independant at present) commands.
. Tabular display of nodes.
customisation section may now be hidden (patch from Roch'e Compaan.)
. bug #473122: Issue id sorting (hyperdb sorts strings-that-look-like-numbers
as numbers now.
+ . bug #473124: UI inconsistency with Link fields.
+ This also prompted me to fix a fairly long-standing usability issue -
+ that of being able to turn off certain filters.
+ . bug #473125: Paragraph in e-mails
. bug #473126: Sender unknown
. bug #473130: Nosy list not set correctly
- . bug #473125: Paragraph in e-mails
2001-10-11 - 0.3.0 pre 2
Fixed:
diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py
index 55ced042a158a93b77fd0e0016a7695d14c4afd7..e46098ba0aa2273593bbb56c400825db403dddb4 100644 (file)
--- a/roundup/cgi_client.py
+++ b/roundup/cgi_client.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: cgi_client.py,v 1.35 2001-10-21 00:17:54 richard Exp $
+# $Id: cgi_client.py,v 1.36 2001-10-21 04:44:50 richard Exp $
import os, cgi, pprint, StringIO, urlparse, re, traceback, mimetypes
import base64, Cookie, time
return arg.value.split(',')
return []
- def index_filterspec(self):
+ def index_filterspec(self, filter):
''' pull the index filter spec from the form
Links and multilinks want to be lists - the rest are straight
for key in self.form.keys():
if key[0] == ':': continue
if not props.has_key(key): continue
+ if key not in filter: continue
prop = props[key]
value = self.form[key]
if (isinstance(prop, hyperdb.Link) or
default_index_sort = ['-activity']
default_index_group = ['priority']
- default_index_filter = []
+ default_index_filter = ['status']
default_index_columns = ['id','activity','title','status','assignedto']
default_index_filterspec = {'status': ['1', '2', '3', '4', '5', '6', '7']}
def index(self):
''' put up an index
'''
self.classname = 'issue'
- if self.form.has_key(':sort'): sort = self.index_arg(':sort')
- else: sort = self.default_index_sort
- if self.form.has_key(':group'): group = self.index_arg(':group')
- else: group = self.default_index_group
- if self.form.has_key(':filter'): filter = self.index_arg(':filter')
- else: filter = self.default_index_filter
- if self.form.has_key(':columns'): columns = self.index_arg(':columns')
- else: columns = self.default_index_columns
- filterspec = self.index_filterspec()
- if not filterspec:
+ # see if the web has supplied us with any customisation info
+ defaults = 1
+ for key in ':sort', ':group', ':filter', ':columns':
+ if self.form.has_key(key):
+ defaults = 0
+ break
+ if defaults:
+ # no info supplied - use the defaults
+ sort = self.default_index_sort
+ group = self.default_index_group
+ filter = self.default_index_filter
+ columns = self.default_index_columns
filterspec = self.default_index_filterspec
+ else:
+ sort = self.index_arg(':sort')
+ group = self.index_arg(':group')
+ filter = self.index_arg(':filter')
+ columns = self.index_arg(':columns')
+ filterspec = self.index_filterspec(filter)
return self.list(columns=columns, filter=filter, group=group,
sort=sort, filterspec=filterspec)
if group is None: group = self.index_arg(':group')
if filter is None: filter = self.index_arg(':filter')
if columns is None: columns = self.index_arg(':columns')
- if filterspec is None: filterspec = self.index_filterspec()
+ if filterspec is None: filterspec = self.index_filterspec(filter)
if show_customization is None:
show_customization = self.customization_widget()
default_index_sort = ['-activity']
default_index_group = ['priority']
- default_index_filter = []
+ default_index_filter = ['status']
default_index_columns = ['activity','status','title','assignedto']
default_index_filterspec = {'status': ['1', '2', '3', '4', '5', '6', '7']}
if self.user not in (None, 'anonymous'):
userid = self.db.user.lookup(self.user)
user_info = '''
-<a href="issue?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">My Issues</a> |
-<a href="support?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">My Support</a> |
+<a href="issue?assignedto=%s&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:filter=status,assignedto&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">My Issues</a> |
+<a href="support?assignedto=%s&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:filter=status,assignedto&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">My Support</a> |
<a href="user%s">My Details</a> | <a href="logout">Logout</a>
'''%(userid, userid, userid)
else:
<td align=right valign=bottom>%s</td></tr>
<tr class="location-bar">
<td align=left>All
-<a href="issue?status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
-<a href="support?status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
+<a href="issue?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
+<a href="support?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
| Unassigned
-<a href="issue?assignedto=admin&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
-<a href="support?assignedto=admin&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
+<a href="issue?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
+<a href="support?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
%s
%s</td>
<td align=right>%s</td>
value = date.Interval(form[key].value.strip())
elif isinstance(proptype, hyperdb.Link):
value = form[key].value.strip()
- # handle key values
- link = cl.properties[key].classname
- if not num_re.match(value):
- try:
- value = db.classes[link].lookup(value)
- except KeyError:
- raise ValueError, 'property "%s": %s not a %s'%(
- key, value, link)
+ # see if it's the "no selection" choice
+ if value == '-1':
+ # don't set this property
+ continue
+ else:
+ # handle key values
+ link = cl.properties[key].classname
+ if not num_re.match(value):
+ try:
+ value = db.classes[link].lookup(value)
+ except KeyError:
+ raise ValueError, 'property "%s": %s not a %s'%(
+ key, value, link)
elif isinstance(proptype, hyperdb.Multilink):
value = form[key]
if type(value) != type([]):
#
# $Log: not supported by cvs2svn $
+# Revision 1.35 2001/10/21 00:17:54 richard
+# CGI interface view customisation section may now be hidden (patch from
+# Roch'e Compaan.)
+#
# Revision 1.34 2001/10/20 11:58:48 richard
# Catch errors in login - no username or password supplied.
# Fixed editing of password (Password property type) thanks Roch'e Compaan.
index c65ef4dea6763cd0ad5db16f6df981b888585938..c720bb18f310976a1d915292b5bcdf3b832580a0 100644 (file)
--- a/roundup/htmltemplate.py
+++ b/roundup/htmltemplate.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: htmltemplate.py,v 1.29 2001-10-21 00:17:56 richard Exp $
+# $Id: htmltemplate.py,v 1.30 2001-10-21 04:44:50 richard Exp $
import os, re, StringIO, urllib, cgi, errno
linkcl = self.db.classes[propclass.classname]
l = ['<select name="%s">'%property]
k = linkcl.labelprop()
+ if value is None:
+ s = 'selected '
+ else:
+ s = ''
+ l.append('<option %svalue="-1">- no selection -</option>'%s)
for optionid in linkcl.list():
option = linkcl.get(optionid, k)
s = ''
linkcl = self.db.classes[propclass.classname]
l = ['<select name="%s">'%property]
k = linkcl.labelprop()
+ s = ''
+ if value is None:
+ s = 'selected '
+ l.append('<option %svalue="-1">- no selection -</option>'%s)
for optionid in linkcl.list():
option = linkcl.get(optionid, k)
s = ''
checked = ''
l.append('%s:<input type="checkbox" %s name="%s" value="%s">'%(
option, checked, property, option))
+
+ # for Links, allow the "unselected" option too
+ if isinstance(propclass, hyperdb.Link):
+ if value is None or '-1' in value:
+ checked = 'checked'
+ else:
+ checked = ''
+ l.append('[unselected]:<input type="checkbox" %s name="%s" '
+ 'value="-1">'%(checked, property))
return '\n'.join(l)
class Note(Base):
l.append(name)
columns = l
+ # display the filter section
+ filter_section(w, cl, filter, columns, group, all_filters, all_columns,
+ show_display_form, show_customization)
+
+ # now display the index section
+ w('<table width=100% border=0 cellspacing=0 cellpadding=2>\n')
+ w('<tr class="list-header">\n')
+ for name in columns:
+ cname = name.capitalize()
+ if show_display_form:
+ anchor = "%s?%s"%(classname, sortby(name, columns, filter,
+ sort, group, filterspec))
+ w('<td><span class="list-header"><a href="%s">%s</a></span></td>\n'%(
+ anchor, cname))
+ else:
+ w('<td><span class="list-header">%s</span></td>\n'%cname)
+ w('</tr>\n')
+
+ # this stuff is used for group headings - optimise the group names
+ old_group = None
+ group_names = []
+ if group:
+ for name in group:
+ if name[0] == '-': group_names.append(name[1:])
+ else: group_names.append(name)
+
+ # now actually loop through all the nodes we get from the filter and
+ # apply the template
+ if nodeids is None:
+ nodeids = cl.filter(filterspec, sort, group)
+ for nodeid in nodeids:
+ # check for a group heading
+ if group_names:
+ this_group = [cl.get(nodeid, name) for name in group_names]
+ if this_group != old_group:
+ l = []
+ for name in group_names:
+ prop = properties[name]
+ if isinstance(prop, hyperdb.Link):
+ group_cl = db.classes[prop.classname]
+ key = group_cl.getkey()
+ value = cl.get(nodeid, name)
+ if value is None:
+ l.append('[unselected %s]'%prop.classname)
+ else:
+ l.append(group_cl.get(cl.get(nodeid, name), key))
+ elif isinstance(prop, hyperdb.Multilink):
+ group_cl = db.classes[prop.classname]
+ key = group_cl.getkey()
+ for value in cl.get(nodeid, name):
+ l.append(group_cl.get(value, key))
+ else:
+ value = cl.get(nodeid, name)
+ if value is None:
+ value = '[empty %s]'%name
+ else:
+ value = str(value)
+ l.append(value)
+ w('<tr class="section-bar">'
+ '<td align=middle colspan=%s><strong>%s</strong></td></tr>'%(
+ len(columns), ', '.join(l)))
+ old_group = this_group
+
+ # display this node's row
+ for value in globals.values():
+ if hasattr(value, 'nodeid'):
+ value.nodeid = nodeid
+ replace = IndexTemplateReplace(globals, locals(), columns)
+ w(replace.go(template))
+
+ w('</table>')
+
+
+def filter_section(w, cl, filter, columns, group, all_filters, all_columns,
+ show_display_form, show_customization):
# now add in the filter/columns/group/etc config table form
w('<input type="hidden" name="show_customization" value="%s">' %
show_customization )
w('<table width=100% border=0 cellspacing=0 cellpadding=2>\n')
names = []
- for name in cl.getprops().keys():
+ properties = cl.getprops()
+ for name in properties.keys():
if name in all_filters or name in all_columns:
names.append(name)
w('<tr class="location-bar">')
w('</table>\n')
w('</form>\n')
- # now display the index section
- w('<table width=100% border=0 cellspacing=0 cellpadding=2>\n')
- w('<tr class="list-header">\n')
- for name in columns:
- cname = name.capitalize()
- if show_display_form:
- anchor = "%s?%s"%(classname, sortby(name, columns, filter,
- sort, group, filterspec))
- w('<td><span class="list-header"><a href="%s">%s</a></span></td>\n'%(
- anchor, cname))
- else:
- w('<td><span class="list-header">%s</span></td>\n'%cname)
- w('</tr>\n')
-
- # this stuff is used for group headings - optimise the group names
- old_group = None
- group_names = []
- if group:
- for name in group:
- if name[0] == '-': group_names.append(name[1:])
- else: group_names.append(name)
-
- # now actually loop through all the nodes we get from the filter and
- # apply the template
- if nodeids is None:
- nodeids = cl.filter(filterspec, sort, group)
- for nodeid in nodeids:
- # check for a group heading
- if group_names:
- this_group = [cl.get(nodeid, name) for name in group_names]
- if this_group != old_group:
- l = []
- for name in group_names:
- prop = properties[name]
- if isinstance(prop, hyperdb.Link):
- group_cl = db.classes[prop.classname]
- key = group_cl.getkey()
- value = cl.get(nodeid, name)
- if value is None:
- l.append('[unselected %s]'%prop.classname)
- else:
- l.append(group_cl.get(cl.get(nodeid, name), key))
- elif isinstance(prop, hyperdb.Multilink):
- group_cl = db.classes[prop.classname]
- key = group_cl.getkey()
- for value in cl.get(nodeid, name):
- l.append(group_cl.get(value, key))
- else:
- value = cl.get(nodeid, name)
- if value is None:
- value = '[empty %s]'%name
- else:
- value = str(value)
- l.append(value)
- w('<tr class="section-bar">'
- '<td align=middle colspan=%s><strong>%s</strong></td></tr>'%(
- len(columns), ', '.join(l)))
- old_group = this_group
-
- # display this node's row
- for value in globals.values():
- if hasattr(value, 'nodeid'):
- value.nodeid = nodeid
- replace = IndexTemplateReplace(globals, locals(), columns)
- w(replace.go(template))
-
- w('</table>')
-
-
#
# ITEM TEMPLATES
#
#
# $Log: not supported by cvs2svn $
+# Revision 1.29 2001/10/21 00:17:56 richard
+# CGI interface view customisation section may now be hidden (patch from
+# Roch'e Compaan.)
+#
# Revision 1.28 2001/10/21 00:00:16 richard
# Fixed Checklist function - wasn't always working on a list.
#
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index 391c6f3c1b80a411dd6d4ebc12a8974c3ed07ad4..8bcd4e919ef474deb227f0dc786336318e2a0f4f 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.27 2001-10-20 23:44:27 richard Exp $
+# $Id: hyperdb.py,v 1.28 2001-10-21 04:44:50 richard Exp $
# standard python modules
import cPickle, re, string
u = []
link_class = self.db.classes[propclass.classname]
for entry in v:
- if not num_re.match(entry):
+ if entry == '-1': entry = None
+ elif not num_re.match(entry):
try:
entry = link_class.lookup(entry)
except:
- raise ValueError, 'new property "%s": %s not a %s'%(
+ raise ValueError, 'property "%s": %s not a %s'%(
k, entry, self.properties[k].classname)
u.append(entry)
#
# $Log: not supported by cvs2svn $
+# Revision 1.27 2001/10/20 23:44:27 richard
+# Hyperdatabase sorts strings-that-look-like-numbers as numbers now.
+#
# Revision 1.26 2001/10/16 03:48:01 richard
# admin tool now complains if a "find" is attempted with a non-link property.
#