diff --git a/include/ajax.search.php b/include/ajax.search.php
index 4edad32cac5b6c6acea5666cf5fc1426838940c9..d433963a362df731084c631fa4d66251e0b1e889 100644
--- a/include/ajax.search.php
+++ b/include/ajax.search.php
@@ -132,7 +132,7 @@ class SearchAjaxAPI extends AjaxController {
         $form = $search->getForm($data);
         $form->setSource($data);
         if (!$data || !$form->isValid()) {
-            Http::response(422, 'Validation errors exist on form');
+            Http::response(422, 'Validation errors exist on criteria');
         }
 
         $search->config = JsonDataEncoder::encode($form->getState());
@@ -227,15 +227,14 @@ class SearchAjaxAPI extends AjaxController {
             $queue = CustomQueue::create();
         }
 
-        $form = $queue->getForm($_POST);
-
-        // TODO: Update queue columns (but without save)
+        // Update queue columns (but without save)
         foreach ($_POST['columns'] as $colid) {
             $col = QueueColumn::create(array("id" => $colid, "queue" => $queue));
             $col->update($_POST);
             $queue->addColumn($col);
         }
 
+        $form = $queue->getForm($_POST);
         $tickets = $queue->getQuery($form);
         $count = 10; // count($queue->getBasicQuery($form));
 
diff --git a/include/class.queue.php b/include/class.queue.php
index d0aa1c64563d3c4ba32507bd385d843a8c055c94..c3a4d202ae3e884c2cd133c75d9f2ca656ffebb7 100644
--- a/include/class.queue.php
+++ b/include/class.queue.php
@@ -22,6 +22,11 @@ class CustomQueue extends SavedSearch {
             'columns' => array(
                 'reverse' => 'QueueColumn.queue',
             ),
+            'staff' => array(
+                'constraint' => array(
+                    'staff_id' => 'Staff.staff_id',
+                )
+            )
         ),
     );
 
@@ -31,8 +36,8 @@ class CustomQueue extends SavedSearch {
         ));
     }
 
-    static function getDecorations($root) {
-        // Ticket decorations
+    static function getAnnotations($root) {
+        // Ticket annotations
         return array(
             'TicketThreadCount',
             'ThreadAttachmentCount',
@@ -93,10 +98,18 @@ class CustomQueue extends SavedSearch {
         $col->queue = $this;
     }
 
+    function getId() {
+        return $this->id;
+    }
+
     function getRoot() {
         return 'Ticket';
     }
 
+    function getStatus() {
+        return 'bogus';
+    }
+
     function getBasicQuery($form=false) {
         $root = $this->getRoot();
         $query = $root::objects();
@@ -118,9 +131,60 @@ class CustomQueue extends SavedSearch {
         }
         return $query;
     }
+
+    function update($vars, &$errors) {
+        // TODO: Move this to SavedSearch::update() and adjust
+        //       AjaxSearch::_saveSearch()
+        $form = $this->getForm($vars);
+        $form->setSource($vars);
+        if (!$vars || !$form->isValid()) {
+            $errors['criteria'] = __('Validation errors exist on criteria');
+        }
+        else {
+            $this->config = JsonDataEncoder::encode($form->getState());
+        }
+
+        // Set basic queue information
+        $this->title = $vars['name'];
+
+        // Update queue columns (but without save)
+        if (isset($vars['columns'])) {
+            foreach ($vars['columns'] as $sort=>$colid) {
+                // Try and find the column in this queue, if it's a new one,
+                // add it to the columns list
+                if (!($col = $this->columns->findFirst(array('id' => $colid)))) {
+                    $col = QueueColumn::create(array("id" => $colid, "queue" => $this));
+                    $this->addColumn($col);
+                }
+                $col->set('sort', $sort+1);
+                $col->update($vars, $errors);
+            }
+            // Re-sort the in-memory columns array
+            $this->columns->sort(function($c) { return $c->sort; });
+        }
+        return 0 === count($errors);
+    }
+
+    function save($refetch=false) {
+        if (!($rv = parent::save($refetch)))
+            return $rv;
+
+        return $this->columns->saveAll();
+    }
+
+    static function create($vars=false) {
+        global $thisstaff;
+
+        $queue = parent::create($vars);
+        $queue->setFlag(SavedSearch::FLAG_QUEUE);
+        if ($thisstaff)
+            $queue->staff_id = $thisstaff->getId();
+
+        return $queue;
+    }
 }
 
-abstract class QueueDecoration {
+abstract class QueueColumnAnnotation {
     static $icon = false;
     static $desc = '';
 
@@ -167,7 +231,7 @@ abstract class QueueDecoration {
     }
 
     // Render the annotation with the database record $row. $text is the
-    // text of the cell before decorations were applied.
+    // text of the cell before annotations were applied.
     function render($row, $cell) {
         if ($decoration = $this->getDecoration($row, $cell))
             return $this->decorate($cell, $decoration);
@@ -185,10 +249,14 @@ abstract class QueueDecoration {
     function getPosition() {
         return strtolower($this->config['p']) ?: 'a';
     }
+
+    function getClassName() {
+        return @$this->config['c'] ?: get_class();
+    }
 }
 
 class TicketThreadCount
-extends QueueDecoration {
+extends QueueColumnAnnotation {
     static $icon = 'comments-alt';
     static $qname = '_thread_count';
     static $desc = /* @trans */ 'Thread Count';
@@ -214,7 +282,7 @@ extends QueueDecoration {
 }
 
 class ThreadAttachmentCount
-extends QueueDecoration {
+extends QueueColumnAnnotation {
     static $icon = 'paperclip';
     static $qname = '_att_count';
     static $desc = /* @trans */ 'Attachment Count';
@@ -240,7 +308,7 @@ extends QueueDecoration {
 }
 
 class OverdueFlagDecoration
-extends QueueDecoration {
+extends QueueColumnAnnotation {
     static $icon = 'exclamation';
     static $desc = /* @trans */ 'Overdue Icon';
 
@@ -255,7 +323,7 @@ extends QueueDecoration {
 }
 
 class TicketSourceDecoration
-extends QueueDecoration {
+extends QueueColumnAnnotation {
     static $icon = 'phone';
     static $desc = /* @trans */ 'Ticket Source';
 
@@ -308,22 +376,36 @@ class QueueColumnCondition {
         ));
     }
 
+    function getField() {
+      // FIXME
+      #$root = $this->getColumn()->getQueue()->getRoot();
+      $root = 'Ticket';
+      $searchable = SavedSearch::getSearchableFields($root);
+      list($name, $method, $value) = $this->config['crit'];
+
+      // Lookup the field to search this condition
+      if (isset($searchable[$name]))
+          return $searchable[$name];
+    }
+
+    function getFieldName() {
+        list($name) = $this->config['crit'];
+        return $name;
+    }
+
     function getSearchQ() {
-        // FIXME
-        #$root = $this->getColumn()->getQueue()->getRoot();
-        $root = 'Ticket';
-        $searchable = SavedSearch::getSearchableFields($root);
         list($name, $method, $value) = $this->config['crit'];
 
-        // Lookup the field to search this condition
-        if (!isset($searchable[$name]))
-            return null;
-        $field = $searchable[$name];
-
         // Fetch a criteria Q for the query
-        return $field->getSearchQ($method, $value, $name);
+        if ($field = $this->getField())
+            return $field->getSearchQ($method, $value, $name);
     }
 
+    /**
+     * Take the criteria from the SavedSearch fields setup and isolate the
+     * field name being search, the method used for searhing, and the method-
+     * specific data entered in the UI.
+     */
     static function isolateCriteria($criteria, $root='Ticket') {
         $searchable = SavedSearch::getSearchableFields($root);
         foreach ($criteria as $k=>$v) {
@@ -456,40 +538,26 @@ extends ChoiceField {
 
 
 /**
- * Object version of JSON-serialized column array which has several
- * properties:
+ * A column of a custom queue. Columns have many customizable features
+ * including:
  *
- * {
- *   "heading": "Header Text",
- *   "primary": "user__name",
- *   "secondary": null,
- *   "width": 100,
- *   "link": 'ticket',
- *   "truncate": "wrap",
- *   "filter": "UsersName"
- *   "annotations": [
- *     {
- *       "c": "ThreadCollabCount",
- *       "p": ">"
- *     }
- *   ],
- *   "conditions": [
- *     {
- *       "crit": {
- *         "created+method": {"ndaysago": "in the last n days"}, "created+ndaysago": {"until":"7"}
- *       },
- *       "prop": {
- *         "font-weight": "bold"
- *       }
- *     }
- *   ]
- * }
+ *   * Data Source (primary and secondary)
+ *   * Heading
+ *   * Link (to an object like the ticket)
+ *   * Size and truncate settings
+ *   * annotations (like counts and flags)
+ *   * Conditions (which change the formatting like bold text)
+ *
+ * Columns are stored in a separate table from the queue itself, but other
+ * breakout items for the annotations and conditions, for instance, are stored
+ * as JSON text in the QueueColumn model.
  */
 class QueueColumn
 extends VerySimpleModel {
     static $meta = array(
         'table' => QUEUE_COLUMN_TABLE,
         'pk' => array('id'),
+        'ordering' => array('sort'),
         'joins' => array(
             'queue' => array(
                 'constraint' => array('queue_id' => 'CustomQueue.id'),
@@ -497,17 +565,23 @@ extends VerySimpleModel {
         ),
     );
 
-    var $_decorations = array();
+    var $_annotations = array();
     var $_conditions = array();
 
     function __onload() {
-        if ($this->annotations) {
-            foreach ($this->annotations as $D)
-                $this->_decorations[] = QueueDecoration::fromJson($D) ?: array();
+        if ($this->annotations
+            && ($anns = JsonDataParser::decode($this->annotations))
+        ) {
+            foreach ($anns as $D)
+                if ($T = QueueColumnAnnotation::fromJson($D))
+                    $this->_annotations[] = $T;
         }
-        if ($this->conditions) {
-            foreach ($this->conditions as $C)
-                $this->_conditions[] = QueueColumnCondition::fromJson($C) ?: array();
+        if ($this->conditions
+            && ($conds = JsonDataParser::decode($this->conditions))
+        ) {
+            foreach ($conds as $C)
+                if ($T = QueueColumnCondition::fromJson($C))
+                    $this->_conditions[] = $T;
         }
     }
 
@@ -554,8 +628,8 @@ extends VerySimpleModel {
             $text = sprintf('<a href="%s">%s</a>', $link, $text);
         }
 
-        // Decorations and conditions
-        foreach ($this->_decorations as $D) {
+        // annotations and conditions
+        foreach ($this->_annotations as $D) {
             $text = $D->render($row, $text);
         }
         foreach ($this->_conditions as $C) {
@@ -615,8 +689,8 @@ extends VerySimpleModel {
             break;
         }
 
-        // Decorations
-        foreach ($this->_decorations as $D) {
+        // annotations
+        foreach ($this->_annotations as $D) {
             $query = $D->annotate($query);
         }
 
@@ -637,8 +711,8 @@ extends VerySimpleModel {
         return $name;
     }
 
-    function getDecorations() {
-        return $this->_decorations;
+    function getAnnotations() {
+        return $this->_annotations;
     }
 
     function getConditions() {
@@ -651,7 +725,7 @@ extends VerySimpleModel {
      */
     static function create($vars=array()) {
         $inst = parent::create($vars);
-        // TODO: Convert decorations and conditions
+        // TODO: Convert annotations and conditions
         return $inst;
     }
 
@@ -660,65 +734,78 @@ extends VerySimpleModel {
         foreach ($form->getClean() as $k=>$v)
             $this->set($k, $v);
 
-        // Do the decorations
-        $this->_decorations = $this->decorations = array();
-        foreach (@$vars['decorations'] as $i=>$class) {
-            if (!class_exists($class) || !is_subclass_of($class, 'QueueDecoration'))
-                continue;
-            if ($vars['deco_column'][$i] != $this->id)
-                continue;
-            $json = array('c' => $class, 'p' => $vars['deco_pos'][$i]);
-            $this->_decorations[] = QueueDecoration::fromJson($json);
-            $this->decorations[] = $json;
+        // Do the annotations
+        $this->_annotations = $annotations = array();
+        if (isset($vars['annotations'])) {
+            foreach (@$vars['annotations'] as $i=>$class) {
+                if ($vars['deco_column'][$i] != $this->id)
+                    continue;
+                if (!class_exists($class) || !is_subclass_of($class, 'QueueColumnAnnotation'))
+                    continue;
+                $json = array('c' => $class, 'p' => $vars['deco_pos'][$i]);
+                $annotations[] = $json;
+                $this->_annotations[] = QueueColumnAnnotation::fromJson($json);
+            }
         }
 
         // Do the conditions
-        $this->_conditions = $this->conditions = array();
-        foreach (@$vars['conditions'] as $i=>$id) {
-            if ($vars['condition_column'][$i] != $this->id)
-                // Not a condition for this column
-                continue;
-            // Determine the criteria
-            $name = $vars['condition_field'][$i];
-            $fields = SavedSearch::getSearchableFields($this->getQueue()->getRoot());
-            if (!isset($fields[$name]))
-                // No such field exists for this queue root type
-                continue;
-            $field = $fields[$name];
-            $parts = SavedSearch::getSearchField($field, $name);
-            $search_form = new SimpleForm($parts, $vars, array('id' => $id));
-            $search_form->getField("{$name}+search")->value = true;
-            $crit = $search_form->getClean();
-            // Check the box to enable searching on the field
-            $crit["{$name}+search"] = true;
-
-            // Convert search criteria to a Q instance
-            $crit = QueueColumnCondition::isolateCriteria($crit);
-
-            // Determine the properties
-            $props = array();
-            foreach ($vars['properties'] as $i=>$cid) {
-                if ($cid != $id)
-                    // Not a property for this condition
+        $this->_conditions = $conditions = array();
+        if (isset($vars['conditions'])) {
+            foreach (@$vars['conditions'] as $i=>$id) {
+                if ($vars['condition_column'][$i] != $this->id)
+                    // Not a condition for this column
                     continue;
-
-                // Determine the property configuration
-                $prop = $vars['property_name'][$i];
-                if (!($F = QueueColumnConditionProperty::getField($prop))) {
-                    // Not a valid property
+                // Determine the criteria
+                $name = $vars['condition_field'][$i];
+                $fields = SavedSearch::getSearchableFields($this->getQueue()->getRoot());
+                if (!isset($fields[$name]))
+                    // No such field exists for this queue root type
                     continue;
+                $field = $fields[$name];
+                $parts = SavedSearch::getSearchField($field, $name);
+                $search_form = new SimpleForm($parts, $vars, array('id' => $id));
+                $search_form->getField("{$name}+search")->value = true;
+                $crit = $search_form->getClean();
+                // Check the box to enable searching on the field
+                $crit["{$name}+search"] = true;
+
+                // Isolate only the critical parts of the criteria
+                $crit = QueueColumnCondition::isolateCriteria($crit);
+
+                // Determine the properties
+                $props = array();
+                foreach ($vars['properties'] as $i=>$cid) {
+                    if ($cid != $id)
+                        // Not a property for this condition
+                        continue;
+
+                    // Determine the property configuration
+                    $prop = $vars['property_name'][$i];
+                    if (!($F = QueueColumnConditionProperty::getField($prop))) {
+                        // Not a valid property
+                        continue;
+                    }
+                    $prop_form = new SimpleForm(array($F), $vars, array('id' => $cid));
+                    $props[$prop] = $prop_form->getField($prop)->getClean();
                 }
-                $prop_form = new SimpleForm(array($F), $vars, array('id' => $cid));
-                $props[$prop] = $prop_form->getClean();
+                $json = array('crit' => $crit, 'prop' => $props);
+                $this->_conditions[] = QueueColumnCondition::fromJson($json);
+                $conditions[] = $json;
             }
-            $json = array('crit' => $crit, 'prop' => $props);
-            $this->_conditions[] = QueueColumnCondition::fromJson($json);
-            $this->conditions[] = $json;
         }
 
         // Store as JSON array
-        $this->decorations = JsonDataEncoder::encode($this->decorations);
-        $this->conditions = JsonDataEncoder::encode($this->conditions);
+        $this->annotations = JsonDataEncoder::encode($annotations);
+        $this->conditions = JsonDataEncoder::encode($conditions);
+    }
+
+    function save($refetch=false) {
+        if ($this->__new__ && isset($this->id))
+            // The ID is used to synchrize the POST data with the forms API.
+            // It should not be assumed to be a valid or unique database ID
+            // number
+            unset($this->id);
+        return parent::save($refetch);
     }
 }
 
diff --git a/include/class.search.php b/include/class.search.php
index 674533e2a531748f9bfb8a562d34777ed45b4bee..91c19f3c38886df2dd8384de29be7354be355445 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -675,12 +675,12 @@ class SavedSearch extends VerySimpleModel {
     }
 
     function getName() {
-        return $this->name;
+        return $this->title;
     }
 
     function getSearchForm() {
-        if ($state = JsonDataParser::parse($search->config)) {
-            $form = $search->loadFromState($state);
+        if ($state = JsonDataParser::parse($this->config)) {
+            $form = $this->loadFromState($state);
             $form->loadState($state);
             return $form;
         }
diff --git a/include/staff/queue.inc.php b/include/staff/queue.inc.php
index d322a912554b6bc65e91462834a1609e9f3abd27..0c5b36a0a6ba82220eefac1410d04055110ca0d9 100644
--- a/include/staff/queue.inc.php
+++ b/include/staff/queue.inc.php
@@ -5,18 +5,15 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access
 
 $info = $qs = array();
 
-if ($_REQUEST['a']=='add'){
-    if (!$queue) {
-        $queue = CustomQueue::create(array(
-            'flags' => CustomQueue::FLAG_QUEUE,
-        ));
-    }
+if (!$queue) {
+    $queue = CustomQueue::create(array(
+        'flags' => CustomQueue::FLAG_QUEUE,
+    ));
     $title=__('Add New Queue');
     $action='create';
     $submit_text=__('Create');
 }
 else {
-    //Editing Department.
     $title=__('Manage Custom Queue');
     $action='update';
     $submit_text=__('Save Changes');
@@ -30,6 +27,7 @@ else {
   <input type="hidden" name="do" value="<?php echo $action; ?>">
   <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
   <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
+  <input type="hidden" name="root" value="<?php echo Format::htmlchars($_REQUEST['t']); ?>">
 
   <h2><?php echo __('Ticket Queues'); ?> // <?php echo $title; ?>
       <?php if (isset($queue->id)) { ?><small>
@@ -59,6 +57,7 @@ else {
         <br/>
         <div><strong><?php echo __("Queue Search Criteria"); ?></strong></div>
         <hr/>
+        <div class="error"><?php echo $errors['criteria']; ?></div>
         <div class="advanced-search">
 <?php
             $form = $queue->getSearchForm();
@@ -128,7 +127,7 @@ else {
             config.append($(json.config)).insertAfter(columns.append(div));
             $this.data('nextId', nextId+1);
           }
-        }); 
+        });
       ">
         <option value="">— <?php echo __('Add a column'); ?> —</option>
 <?php foreach (SavedSearch::getSearchableFields('Ticket') as $path=>$f) { ?>
@@ -140,12 +139,13 @@ else {
 <?php foreach ($queue->getColumns() as $column) {
         $colid = $column->getId();
         $maxcolid = max(@$maxcolid ?: 0, $colid);
-        echo sprintf('<div data-id="%s" data-col-id="colconfig-%s" class="column-header" '
-          .'data-width="%s">%s'
+        echo sprintf('<div data-id="%1$s" data-col-id="colconfig-%1$s" class="column-header" '
+          .'data-width="%2$s">%3$s'
           .'<i class="icon-ellipsis-vertical ui-resizable-handle ui-resizable-handle-e"></i>'
-          .'<input type="hidden" name="columns[]" value="%s"/>'
+          .'<input type="hidden" name="columns[]" value="%1$s"/>'
           .'</div>',
-          $colid, $colid, $column->getWidth(), $column->getHeading(), $colid);
+          $colid, $column->getWidth(), $column->getHeading(),
+          $column->sort ?: 1);
 } ?>
       </div>
       <script>
diff --git a/include/staff/queues-ticket.inc.php b/include/staff/queues-ticket.inc.php
index 170edafed6e22445c3a6b2ce74edea5103468272..620ae915897a20a35f690179942bbbb06ee283c2 100644
--- a/include/staff/queues-ticket.inc.php
+++ b/include/staff/queues-ticket.inc.php
@@ -1,38 +1,38 @@
-
+<?php
+require_once INCLUDE_DIR . 'class.queue.php';
+?>
 <form action="queues.php?t=tickets" method="POST" name="keys">
-    <div class="sticky bar opaque">
-        <div class="content">
-            <div class="pull-right">
-                <a href="queues.php?t=tickets&amp;a=add" class="green button action-button"><i class="icon-plus-sign"></i> <?php echo __('Add New Queue');?></a>
-                <span class="action-button" data-dropdown="#action-dropdown-more">
-                            <i class="icon-caret-down pull-right"></i>
-                            <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
-                </span>
-                <div id="action-dropdown-more" class="action-dropdown anchor-right">
-                    <ul id="actions">
-                        <li>
-                            <a class="confirm" data-name="enable" href="queues.php?t=tickets&amp;a=enable">
-                                <i class="icon-ok-sign icon-fixed-width"></i>
-                                <?php echo __( 'Enable'); ?>
-                            </a>
-                        </li>
-                        <li>
-                            <a class="confirm" data-name="disable" href="queues.php?t=tickets&amp;a=disable">
-                                <i class="icon-ban-circle icon-fixed-width"></i>
-                                <?php echo __( 'Disable'); ?>
-                            </a>
-                        </li>
-                        <li class="danger">
-                            <a class="confirm" data-name="delete" href="queues.php?t=tickets&amp;a=delete#queues">
-                                <i class="icon-trash icon-fixed-width"></i>
-                                <?php echo __( 'Delete'); ?>
-                            </a>
-                        </li>
-                    </ul>
-                </div>
+    <div>
+        <div class="pull-right">
+            <a href="queues.php?t=tickets&amp;a=add" class="green button action-button"><i class="icon-plus-sign"></i> <?php echo __('Add New Queue');?></a>
+            <span class="action-button" data-dropdown="#action-dropdown-more">
+                        <i class="icon-caret-down pull-right"></i>
+                        <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
+            </span>
+            <div id="action-dropdown-more" class="action-dropdown anchor-right">
+                <ul id="actions">
+                    <li>
+                        <a class="confirm" data-name="enable" href="queues.php?t=tickets&amp;a=enable">
+                            <i class="icon-ok-sign icon-fixed-width"></i>
+                            <?php echo __( 'Enable'); ?>
+                        </a>
+                    </li>
+                    <li>
+                        <a class="confirm" data-name="disable" href="queues.php?t=tickets&amp;a=disable">
+                            <i class="icon-ban-circle icon-fixed-width"></i>
+                            <?php echo __( 'Disable'); ?>
+                        </a>
+                    </li>
+                    <li class="danger">
+                        <a class="confirm" data-name="delete" href="queues.php?t=tickets&amp;a=delete#queues">
+                            <i class="icon-trash icon-fixed-width"></i>
+                            <?php echo __( 'Delete'); ?>
+                        </a>
+                    </li>
+                </ul>
             </div>
-            <h3><?php echo __('Ticket Queues');?></h3>
         </div>
+        <h3><?php echo __('Ticket Queues');?></h3>
     </div>
     <div class="clear"></div>
  <?php csrf_token(); ?>
@@ -49,6 +49,16 @@
         </tr>
     </thead>
     <tbody>
+<?php foreach (CustomQueue::objects() as $q) { ?>
+    <tr>
+      <td><input type="checkbox" class="checkbox" name="ckb[]"></td>
+      <td><a href="queues.php?id=<?php echo $q->getId(); ?>"><?php
+        echo Format::htmlchars($q->getName()); ?></a></td>
+      <td><?php echo Format::htmlchars($q->staff->getName()); ?></td>
+      <td><?php echo Format::htmlchars($q->getStatus()); ?></td>
+      <td><?php echo Format::date($q->created); ?></td>
+    </tr>
+<?php } ?>
     </tbody>
 </table>
 </form>
diff --git a/include/staff/templates/queue-column-condition.tmpl.php b/include/staff/templates/queue-column-condition.tmpl.php
index 1c1684b43b62491d2e7e92b5e813d45f2d808d97..659158d06fb547c46146eb5441cd9eaf57c99d0c 100644
--- a/include/staff/templates/queue-column-condition.tmpl.php
+++ b/include/staff/templates/queue-column-condition.tmpl.php
@@ -2,7 +2,6 @@
 // Calling convention:
 //
 // $field - field for the condition (Ticket / Last Update)
-// $properties - currently-configured properties for the condition
 // $condition - <QueueColumnCondition> instance for this condition
 // $column - <QueueColumn> to which the condition belongs
 // $id - temporary ID number for the condition
@@ -25,7 +24,8 @@ $parts = SavedSearch::getSearchField($field, $field_name);
 unset($parts["{$field_name}+search"]);
 foreach ($parts as $name=>$F) {
     if (substr($name, -7) == '+method')
-        // XXX: Hack
+        // XXX: Hack — drop visibility connection between the method drop-down
+        //      and the enabled checkbox
         unset($F->ht['visibility']);
 }
 $form = new SimpleForm($parts, false, array('id' => $id));
diff --git a/include/staff/templates/queue-column.tmpl.php b/include/staff/templates/queue-column.tmpl.php
index 5d2f23e6f57c6ef5c5ecfbe39c8230049f7e6400..d8d9f6de7b3b5284a73ab48ffeb6efc7928c135b 100644
--- a/include/staff/templates/queue-column.tmpl.php
+++ b/include/staff/templates/queue-column.tmpl.php
@@ -9,7 +9,7 @@ $data_form = $column->getDataConfigForm($_POST);
 ?>
 <ul class="alt tabs">
   <li class="active"><a href="#<?php echo $colid; ?>-data"><?php echo __('Data'); ?></a></li>
-  <li><a href="#<?php echo $colid; ?>-decorations"><?php echo __('Decorations'); ?></a></li>
+  <li><a href="#<?php echo $colid; ?>-annotations"><?php echo __('Annotations'); ?></a></li>
   <li><a href="#<?php echo $colid; ?>-conditions"><?php echo __('Conditions'); ?></a></li>
 </ul>
 
@@ -20,31 +20,31 @@ $data_form = $column->getDataConfigForm($_POST);
 </div>
 
 <div class="hidden tab_content" data-col-id="<?php echo $colid; ?>"
-  id="<?php echo $colid; ?>-decorations" style="max-width: 400px">
+  id="<?php echo $colid; ?>-annotations" style="max-width: 400px">
   <div class="empty placeholder" style="margin-left: 20px">
-    <em><?php echo __('No decorations for this field'); ?></em>
+    <em><?php echo __('No annotations for this field'); ?></em>
   </div>
   <div style="margin: 0 20px;">
-    <div class="decoration clear template hidden">
-      <input data-field="input" data-name="decorations[]" value="" type="hidden" />
+    <div class="annotation clear template hidden">
+      <input data-field="input" data-name="annotations[]" value="" type="hidden" />
       <input data-field="column" data-name="deco_column[]" value="" type="hidden" />
       <i data-field="icon"></i>
       <span data-field="name"></span>
       <div class="pull-right">
         <select data-field="position" data-name="deco_pos[]">
-<?php foreach (QueueDecoration::getPositions() as $key=>$desc) {
+<?php foreach (QueueColumnAnnotation::getPositions() as $key=>$desc) {
           echo sprintf('<option value="%s">%s</option>', $key, Format::htmlchars($desc));
 } ?>
         </select>
         <a href="#" data-field="delete" title="<?php echo __('Delete'); ?>"
-            onclick="javascript: 
+            onclick="javascript:
             var tab = $(this).closest('.tab_content'),
-                decoration = $(this).closest('.decoration'),
-                klass = decoration.find('input[data-field=input]').val(),
-                select = $('select.add-decoration', tab);
+                annotation = $(this).closest('.annotation'),
+                klass = annotation.find('input[data-field=input]').val(),
+                select = $('select.add-annotation', tab);
             select.find('option[value=' + klass + ']').prop('disabled', false);
-            decoration.remove();
-            if (tab.find('.decoration:not(.template)').length === 0)
+            annotation.remove();
+            if (tab.find('.annotation:not(.template)').length === 0)
                 tab.find('.empty.placeholder').show()
             return false;"><i class="icon-trash"></i></a>
       </div>
@@ -52,9 +52,9 @@ $data_form = $column->getDataConfigForm($_POST);
 
     <div style="margin-top: 20px">
       <i class="icon-plus-sign"></i>
-      <select class="add-decoration">
-        <option>— <?php echo __("Add a decoration"); ?> —</option>
-<?php foreach (CustomQueue::getDecorations('Ticket') as $class) {
+      <select class="add-annotation">
+        <option>— <?php echo __("Add a annotation"); ?> —</option>
+<?php foreach (CustomQueue::getAnnotations('Ticket') as $class) {
         echo sprintf('<option data-icon="%s" value="%s">%s</option>',
           $class::$icon, $class, $class::getDescription());
       } ?>
@@ -63,8 +63,8 @@ $data_form = $column->getDataConfigForm($_POST);
 
     <script>
       $(function() {
-        var addDecoration = function(type, desc, icon, pos) {
-          var template = $('.decoration.template', '#<?php echo $colid; ?>-decorations'),
+        var addAnnotation = function(type, desc, icon, pos) {
+          var template = $('.annotation.template', '#<?php echo $colid; ?>-annotations'),
               clone = template.clone().show().removeClass('template').insertBefore(template),
               input = clone.find('[data-field=input]'),
               colid = clone.closest('.tab_content').data('colId'),
@@ -81,19 +81,20 @@ $data_form = $column->getDataConfigForm($_POST);
             position.val(pos);
           template.closest('.tab_content').find('.empty').hide();
         };
-        $('select.add-decoration', '#<?php echo $colid; ?>-decorations').change(function() {
+        $('select.add-annotation', '#<?php echo $colid; ?>-annotations').change(function() {
           var selected = $(this).find(':selected');
-          addDecoration(selected.val(), selected.text(), selected.data('icon'));
+          addAnnotation(selected.val(), selected.text(), selected.data('icon'));
           selected.prop('disabled', true);
         });
-        $('#<?php echo $colid; ?>-decorations').click('a[data-field=delete]',
+        $('#<?php echo $colid; ?>-annotations').click('a[data-field=delete]',
         function() {
-          var tab = $('#<?php echo $colid; ?>-decorations');
-          if ($('.decoration', tab).length === 0)
+          var tab = $('#<?php echo $colid; ?>-annotations');
+          if ($('.annotation', tab).length === 0)
             tab.find('.empty').show();
         });
-        <?php foreach ($column->getDecorations() as $d) {
-            echo sprintf('addDecoration(%s, %s, %s);',
+        <?php foreach ($column->getAnnotations() as $d) {
+            echo sprintf('addAnnotation(%s, %s, %s, %s);',
+                JsonDataEncoder::encode($d->getClassName()),
                 JsonDataEncoder::encode($d::getDescription()),
                 JsonDataEncoder::encode($d::getIcon()),
                 JsonDataEncoder::encode($d->getPosition())
@@ -108,8 +109,15 @@ $data_form = $column->getDataConfigForm($_POST);
   <div style="margin: 0 20px"><?php echo __("Conditions are used to change the view of the data in a row based on some conditions of the data. For instance, a column might be shown bold if some condition is met.");
   ?></div>
   <div class="conditions" style="margin: 20px; max-width: 400px">
-<?php foreach ($column->getConditions() as $condition) {
+<?php
+if ($column->getConditions()) {
+  $fields = SavedSearch::getSearchableFields($column->getQueue()->getRoot());
+  foreach ($column->getConditions() as $i=>$condition) {
+     $id = $column->getId() * 40 + $i;
+     $field = $condition->getField();
+     $field_name = $condition->getFieldName();
      include STAFFINC_DIR . 'templates/queue-column-condition.tmpl.php';
+  }
 } ?>
     <div style="margin-top: 20px">
       <i class="icon-plus-sign"></i>
diff --git a/scp/queues.php b/scp/queues.php
index d348d570503e54c51dd17358dc0421645ceb7e5c..dc95a569764f0df20832efec6e5108a0fb23fea3 100644
--- a/scp/queues.php
+++ b/scp/queues.php
@@ -20,6 +20,43 @@ require('admin.inc.php');
 require_once INCLUDE_DIR . 'class.queue.php';
 
 $nav->setTabActive('settings', 'settings.php?t='.urlencode($_GET['t']));
+$errors = array();
+
+if ($_REQUEST['id']) {
+    $queue = CustomQueue::lookup($_REQUEST['id']);
+}
+
+if ($_POST) {
+    switch (strtolower($_POST['do'])) {
+    case 'update':
+        if (!$queue) {
+            $errors['err'] = '';
+            break;
+        }
+        if ($queue->update($_POST, $errors) && $queue->save()) {
+            $msg = sprintf(__('Successfully updated %s'), Format::htmlchars($_POST['name']));
+        }
+        elseif (!$errors['err']) {
+            $errors['err']=sprintf(__('Unable to udpate %s. Correct error(s) below and try again.'),
+                __('this queue'));
+        }
+        break;
+
+    case 'create':
+        $queue = CustomQueue::create(array(
+            'root' => $_POST['root'] ?: 'Ticket'
+        ));
+
+        if ($queue->update($_POST, $errors) && $queue->save(true)) {
+            $msg = sprintf(__('Successfully added %s'), Format::htmlchars($_POST['name']));
+        }
+        elseif (!$errors['err']) {
+            $errors['err']=sprintf(__('Unable to add %s. Correct error(s) below and try again.'),
+                __('this queue'));
+        }
+        break;
+    }
+}
 
 require_once(STAFFINC_DIR.'header.inc.php');
 include_once(STAFFINC_DIR."queue.inc.php");