From: richard Date: Sun, 21 Oct 2001 04:44:50 +0000 (+0000) Subject: bug #473124: UI inconsistency with Link fields. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=4e33199485736318571cf78644c2a4c94e645987;p=roundup.git 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. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@322 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/CHANGES.txt b/CHANGES.txt index 3dc98a9..23bcb26 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,6 +3,7 @@ are given with the most recent entry first. 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. @@ -20,9 +21,12 @@ Fixed: 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 55ced04..e46098b 100644 --- a/roundup/cgi_client.py +++ b/roundup/cgi_client.py @@ -15,7 +15,7 @@ # 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 @@ -129,7 +129,7 @@ class Client: 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 @@ -141,6 +141,7 @@ class Client: 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 @@ -173,24 +174,32 @@ class Client: 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) @@ -216,7 +225,7 @@ class Client: 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() @@ -676,7 +685,7 @@ class ExtendedClient(Client): 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']} @@ -699,8 +708,8 @@ class ExtendedClient(Client): if self.user not in (None, 'anonymous'): userid = self.db.user.lookup(self.user) user_info = ''' -My Issues | -My Support | +My Issues | +My Support | My Details | Logout '''%(userid, userid, userid) else: @@ -725,11 +734,11 @@ class ExtendedClient(Client): %s All -Issues, -Support +Issues, +Support | Unassigned -Issues, -Support +Issues, +Support %s %s %s @@ -758,14 +767,19 @@ def parsePropsFromForm(db, cl, form, nodeid=0): 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([]): @@ -794,6 +808,10 @@ def parsePropsFromForm(db, cl, form, nodeid=0): # # $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. diff --git a/roundup/htmltemplate.py b/roundup/htmltemplate.py index c65ef4d..c720bb1 100644 --- a/roundup/htmltemplate.py +++ b/roundup/htmltemplate.py @@ -15,7 +15,7 @@ # 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 @@ -116,6 +116,11 @@ class Field(Base): linkcl = self.db.classes[propclass.classname] l = [''%property] k = linkcl.labelprop() + s = '' + if value is None: + s = 'selected ' + l.append(''%s) for optionid in linkcl.list(): option = linkcl.get(optionid, k) s = '' @@ -335,6 +344,15 @@ class Checklist(Base): checked = '' l.append('%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]:'%(checked, property)) return '\n'.join(l) class Note(Base): @@ -529,12 +547,88 @@ def index(client, templates, db, classname, filterspec={}, filter=[], 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('\n') + w('\n') + for name in columns: + cname = name.capitalize() + if show_display_form: + anchor = "%s?%s"%(classname, sortby(name, columns, filter, + sort, group, filterspec)) + w('\n'%( + anchor, cname)) + else: + w('\n'%cname) + w('\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('' + ''%( + 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('
%s%s
%s
') + + +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('' % show_customization ) w('\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('') @@ -616,75 +710,6 @@ def index(client, templates, db, classname, filterspec={}, filter=[], w('
\n') w('\n') - # now display the index section - w('\n') - w('\n') - for name in columns: - cname = name.capitalize() - if show_display_form: - anchor = "%s?%s"%(classname, sortby(name, columns, filter, - sort, group, filterspec)) - w('\n'%( - anchor, cname)) - else: - w('\n'%cname) - w('\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('' - ''%( - 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('
%s%s
%s
') - - # # ITEM TEMPLATES # @@ -790,6 +815,10 @@ def newitem(client, templates, db, classname, form, replace=re.compile( # # $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 391c6f3..8bcd4e9 100644 --- a/roundup/hyperdb.py +++ b/roundup/hyperdb.py @@ -15,7 +15,7 @@ # 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 @@ -584,11 +584,12 @@ class Class: 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) @@ -846,6 +847,9 @@ def Choice(name, *options): # # $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. #