[Zope-PTK] Wizards

Andrew Wilcox circle@gwi.net
Sat, 25 Mar 2000 13:10:44 -0500


Excellent discussion!

> Back in February, Paul Everitt tried to raise a discussion about
> wizards but there was little interest.

Oh no, I have lots of interest, I've been mulling ever since!

Here are my thoughts on wizard requirements...


* Permit a wizard to be run more than once at the same time.

For example, if you store intermediate steps in a session, be sure to use a
unique key for each run of the wizard, so the user can run multiple
instances of the wizard in different browser windows at the same time.

In the past, I've made the mistake of storing such fields as a simple
"foo_title" and "foo_subject" in a session for a "foo" process, and then my
pesky users have had some reason for adding two foo's at the same time.


* Don't constrain wizards to be building only one object.

Maybe I'll have a fancy wizard that is building two or three things at
once.  If the multiple objects happen to have an "id" or "title" field, it
should be possible to keep the fields from clashing.


* Avoid having intermediate states published on the web.

This is echoing Jeffrey's comments on an "intellient" wizard being able to
cleanly cancel an add operation.

Build the object in a scratch area, and then have the wizard cut and paste
it to its final destination as the final step.  Or carry all the fields
along during the wizard process, and create the object at the end.


* Allow the object class (or a helper) to validate field values.

I see a lot of field validation happening in form processing code.  Then at
the end, the object gets created with the field attributes... assuming the
creation will be successful.  But consider, who but the object is in the
best position to know whether field values are valid?

And come to think of it, if the object could be carrying storing the
attributes during the build process, rather than having to make the wizard
manage the properties, that would pull a lot of responsibility out of the
wizard code and make it easier to change an object's interface.


* Permit the build state to be stored in the ZODB, if appropriate for the
portal.

Consider... I'm at work, I'm on a creative brainstorm, I've got eight
browser windows open, I'm creating news items, events, I'm in the middle of
a bunch of multi-page wizards, suddenly, I notice the time, I have to rush
home!  Feed the cat.  Whew.  Wander over to my home computer, log into the
portal, and... continue where I left off?

Yes, if the wizard states were in a build area in my personal user folder
in the portal.  Login to the same portal account, and open 'em up.

Many portals will want to keep wizard state in the session, which is fine.
We should have the flexibility to keep wizard state either in the session
or in the ZODB.  Ideally transparent to wizard authors.


* Permit navigation within the wizard pages

Building upon Andrew M. Kuchling's requirement:

>      (1)* You want to be able to sanity-check the fields after each step,
> staying at the same step until the fields have reasonable values.

And in some cases you may not be able to completely validate values
individually.  A good example is not coming to mind, but suppose I enter a
valid id at the beginning, but by the time I reach the last page someone
has created some other object with the same id.  Now what do I, the hapless
user, do?  I click on "Back" a few times, enter a good id, but now I've
lost all the other information I had entered on later pages.


* A wizard should be usable for both adding and editing an object.

I'm greatly frustrated by the typical Microsoft "wizard", because you can't
run them again without losing everything.  An example is the wizard which
creates a form from a table in Access.  The wizard asks questions about the
kind of form you want to create and what style it should have, looks up
what fields are in the table, and then creates a form that displays those
fields.  But when you change the fields in table, the form is broken, and
there's no way to re-run the wizard without starting over from scratch.
Makes for fragile applications!

This one is going to take some thought... not easy, perhaps, but a killer
if we pull it off.  When creating an object, sources of information is what
the user is entering, and information from the environment (i.e. other
objects in the ZODB).  When editing an object, there's also the object's
state, which may have been modified outside of the wizard.

One thing that would be needed here is a way of either filling in the
wizard page fields from the state of the object, or if that was not a
one-to-one operation, storing the wizard state so it could be retrieved
later.  


Now, this is only one piece of the puzzle, but let me take a look at the
backend of storing object state during the wizard process.

Consider a "Buildable" interface.  A Buildable would be a portal object
(such as a news item, image, document, etc.) that participates in being
built and stores the object state while it is being built.  It would be
responsible for validation of its own property values.  It would not do the
user interface, that's up to the wizard.

Portal objects could implement Buildable themselves, or if they didn't want
to deal with issues of being in an incomplete state, a helper class could
implement Buildable on behalf of a portal object.

A Buildable object would be stored either in the session, or in a private
member's area of the ZODB.

A Buildable would accept a REQUEST form and populate properties, like
ZClass's do.  And in fact in the simple case, when the portal object was
Buildable itself, it would be its own property sheets that got updated.

A Buildable would accept properties in any combination, so it could be used
by a multi-page wizard that fed it properties a few at a time, or by an
expert one-page wizard that stored all the properties at once.

Buildable would have an isValid() method.  An object that reported
isValid() true would have all its data (have its image if it were an image
or have its subject and title if it were a message), knows its id, all the
property values would be consistent, the object is ready to go and be
published on the web.

A clean interface for checking property values would be very useful.  Right
now various errors get returned for invalid properties:
ZPublisher/Converters.py will raise a ValueError exception class object
i.e. if you try to store a non-number in a numeric property,
OFS/ObjectManager.py will raise "Bad Request" (old style string exception
style) if you don't specify the id for an object that you're trying to create.

Many times a property value will be invalid by itself: non-numeric value
for a number, an id that begins with an underscore.  Some properties are
only invalid in combination: the Image that will get its id either from the
user typing in an id or from the image filename.  When it is a particular
value which is in error, it would be really neat to return the particular
property that is in error.  That way the wizard UI can put the error
message ("title must be specified") next to the input box.

An approach I'm thinking about is the Buildable would raise a standard
error, "PropertyError" perhaps, if one or more properties were invalid.
The error value would be *standardized* to contain information about the
list of invalid properties.  The wizard would grab that with <dtml-try>,
and easily pull the error description out to display in the UI.

So, let's see, the Buildable interface would need to provide for:

 * Storing one or more properties at a time
 * Reporting on invalid property values in a *standard* way
 * Once all the properties had been entered, reporting on
     whether the object as a whole is valid
 * Instantiating the object in the ZODB
 * For when you want to edit an existing object, making a
     working copy of the object in either the session
     or a user's private "construction yard" area of the ZODB.

...hmm, anything else?


Is Buildable doing a good job fitting into a
model/view/controller(presenter) architecture Jeffrey?