Code

Added reindex command to roundup-admin.
[roundup.git] / doc / customizing.txt
1 ===================
2 Customising Roundup
3 ===================
5 :Version: $Revision: 1.9 $
7 .. contents::
10 Instances have the following structure:
12 +-------------------+--------------------------------------------------------+
13 |instance_config.py |Holds the basic instance_configuration                  |
14 +-------------------+--------------------------------------------------------+
15 |dbinit.py          |Holds the instance_schema                               |
16 +-------------------+--------------------------------------------------------+
17 |interfaces.py      |Defines the Web and E-Mail interfaces for the instance  |
18 +-------------------+--------------------------------------------------------+
19 |select_db.py       |Selects the database back-end for the instance          |
20 +-------------------+--------------------------------------------------------+
21 |db/                |Holds the instance's database                           |
22 +-------------------+--------------------------------------------------------+
23 |db/files/          |Holds the instance's upload files and messages          |
24 +-------------------+--------------------------------------------------------+
25 |detectors/         |Auditors and reactors for this instance                 |
26 +-------------------+--------------------------------------------------------+
27 |html/              |Web interface templates, images and style sheets        |
28 +-------------------+--------------------------------------------------------+
30 Instance Configuration
31 ----------------------
33 The instance_config.py located in your instance home contains the basic
34 configuration for the web and e-mail components of roundup's interfaces. This
35 file is a Python module. The configuration variables available are:
37 **INSTANCE_HOME** - ``os.path.split(__file__)[0]``
38  The instance home directory. The above default code will automatically
39  determine the instance home for you.
41 **MAILHOST** - ``'localhost'``
42  The SMTP mail host that roundup will use to send e-mail.
44 **MAIL_DOMAIN** - ``'your.tracker.email.domain.example'``
45  The domain name used for email addresses.
47 **DATABASE** - ``os.path.join(INSTANCE_HOME, 'db')``
48  This is the directory that the database is going to be stored in. By default
49  it is in the instance home.
51 **TEMPLATES** - ``os.path.join(INSTANCE_HOME, 'html')``
52  This is the directory that the HTML templates reside in. By default they are
53  in the instance home.
55 **INSTANCE_NAME** - ``'Roundup issue tracker'``
56  A descriptive name for your roundup instance. This is sent out in e-mails and
57  appears in the heading of CGI pages.
59 **ISSUE_TRACKER_EMAIL** - ``'issue_tracker@%s'%MAIL_DOMAIN``
60  The email address that e-mail sent to roundup should go to. Think of it as the
61  instance's personal e-mail address.
63 **ISSUE_TRACKER_WEB** - ``'http://your.tracker.url.example/'``
64  The web address that the instance is viewable at. This will be included in
65  information sent to users of the tracker.
67 **ADMIN_EMAIL** - ``'roundup-admin@%s'%MAIL_DOMAIN``
68  The email address that roundup will complain to if it runs into trouble.
70 **FILTER_POSITION** - ``'top'``, ``'bottom'`` or ``'top and bottom'``
71  Where to place the web filtering HTML on the index page.
73 **ANONYMOUS_ACCESS** - ``'deny'`` or ``'allow'``
74  Deny or allow anonymous access to the web interface.
76 **ANONYMOUS_REGISTER** - ``'deny'`` or ``'allow'``
77  Deny or allow anonymous users to register through the web interface.
79 **ANONYMOUS_REGISTER_MAIL** - ``'deny'`` or ``'allow'``
80  Deny or allow anonymous users to register through the mail interface.
82 **MESSAGES_TO_AUTHOR** - ``'yes'`` or``'no'``
83  Send nosy messages to the author of the message.
85 **ADD_AUTHOR_TO_NOSY** - ``'new'``, ``'yes'`` or ``'no'``
86  Does the author of a message get placed on the nosy list automatically?
87  If ``'new'`` is used, then the author will only be added when a message
88  creates a new issue. If ``'yes'``, then the author will be added on followups
89  too. If ``'no'``, they're never added to the nosy.
91 **ADD_RECIPIENTS_TO_NOSY** - ``'new'``, ``'yes'`` or ``'no'``
92  Do the recipients (To:, Cc:) of a message get placed on the nosy list?
93  If ``'new'`` is used, then the recipients will only be added when a message
94  creates a new issue. If ``'yes'``, then the recipients will be added on
95  followups too. If ``'no'``, they're never added to the nosy.
97 **EMAIL_SIGNATURE_POSITION** - ``'top'``, ``'bottom'`` or ``'none'``
98  Where to place the email signature in messages that Roundup generates.
100 **EMAIL_KEEP_QUOTED_TEXT** - ``'yes'`` or ``'no'``
101  Keep email citations. Citations are the part of e-mail which the sender has
102  quoted in their reply to previous e-mail.
104 **EMAIL_LEAVE_BODY_UNCHANGED** - ``'no'``
105  Preserve the email body as is. Enabiling this will cause the entire message
106  body to be stored, including all citations and signatures. It should be
107  either ``'yes'`` or ``'no'``.
109 **MAIL_DEFAULT_CLASS** - ``'issue'`` or ``''``
110  Default class to use in the mailgw if one isn't supplied in email
111  subjects. To disable, comment out the variable below or leave it blank.
113 **HEADER_INDEX_LINKS** - ``['DEFAULT', 'UNASSIGNED', 'USER']``
114  Define what index links are available in the header, and what their
115  labels are. Each key is used to look up one of the index specifications
116  below - so ``'DEFAULT'`` will use ``'DEFAULT_INDEX'``.
118  Example ``DEFAULT_INDEX``::
120   {
121    'LABEL': 'All Issues',
122    'CLASS': 'issue',
123    'SORT': ['-activity'],
124    'GROUP': ['priority'],
125    'FILTER': ['status'],
126    'COLUMNS': ['id','activity','title','creator','assignedto'],
127    'FILTERSPEC': {
128      'status': ['-1', '1', '2', '3', '4', '5', '6', '7'],
129    },
130   }
132  This defines one of the index links that appears in the
133  ``HEADER_INDEX_LINKS`` list.
135  **LABEL** - ``'All Issues'``
136   The text that appears as the link label.
137  **CLASS** - ``'issue'``
138   The class to display the index for.
139  **SORT** - ``['-activity']``
140   Sort by prop name, optionally preceeded with '-' to give descending or
141   nothing for ascending sorting.
142  **GROUP** - ``['priority']``
143   Group by prop name, optionally preceeded with '-' or to sort in descending
144   or nothing for ascending order.
145  **FILTER** - ``['status']``
146   Selects which props should be displayed in the filter section.
147   Default is all. 
148  **COLUMNS** - ``['id','activity','title','creator','assignedto']``
149   Selects the columns that should be displayed. Default is all.
150  **FILTERSPEC** - *a dictionary giving the filter specification*
151   The ``FILTERSPEC`` gives the filtering arguments. This selects the values
152   the node properties given by propname must have.
154   Where the ``FILTERSPEC`` value is ``'CURRENT USER'``, it will be replaced
155   by the id of the logged-in user. For example::
157    'FILTERSPEC': {
158      'status': ['-1', '1', '2', '3', '4', '5', '6', '7'],
159      'assignedto': 'CURRENT USER',
160    },
162 **HEADER_ADD_LINKS** - ``['issue']``
163  List the classes that users are able to add nodes to.
165 **HEADER_SEARCH_LINKS** - ``['issue']``
166  List the classes that users can search.
168 **SEARCH_FILTERS** - ``['ISSUE_FILTER', 'SUPPORT_FILTER']``
169  List search filters per class. Like the INDEX entries above, each key is
170  used to look up one of the filter specifications below - so ``'ISSUE'``
171  will use ``'ISSUE_FILTER'``.
173  Example ``ISSUE_FILTER``::
175   ISSUE_FILTER = {
176     'CLASS': 'issue',
177     'FILTER': ['status', 'priority', 'assignedto', 'creator']
178   }
180   **CLASS** - ``'issue'``
181    The class that the search page is for.
182   **FILTER** - ``['status', 'priority', 'assignedto', 'creator']``
183    Selects which props should be displayed on the filter page. Default is
184    all.
186 The default instance_config.py is given below - as you
187 can see, the MAIL_DOMAIN must be edited before any interaction with the
188 instance is attempted.::
190     # roundup home is this package's directory
191     INSTANCE_HOME=os.path.split(__file__)[0]
193     # The SMTP mail host that roundup will use to send mail
194     MAILHOST = 'localhost'
196     # The domain name used for email addresses.
197     MAIL_DOMAIN = 'your.tracker.email.domain.example'
199     # the next two are only used for the standalone HTTP server.
200     HTTP_HOST = ''
201     HTTP_PORT = 9080
203     # This is the directory that the database is going to be stored in
204     DATABASE = os.path.join(INSTANCE_HOME, 'db')
206     # This is the directory that the HTML templates reside in
207     TEMPLATES = os.path.join(INSTANCE_HOME, 'html')
209     # A descriptive name for your roundup instance
210     INSTANCE_NAME = 'Roundup issue tracker'
212     # The email address that mail to roundup should go to
213     ISSUE_TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
215     # The web address that the instance is viewable at
216     ISSUE_TRACKER_WEB = 'http://your.tracker.url.example/'
218     # The email address that roundup will complain to if it runs into trouble
219     ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
221     # Somewhere for roundup to log stuff internally sent to stdout or stderr
222     LOG = os.path.join(INSTANCE_HOME, 'roundup.log')
224     # Where to place the web filtering HTML on the index page
225     FILTER_POSITION = 'bottom'          # one of 'top', 'bottom', 'top and bottom'
227     # Deny or allow anonymous access to the web interface
228     ANONYMOUS_ACCESS = 'deny'           # either 'deny' or 'allow'
230     # Deny or allow anonymous users to register through the web interface
231     ANONYMOUS_REGISTER = 'deny'         # either 'deny' or 'allow'
233     # Deny or allow anonymous users to register through the mail interface
234     ANONYMOUS_REGISTER_MAIL = 'deny'    # either 'deny' or 'allow'
236     # Send nosy messages to the author of the message
237     MESSAGES_TO_AUTHOR = 'no'           # either 'yes' or 'no'
239     # Does the author of a message get placed on the nosy list automatically?
240     # If 'new' is used, then the author will only be added when a message
241     # creates a new issue. If 'yes', then the author will be added on followups
242     # too. If 'no', they're never added to the nosy.
243     ADD_AUTHOR_TO_NOSY = 'new'          # one of 'yes', 'no', 'new'
245     # Do the recipients (To:, Cc:) of a message get placed on the nosy list?
246     # If 'new' is used, then the recipients will only be added when a message
247     # creates a new issue. If 'yes', then the recipients will be added on followups
248     # too. If 'no', they're never added to the nosy.
249     ADD_RECIPIENTS_TO_NOSY = 'new'      # either 'yes', 'no', 'new'
251     # Where to place the email signature
252     EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
254     # Keep email citations
255     EMAIL_KEEP_QUOTED_TEXT = 'no'       # either 'yes' or 'no'
257     # Preserve the email body as is
258     EMAIL_LEAVE_BODY_UNCHANGED = 'no'   # either 'yes' or 'no'
260     # Default class to use in the mailgw if one isn't supplied in email
261     # subjects. To disable, comment out the variable below or leave it blank.
262     # Examples:
263     MAIL_DEFAULT_CLASS = 'issue'   # use "issue" class by default
264     #MAIL_DEFAULT_CLASS = ''        # disable (or just comment the var out)
266     # Define what index links are available in the header, and what their
267     # labels are. Each key is used to look up one of the index specifications
268     # below - so 'DEFAULT' will use 'DEFAULT_INDEX'.
269     # Where the FILTERSPEC has 'assignedto' with a value of None, it will be
270     # replaced by the id of the logged-in user.
271     HEADER_INDEX_LINKS = ['DEFAULT', 'UNASSIGNED', 'USER']
273     # list the classes that users are able to add nodes to
274     HEADER_ADD_LINKS = ['issue']
276     # list the classes that users can search
277     HEADER_SEARCH_LINKS = ['issue']
279     # list search filters per class
280     SEARCH_FILTERS = ['ISSUE_FILTER', 'SUPPORT_FILTER']
282     # Now the DEFAULT display specification. TODO: describe format
283     DEFAULT_INDEX = {
284       'LABEL': 'All Issues',
285       'CLASS': 'issue',
286       'SORT': ['-activity'],
287       'GROUP': ['priority'],
288       'FILTER': ['status'],
289       'COLUMNS': ['id','activity','title','creator','assignedto'],
290       'FILTERSPEC': {
291         'status': ['-1', '1', '2', '3', '4', '5', '6', '7'],
292       },
293     }
295     # The "unsassigned issues" index
296     UNASSIGNED_INDEX = {
297       'LABEL': 'Unassigned Issues',
298       'CLASS': 'issue',
299       'SORT': ['-activity'],
300       'GROUP': ['priority'],
301       'FILTER': ['status', 'assignedto'],
302       'COLUMNS': ['id','activity','title','creator','status'],
303       'FILTERSPEC': {
304         'status': ['-1', '1', '2', '3', '4', '5', '6', '7'],
305         'assignedto': ['-1'],
306       },
307     }
309     # The "my issues" index -- note that the user's id will replace the
310     # 'CURRENT USER' value of the "assignedto" filterspec
311     USER_INDEX = {
312       'LABEL': 'My Issues',
313       'CLASS': 'issue',
314       'SORT': ['-activity'],
315       'GROUP': ['priority'],
316       'FILTER': ['status', 'assignedto'],
317       'COLUMNS': ['id','activity','title','creator','status'],
318       'FILTERSPEC': {
319         'status': ['-1', '1', '2', '3', '4', '5', '6', '7'],
320         'assignedto': 'CURRENT USER',
321       },
322     }
324     ISSUE_FILTER = {
325       'CLASS': 'issue',
326       'FILTER': ['status', 'priority', 'assignedto', 'creator']
327     }
329     SUPPORT_FILTER = {
330       'CLASS': 'issue',
331       'FILTER': ['status', 'priority', 'assignedto', 'creator']
332     }
335 Instance Schema
336 ---------------
338 Note: if you modify the schema, you'll most likely need to edit the
339       `web interface`_ HTML template files to reflect your changes.
341 An instance schema defines what data is stored in the instance's database. The
342 two schemas shipped with Roundup turn it into a typical software bug tracker
343 (the extended schema allowing for support issues as well as bugs). Schemas are
344 defined using Python code. The "classic" schema looks like this::
346     pri = Class(db, "priority", name=String(), order=String())
347     pri.setkey("name")
348     pri.create(name="critical", order="1")
349     pri.create(name="urgent", order="2")
350     pri.create(name="bug", order="3")
351     pri.create(name="feature", order="4")
352     pri.create(name="wish", order="5")
354     stat = Class(db, "status", name=String(), order=String())
355     stat.setkey("name")
356     stat.create(name="unread", order="1")
357     stat.create(name="deferred", order="2")
358     stat.create(name="chatting", order="3")
359     stat.create(name="need-eg", order="4")
360     stat.create(name="in-progress", order="5")
361     stat.create(name="testing", order="6")
362     stat.create(name="done-cbb", order="7")
363     stat.create(name="resolved", order="8")
365     keyword = Class(db, "keyword", name=String())
366     keyword.setkey("name")
368     user = Class(db, "user", username=String(), password=String(),
369         address=String(), realname=String(), phone=String(),
370         organisation=String())
371     user.setkey("username")
372     user.create(username="admin", password=adminpw,
373         address=instance_config.ADMIN_EMAIL)
375     msg = FileClass(db, "msg", author=Link("user"), recipients=Multilink
376         ("user"), date=Date(), summary=String(), files=Multilink("file"))
378     file = FileClass(db, "file", name=String(), type=String())
380     issue = IssueClass(db, "issue", assignedto=Link("user"),
381         topic=Multilink("keyword"), priority=Link("priority"), status=Link
382         ("status"))
383     issue.setkey('title')
385 Classes and Properties - creating a new information store
386 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
388 In the instance above, we've defined 7 classes of information:
390   priority
391       Defines the possible levels of urgency for issues.
393   status
394       Defines the possible states of processing the issue may be in.
396   keyword
397       Initially empty, will hold keywords useful for searching issues.
399   user
400       Initially holding the "admin" user, will eventually have an entry for all
401       users using roundup.
403   msg
404       Initially empty, will all e-mail messages sent to or generated by
405       roundup.
407   file
408       Initially empty, will all files attached to issues.
410   issue
411       Initially emtyp, this is where the issue information is stored.
413 We define the "priority" and "status" classes to allow two things: reduction in
414 the amount of information stored on the issue and more powerful, accurate
415 searching of issues by priority and status. By only requiring a link on the
416 issue (which is stored as a single number) we reduce the chance that someone
417 mis-types a priority or status - or simply makes a new one up.
419 Class and Nodes
420 :::::::::::::::
422 A Class defines a particular class (or type) of data that will be stored in the
423 database. A class comprises one or more properties, which given the information
424 about the class nodes.
425 The actual data entered into the database, using class.create() are called
426 nodes. They have a special immutable property called id. We sometimes refer to
427 this as the nodeid.
429 Properties
430 ::::::::::
432 A Class is comprised of one or more properties of the following types:
433     * String properties are for storing arbitrary-length strings.
434     * Password properties are for storing encoded arbitrary-length strings. The
435       default encoding is defined on the roundup.password.Password class.
436     * Date properties store date-and-time stamps. Their values are Timestamp
437       objects.
438     * A Link property refers to a single other node selected from a specified
439       class. The class is part of the property; the value is an integer, the id
440       of the chosen node.
441     * A Multilink property refers to possibly many nodes in a specified class.
442       The value is a list of integers.
444 FileClass
445 :::::::::
447 FileClasses save their "content" attribute off in a separate file from the rest
448 of the database. This reduces the number of large entries in the database,
449 which generally makes databases more efficient, and also allows us to use
450 command-line tools to operate on the files. They are stored in the files sub-
451 directory of the db directory in your instance.
453 IssueClass
454 ::::::::::
456 IssueClasses automatically include the "messages", "files", "nosy", and
457 "superseder" properties.
458 The messages and files properties list the links to the messages and files
459 related to the issue. The nosy property is a list of links to users who wish to
460 be informed of changes to the issue - they get "CC'ed" e-mails when messages
461 are sent to or generated by the issue. The nosy reactor (in the detectors
462 directory) handles this action. The superceder link indicates an issue which
463 has superceded this one.
464 They also have the dynamically generated "creation", "activity" and "creator"
465 properties.
466 The value of the "creation" property is the date when a node was created, and
467 the value of the "activity" property is the date when any property on the node
468 was last edited (equivalently, these are the dates on the first and last
469 records in the node's journal). The "creator" property holds a link to the user
470 that created the issue.
472 setkey(property)
473 ::::::::::::::::
475 Select a String property of the class to be the key property. The key property
476 muse be unique, and allows references to the nodes in the class by the content
477 of the key property. That is, we can refer to users by their username, e.g.
478 let's say that there's an issue in roundup, issue 23. There's also a user,
479 richard who happens to be user 2. To assign an issue to him, we could do either
480 of::
482      roundup-admin set issue assignedto=2
484 or::
486      roundup-admin set issue assignedto=richard
488 Note, the same thing can be done in the web and e-mail interfaces.
490 create(information)
491 :::::::::::::::::::
493 Create a node in the database. This is generally used to create nodes in the
494 "definitional" classes like "priority" and "status".
497 Detectors - adding behaviour to your tracker
498 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
500 Sample additional detectors that have been found useful will appear in the
501 ``detectors`` directory of the Roundup distribution:
503 newissuecopy.py
504   This detector sends an email to a team address whenever a new issue is
505   created. The address is hard-coded into the detector, so edit it before you
506   use it (look for the text 'team@team.host') or you'll get email errors!
509 Web Interface
510 -------------
512 The web interface works behind the cgi-bin/roundup.cgi or roundup-server
513 scripts. In both cases, the scripts determine which instance is being accessed
514 (the first part of the URL path inside the scope of the CGI handler) and pass
515 control on to the instance interfaces.Client class which handles the rest of
516 the access through its main() method. This means that you can do pretty much
517 anything you want as a web interface to your instance.
518 Most customisation of the web view can be done by modifying the templates in
519 the instance html directory. These are divided into index, item and newitem
520 views. The newitem view is optional - the item view will be used if the newitem
521 view doesn't exist.
523 Repurcussions of changing the instance schema
524 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
526 If you choose to change_the_instance_schema you will need to ensure the web
527 interface knows about it:
529 1. Index, item and filter pages for the relevant classes may need to have
530    properties added or removed,
531 2. The default page header relies on the existence of, and some values of
532    the priority, status, assignedto and activity classes. If you change any
533    of these (specifically if you remove any of the classes or their default
534    values) you will need to implement your own pagehead() method in your
535    instance's interfaces.py module.
537 Displaying Properties
538 ~~~~~~~~~~~~~~~~~~~~~
540 Properties appear in the user interface in three contexts: in indices, in
541 editors, and as filters. For each type of property, there are several display
542 possibilities. For example, in an index view, a string property may just be
543 printed as a plain string, but in an editor view, that property should be
544 displayed in an editable field.
546 The display of a property is handled by functions in the htmltemplate module.
547 Displayer functions are triggered by <display> tags in templates. The call
548 attribute of the tag provides a Python expression for calling the displayer
549 function. The three standard arguments are inserted in front of the arguments
550 given. For example, the occurrence of::
552          <display call="plain('status')">
554 in a template triggers a call the "plain" function. The displayer functions can
555 accept extra arguments to further specify details about the widgets that should
556 be generated. By defining new displayer functions, the user interface can be
557 highly customized.
559 +-----------------------------------------------------------------------------+
560 |The displayer functions are                                                  |
561 +---------+-------------------------------------------------------------------+
562 |plain    |Display a String property directly.                                |
563 |         |Display a Date property in a specified time zone with an option to |
564 |         |omit the time from the date stamp.                                 |
565 |         |For a Link or Multilink property, display the key strings of the   |
566 |         |linked nodes (or the ids if the linked class has no key property). |
567 |         |Options:                                                           |
568 |         |escape (boolean) - HTML-escape the resulting text.                 |
569 +---------+-------------------------------------------------------------------+
570 |field    |Display a property like the plain displayer above, but in a form   |
571 |         |field to be edited. Strings, Dates and Intervals use TEXT fields,  |
572 |         |Links use SELECT fields and Multilinks use SELECT MULTIPLE fields. |
573 |         |Options:                                                           |
574 |         |size (number) - width of TEXT fields.                              |
575 |         |height (number) - number of nows in SELECT MULTIPLE tags.          |
576 |         |showid (boolean) - true includes the id of linked nodes in the     |
577 |         |SELECT MULTIPLE fields.                                            |
578 +---------+-------------------------------------------------------------------+
579 |menu     |For a Links and Multilinks, display the same field as would be     |
580 |         |generated using field.                                             |
581 +---------+-------------------------------------------------------------------+
582 |link     |For a Link or Multilink property, display the names of the linked  |
583 |         |nodes, hyperlinked to the item views on those nodes.               |
584 |         |For other properties, link to this node with the property as the   |
585 |         |text.                                                              |
586 |         |Options:                                                           |
587 |         |property (property name) - the property to use in the second case. |
588 |         |showid - use the linked node id as the link text (linked node      |
589 |         |"value" will be set as a tooltip)                                  |
590 +---------+-------------------------------------------------------------------+
591 |count    |For a Multilink property, display a count of the number of links in|
592 |         |the list.                                                          |
593 |         |Arguments:                                                         |
594 |         |property (property name) - the property to use.                    |
595 +---------+-------------------------------------------------------------------+
596 |reldate  |Display a Date property in terms of an interval relative to the    |
597 |         |current date (e.g. "+ 3w", "- 2d").                                |
598 |         |Arguments:                                                         |
599 |         |property (property name) - the property to use.                    |
600 |         |Options:                                                           |
601 |         |pretty (boolean) - display the relative date in an English form.   |
602 +---------+-------------------------------------------------------------------+
603 |download |For a Link or Multilink property, display the names of the linked  |
604 |         |nodes, hyperlinked to the item views on those nodes.               |
605 |         |For other properties, link to this node with the property as the   |
606 |         |text.                                                              |
607 |         |In all cases, append the name (key property) of the item to the    |
608 |         |path so it is the name of the file being downloaded.               |
609 |         |Arguments:                                                         |
610 |         |property (property name) - the property to use.                    |
611 +---------+-------------------------------------------------------------------+
612 |checklist|For a Link or Multilink property, display checkboxes for the       |
613 |         |available choices to permit filtering.                             |
614 |         |Arguments:                                                         |
615 |         |property (property name) - the property to use.                    |
616 +---------+-------------------------------------------------------------------+
617 |note     |Display the special notes field, which is a text area for entering |
618 |         |a note to go along with a change.                                  |
619 +---------+-------------------------------------------------------------------+
620 |list     |List the nodes specified by property using the standard index for  |
621 |         |the class.                                                         |
622 |         |Arguments:                                                         |
623 |         |property (property name) - the property to use.                    |
624 +---------+-------------------------------------------------------------------+
625 |history  |List the history of the item.                                      |
626 +---------+-------------------------------------------------------------------+
627 |submit   |Add a submit button for the item.                                  |
628 +---------+-------------------------------------------------------------------+
631 Index Views
632 ~~~~~~~~~~~
634 An index view contains two sections: a filter section and an index section. The
635 filter section provides some widgets for selecting which items appear in the
636 index. The index section is a table of items.
638 Index View Specifiers
639 :::::::::::::::::::::
641 An index view specifier (URL fragment) looks like this (whitespace has been
642 added for clarity)::
644      /issue?status=unread,in-progress,resolved&
645              topic=security,ui&
646              :group=+priority&
647              :sort=-activity&
648              :filters=status,topic&
649              :columns=title,status,fixer
651 The index view is determined by two parts of the specifier: the layout part and
652 the filter part. The layout part consists of the query parameters that begin
653 with colons, and it determines the way that the properties of selected nodes
654 are displayed. The filter part consists of all the other query parameters, and
655 it determines the criteria by which nodes are selected for display.
656 The filter part is interactively manipulated with the form widgets displayed in
657 the filter section. The layout part is interactively manipulated by clicking on
658 the column headings in the table.
660 The filter part selects the union of the sets of items with values matching any
661 specified Link properties and the intersection of the sets of items with values
662 matching any specified Multilink properties.
664 The example specifies an index of "issue" nodes. Only items with a "status" of
665 either "unread" or "in-progres" or "resolved" are displayed, and only items
666 with "topic" values including both "security" and "ui" are displayed. The items
667 are grouped by priority, arranged in ascending order; and within groups, sorted
668 by activity, arranged in descending order. The filter section shows filters for
669 the "status" and "topic" properties, and the table includes columns for the
670 "title", "status", and "fixer" properties.
672 Associated with each item class is a default layout specifier. The layout
673 specifier in the above example is the default layout to be provided with the
674 default bug-tracker schema described above in section 4.4.
676 Filter Section
677 ::::::::::::::
679 The template for a filter section provides the filtering widgets at the top of
680 the index view. Fragments enclosed in <property>...</property> tags are
681 included or omitted depending on whether the view specifier requests a filter
682 for a particular property.
684 A property must appear in the filter template for it to be available as a
685 filter.
687 Here's a simple example of a filter template.::
689      <property name=status>
690          <display call="checklist('status')">
691      </property>
692      <br>
693      <property name=priority>
694          <display call="checklist('priority')">
695      </property>
696      <br>
697      <property name=fixer>
698          <display call="menu('fixer')">
699      </property>
701 The standard index generation code appends a section to the index pages which
702 allows selection of the filters - from those which are defined in the filter
703 template.
705 Index Section
706 :::::::::::::
708 The template for an index section describes one row of the index table.
709 Fragments enclosed in <property>...</property> tags are included or omitted
710 depending on whether the view specifier requests a column for a particular
711 property. The table cells should contain <display> tags to display the values
712 of the item's properties.
714 Here's a simple example of an index template.::
716      <tr>
717          <property name=title>
718              <td><display call="plain('title', max=50)"></td>
719          </property>
720          <property name=status>
721              <td><display call="plain('status')"></td>
722          </property>
723          <property name=fixer>
724              <td><display call="plain('fixer')"></td>
725          </property>
726      </tr>
728 Sorting
729 :::::::
731 String and Date values are sorted in the natural way. Link properties are
732 sorted according to the value of the "order" property on the linked nodes if it
733 is present; or otherwise on the key string of the linked nodes; or finally on
734 the node ids. Multilink properties are sorted according to how many links are
735 present.
737 Item Views
738 ~~~~~~~~~~
740 An item view contains an editor section and a spool section. At the top of an
741 item view, links to superseding and superseded items are always displayed.
743 Editor Section
744 ::::::::::::::
746 The editor section is generated from a template containing <display> tags to
747 insert the appropriate widgets for editing properties.
749 Here's an example of a basic editor template.::
751      <table>
752      <tr>
753          <td colspan=2>
754              <display call="field('title', size=60)">
755          </td>
756      </tr>
757      <tr>
758          <td>
759              <display call="field('fixer', size=30)">
760          </td>
761          <td>
762              <display call="menu('status')>
763          </td>
764      </tr>
765      <tr>
766          <td>
767              <display call="field('nosy', size=30)">
768          </td>
769          <td>
770              <display call="menu('priority')>
771          </td>
772      </tr>
773      <tr>
774          <td colspan=2>
775              <display call="note()">
776          </td>
777      </tr>
778      </table>
780 As shown in the example, the editor template can also request the display of a
781 "note" field, which is a text area for entering a note to go along with a
782 change.
784 The <property> tag used in the index may also be used here - it checks to see
785 if the nominated Multilink property has any entries. This can be used to
786 eliminate sections of the editor section if the property has no entries::
788   <td class="form-text">
789     <display call="field('superseder', size=40, showid=1)">
790     <display call="classhelp('issue', 'id,title', label='list', width=500)">
791     <property name="superseder">
792       <br>View: <display call="link('superseder', showid=1)">
793     </property>
794   </td>
796 The "View: " part with the links will only display if the superseder property
797 has values.
799 When a change is submitted, the system automatically generates a message
800 describing the changed properties.
802 If a note is given in the "note" field, the note is appended to the
803 description. The message is then added to the item's message spool (thus
804 triggering the standard detector to react by sending out this message to the
805 nosy list).
807 The message also displays all of the property values on the item and indicates
808 which ones have changed. An example of such a message might be this::
810      Polly's taken a turn for the worse - this is now really important!
811      -----
812      title: Polly Parrot is dead
813      priority: critical
814      status: unread -> in-progress
815      fixer: terry
816      keywords: parrot,plumage,perch,nailed,dead
818 Spool Section
819 :::::::::::::
821 The spool section lists messages in the item's "messages" property. The index
822 of messages displays the "date", "author", and "summary" properties on the
823 message nodes, and selecting a message takes you to its content.
825 The <property> tag used in the index may also be used here - it checks to see
826 if the nominated Multilink property has any entries. This can be used to
827 eliminate sections of the spool section if the property has no entries::
829      <property name="files">
830       <tr class="strong-header">
831        <td><b>Files</b></td>
832       </tr>
834       <tr>
835        <td><display call="list('files')"></td>
836       </tr>
837      </property>
839 -----------------
841 Back to `Table of Contents`_
843 .. _`Table of Contents`: index.html