Scenario
I have a use case that asks for something like a tree view with checkboxes, but somehow it is one step more complex.
I have a tree structure where for each node, the user can chose one of three states:
- Enabled (*)
- Disabled
- Inherit state from parent (this state is not available for the root item)
(*) As if this were not enough, every explicitly enabled node has a user-configurable weight, that defines the priority compared to other enabled nodes. Nodes which inherit the "enabled" state from the parent, also inherit the weight, so they don't have this extra setting.
The weight is configured in a separate form with drag/drop sorting. I only mention it here because this means that we really need to distinguish between explicitly enabled and implicitly enabled. It is generally desirable to keep most nodes on "inherit", so the drag/drop sorting form gets more manageable.
The inheritance is also important when new nodes appear, about which the user has not made any explicit choice yet. In general these new nodes start as "inherit". Therefore, any enable/disable choice you make on an existing node may have consequences for new nodes that will be available in the future, and that you don't know about yet. This is absolutely intended.
Audience
The UI is meant for Drupal site administrators. This task often involves some learning. But too much wtf could lead to the user giving up and using something else (that is more work and not as powerful)
UI Challenges
The UI should accomplish the following things:
- For nodes that are set to "inherit", it should be (immediately) obvious which is the source/parent node it inherits from, and which other nodes inherit from the same parent.
- For any node, inherit or not, it should be (immediately) obvious whether the derived/implicit value for this node is "enabled" or "disabled".
- It should be sufficiently obvious which operations the user has available, and what the effect will be.
Possible UI solutions
Old solution: tabledrag sort with sections.
In the past, this all used to be a huge table drag sort interface with separate sections for enabled / disabled / inherit. In the "Enabled" section, the order of the rows would define the weights/priorities. In the other sections, the order would have no meaning. https://drupal.org/files/crumbs_ui.png
This is kinda ok, but I'm afraid it does not really visualize the inheritance concept.
New plan: Tree table + table drag
The new plan looks like this:
- display the nodes in a tree table.
- have the tree table be expansible/collapsible, and only expand the top level by default.
- have controls in each row to choose between enabled/disabled/inherit. This could be dropdowns, radios, a combination of checkboxes, buttons that "touch butt", a tri-state checkbox (which is probably a bad idea), etc.
- the controls could be either on the left of each row (like a typical tree table with checkboxes), or in a dedicated column in the middle.
- The controls in the tree table will be synced with a drag/drop sort interface to control the weights. This is going to be step two of the entire endeavor, so let's not worry about it here.
- Ideally, the rows should also display the weight (as a number or sth else), but
One snapshot: https://drupal.org/files/issues/crumbs-ui.png The version you see there has a "focus group" mechanic, where you can focus a group of rows that inherits from the same parent.
I think this has some potential in visualizing the hierarchical nature of the system, but the understandability is borderline. It feels logical in one moment, and insane in the next moment.
Background (you may skip this)
(don't lose your head over this, it is only if you are really curious)
I maintain a Drupal module where every page in your website is given a parent path. https://drupal.org/node/1404018 Given the path of a page, the module will query a number of plugins, until one of them finds a parent path. (that's a "chain of responsibility" pattern, I think) (The implementation is one level more complicated, but you don't need to know..)
The available plugins are quite fine-grained, and they follow a hierarchical naming scheme. E.g.
taxonomy.termReference.field_categories.node.article
taxonomy.termReference.field_categories.node.event
taxonomy.termReference.field_categories.product.product
The user (site admin) can decide which plugins should be active, and define the order of enabled plugins. Since there can be quite a lot of plugins, the module has a wildcard system, so you have wildcards like this:
*
taxonomy.*
taxonomy.termReference.*
taxonomy.termReference.field_categories.*
taxonomy.termReference.field_categories.node.*
taxonomy.termReference.field_categories.node.article
Instead of enabling every plugin individually, you can enable a wildcard, and let all plugins underneath inherit the status of its parent.
This is also useful for new plugins that enter the game, e.g. when a new module is enabled, a new menu created, etc: These new plugins will simply inherit from the parent (if nothing else then from the root wildcard '*'), without the user having to do anything. Only some plugins start as disabled, to avoid unexpected behavior.
So, you get a huge tree table form, where each row is either a wildcard (ending with .*) or a plugin (the "leafs"). For each row, the user can choose one of 3 states: Enabled, Disabled, Inherit. Or, if it is enabled, the user can also set a weight - but I delegated this to a separate widget with drag/drop ordering.
Typically you will have like 50 plugins and wildcards, with the majority of them being set to "Inherit".