diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index e0980efe06059584fe403b027cb490c98023d448..37f6399ff80943bfc8056855c61d797cf813fd7b 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -99,35 +99,18 @@ class DynamicFormsAjaxAPI extends AjaxController {
     }
 
 
-    function _getListItemEditForm($source=null, $item=false) {
-        return new SimpleForm(array(
-            'value' => new TextboxField(array(
-                'required' => true,
-                'label' => __('Value'),
-                'configuration' => array(
-                    'translatable' => $item ? $item->getTranslateTag('value') : false,
-                    'size' => 60,
-                    'length' => 0,
-                ),
-            )),
-            'extra' => new TextboxField(array(
-                'label' => __('Abbreviation'),
-                'configuration' => array(
-                    'size' => 60,
-                    'length' => 0,
-                ),
-            )),
-        ), $source);
-    }
-
     function getListItem($list_id, $item_id) {
 
         $list = DynamicList::lookup($list_id);
-        if (!$list || !($item = $list->getItem( (int) $item_id)))
+        if (!$list)
+            Http::response(404, 'No such list item');
+
+        $list = CustomListHandler::forList($list);
+        if (!($item = $list->getItem( (int) $item_id)))
             Http::response(404, 'No such list item');
 
         $action = "#list/{$list->getId()}/item/{$item->getId()}/update";
-        $item_form = $this->_getListItemEditForm($item->ht, $item);
+        $item_form = $list->getListItemBasicForm($item->ht, $item);
 
         include(STAFFINC_DIR . 'templates/list-item-properties.tmpl.php');
     }
@@ -155,7 +138,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
         if (!$list || !($item = $list->getItem( (int) $item_id)))
             Http::response(404, 'No such list item');
 
-        $item_form = $this->_getListItemEditForm($_POST, $item);
+        $item_form = $list->getListItemBasicForm($_POST, $item);
 
         if ($valid = $item_form->isValid()) {
             // Update basic information
@@ -191,20 +174,12 @@ class DynamicFormsAjaxAPI extends AjaxController {
     }
 
     function _renderListItem($item, $list=false) {
-        $list = $list ?: $item->list;
+        $list = $list ?: $item->getList();
 
         // Send the whole row back
-        $prop_fields = array();
-        foreach ($list->getConfigurationForm()->getFields() as $f) {
-            if (in_array($f->get('type'), array('text', 'datetime', 'phone')))
-                $prop_fields[] = $f;
-            if (strpos($f->get('type'), 'list-') === 0)
-                $prop_fields[] = $f;
-
-            // 4 property columns max
-            if (count($prop_fields) == 4)
-                break;
-        }
+        $prop_fields = $list->getSummaryFields();
+        $icon = ($list->get('sort_mode') == 'SortCol')
+            ? '<i class="icon-sort"></i>&nbsp;' : '';
         ob_start();
         $item->_config = null;
         include STAFFINC_DIR . 'templates/list-item-row.tmpl.php';
@@ -221,23 +196,19 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!($q = $_GET['q']))
             Http::response(400, '"q" query arg is required');
 
-        $items = clone $list->getAllItems();
-        $items->filter(Q::any(array(
-            'value__startswith' => $q,
-            'extra__contains' => $q,
-            'properties__contains' => '"'.$q,
-        )));
+        $list = CustomListHandler::forList($list);
+        $items = $list->search($q);
 
         $results = array();
         foreach ($items as $I) {
-            $display = $I->value;
-            if ($I->extra)
+            $display = $I->getValue();
+            if (isset($I->extra))
               $display .= " ({$I->extra})";
             $results[] = array(
-                'value' => $I->value,
+                'value' => $I->getValue(),
                 'display' => $display,
                 'id' => $I->id,
-                'list_id' => $I->list_id,
+                'list_id' => $I->getList()->getId(),
             );
         }
         return $this->encode($results);
@@ -251,23 +222,26 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!($list = DynamicList::lookup($list_id)))
             Http::response(404, 'No such list');
 
+        $list = CustomListHandler::forList($list);
         $action = "#list/{$list->getId()}/item/add";
-        $item_form = $this->_getListItemEditForm($_POST ?: null);
+        $item_form = $list->getListItemBasicForm($_POST ?: null);
+        $errors = array();
 
         if ($_POST && ($valid = $item_form->isValid())) {
             $data = $item_form->getClean();
-            if ($_item = DynamicListItem::lookup(array(
-                            'list_id' => $list->getId(), 'value'=>$data['value'])))
-                if ($_item && $_item->id)
-                    $item_form->getField('value')->addError(
-                        __('Value already in use'));
-            $data['list_id'] = $list->getId();
-            $item = DynamicListItem::create($data);
-            if ($item->save() && $item->setConfiguration())
-                Http::response(201, $this->encode(array(
-                    'success' => true,
-                    'row' => $this->_renderListItem($item, $list)
-                )));
+            if ($list->isItemUnique($data)) {
+                $item = $list->addItem($data, $errors);
+                if ($item->setConfiguration($_POST, $errors)) {
+                    Http::response(201, $this->encode(array(
+                        'success' => true,
+                        'row' => $this->_renderListItem($item, $list)
+                    )));
+                }
+            }
+            else {
+                $item_form->getField('value')->addError(
+                    __('Value already in use'));
+            }
         }
 
         include(STAFFINC_DIR . 'templates/list-item-properties.tmpl.php');
@@ -281,6 +255,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!($list = DynamicList::lookup($list_id)))
             Http::response(404, 'No such list');
 
+        $list = CustomListHandler::forList($list);
         $info = array(
             'title' => sprintf('%s &mdash; %s',
                 $list->getName(), __('Import Items')),
@@ -309,6 +284,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!$_POST['ids'])
             Http::response(422, 'Send `ids` parameter');
 
+        $list = CustomListHandler::forList($list);
         foreach ($_POST['ids'] as $id) {
             if ($item = $list->getItem( (int) $id)) {
                 $item->disable();
@@ -331,6 +307,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!$_POST['ids'])
             Http::response(422, 'Send `ids` parameter');
 
+        $list = CustomListHandler::forList($list);
         foreach ($_POST['ids'] as $id) {
             if ($item = $list->getItem( (int) $id)) {
                 $item->enable();
@@ -361,7 +338,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
                 Http::response(404, 'No such list item');
             }
         }
-        #Http::response(200, $this->encode(array('success' => true)));
+        Http::response(200, $this->encode(array('success' => true)));
     }
 
     function upload($id) {
@@ -392,6 +369,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
         elseif (!$form = DynamicForm::lookup($id))
             Http::response(400, 'No such form');
 
+        // XXX: Fetch the form via the list!
         ob_start();
         include STAFFINC_DIR . 'templates/dynamic-form-fields-view.tmpl.php';
         $html = ob_get_clean();
diff --git a/include/class.forms.php b/include/class.forms.php
index ecba6fa9f5af51f9d4249fa28e180e066e3ca8b0..d6957643e720682b1c77f0bf2e85cd83c2055fbc 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -2332,9 +2332,13 @@ class TicketStateField extends ChoiceField {
     function getChoices($verbose=false) {
         static $_choices;
 
+        $states = static::$_states;
+        if ($this->options['private_too'])
+            $states += static::$_privatestates;
+
         if (!isset($_choices)) {
             // Translate and cache the choices
-            foreach (static::$_states as $k => $v)
+            foreach ($states as $k => $v)
                 $_choices[$k] =  _P('ticket state name', $v['name']);
 
             $this->ht['default'] =  '';
diff --git a/include/class.list.php b/include/class.list.php
index b6c8c7327147441b74357fcac7e479193769f239..b52c4f72186606b869a16d70309f36df14d98322 100644
--- a/include/class.list.php
+++ b/include/class.list.php
@@ -38,9 +38,12 @@ interface CustomList {
 
     function getItem($id);
     function addItem($vars, &$errors);
+    function isItemUnique($vars);
 
     function getForm(); // Config form
     function hasProperties();
+    function getConfigurationForm();
+    function getSummaryFields();
 
     function getSortModes();
     function getSortMode();
@@ -66,8 +69,6 @@ interface CustomListItem {
     function getSortOrder();
 
     function getConfiguration();
-    function getConfigurationForm($source=null);
-
 
     function isEnabled();
     function isDeletable();
@@ -123,6 +124,16 @@ abstract class CustomListHandler {
     abstract function getItems($criteria);
     abstract function getItem($id);
     abstract function addItem($vars, &$errors);
+
+    static protected $registry = array();
+    static function forList(/* CustomList */ $list) {
+        if ($list->type && ($handler = static::$registry[$list->type]))
+            return new $handler($list);
+        return $list;
+    }
+    static function register($type, $handler) {
+        static::$registry[$type] = $handler;
+    }
 }
 
 /**
@@ -212,6 +223,15 @@ class DynamicList extends VerySimpleModel implements CustomList {
                 ->order_by($this->getListOrderBy());
     }
 
+    function search($q) {
+        $items = clone $this->getAllItems();
+        return $items->filter(Q::any(array(
+            'value__startswith' => $q,
+            'extra__contains' => $q,
+            'properties__contains' => '"'.$q,
+        )));
+    }
+
     function getItems($limit=false, $offset=false) {
         if (!$this->_items) {
             $this->_items = DynamicListItem::objects()->filter(
@@ -243,7 +263,6 @@ class DynamicList extends VerySimpleModel implements CustomList {
     }
 
     function addItem($vars, &$errors) {
-
         if (($item=$this->getItem($vars['value'])))
             return $item;
 
@@ -254,14 +273,21 @@ class DynamicList extends VerySimpleModel implements CustomList {
             'value' => $vars['value'],
             'extra' => $vars['abbrev']
         ));
-
-        $item->save();
-
         $this->_items = false;
 
         return $item;
     }
 
+    function isItemUnique($data) {
+        try {
+            $this->getItems()->filter(array('value'=>$data['value']))->one();
+            return false;
+        }
+        catch (DoesNotExist $e) {
+            return true;
+        }
+    }
+
     function getConfigurationForm($autocreate=false) {
         if (!$this->_form) {
             $this->_form = DynamicForm::lookup(array('type'=>'L'.$this->getId()));
@@ -274,6 +300,43 @@ class DynamicList extends VerySimpleModel implements CustomList {
         return $this->_form;
     }
 
+    function getListItemBasicForm($source=null, $item=false) {
+        return new SimpleForm(array(
+            'value' => new TextboxField(array(
+                'required' => true,
+                'label' => __('Value'),
+                'configuration' => array(
+                    'translatable' => $item ? $item->getTranslateTag('value') : false,
+                    'size' => 60,
+                    'length' => 0,
+                    'autofocus' => true,
+                ),
+            )),
+            'extra' => new TextboxField(array(
+                'label' => __('Abbreviation'),
+                'configuration' => array(
+                    'size' => 60,
+                    'length' => 0,
+                ),
+            )),
+        ), $source);
+    }
+
+    // Fields shown on the list items page
+    function getSummaryFields() {
+        foreach ($this->getConfigurationForm()->getFields() as $f) {
+            if (in_array($f->get('type'), array('text', 'datetime', 'phone')))
+                $prop_fields[] = $f;
+            if (strpos($f->get('type'), 'list-') === 0)
+                $prop_fields[] = $f;
+
+            // 4 property columns max
+            if (count($prop_fields) == 4)
+                break;
+        }
+        return $prop_fields;
+    }
+
     function isDeleteable() {
         return !$this->hasMask(static::MASK_DELETE);
     }
@@ -726,8 +789,7 @@ class DynamicListItem extends VerySimpleModel implements CustomListItem {
     function getConfigurationForm($source=null) {
         if (!$this->_form) {
             $config = $this->getConfiguration();
-            $this->_form = DynamicForm::lookup(
-                array('type'=>'L'.$this->get('list_id')))->getForm($source);
+            $this->_form = $this->list->getForm()->getForm($source);
             if (!$source && $config) {
                 $fields = $this->_form->getFields();
                 foreach ($fields as $f) {
@@ -813,7 +875,6 @@ class DynamicListItem extends VerySimpleModel implements CustomListItem {
             $ht['properties'] = JsonDataEncoder::encode($ht['properties']);
 
         $inst = parent::create($ht);
-        $inst->save(true);
 
         // Auto-config properties if any
         if ($ht['configuration'] && is_array($ht['configuration'])) {
@@ -868,6 +929,14 @@ class TicketStatusList extends CustomListHandler {
         return $this->_items;
     }
 
+    function search($q) {
+        $items = clone $this->getAllItems();
+        return $items->filter(Q::any(array(
+            'name__startswith' => $q,
+            'properties__contains' => '"'.$q,
+        )));
+    }
+
     function getItems($criteria = array()) {
 
         // Default to only enabled items
@@ -904,20 +973,28 @@ class TicketStatusList extends CustomListHandler {
     }
 
     function addItem($vars, &$errors) {
-
         $item = TicketStatus::create(array(
             'mode' => 1,
             'flags' => 0,
             'sort'  => $vars['sort'],
-            'name' => $vars['value'],
+            'name' => $vars['name'],
         ));
-        $item->save();
-
         $this->_items = false;
 
         return $item;
     }
 
+    function isItemUnique($data) {
+        try {
+            $this->getItems()->filter(array('name'=>$data['name']))->one();
+            return false;
+        }
+        catch (DoesNotExist $e) {
+            return true;
+        }
+    }
+
+
     static function getStatuses($criteria=array()) {
 
         $statuses = array();
@@ -952,58 +1029,8 @@ class TicketStatusList extends CustomListHandler {
 
         return $o[0];
     }
-}
-
-class TicketStatus
-extends VerySimpleModel
-implements CustomListItem, TemplateVariable {
-
-    static $meta = array(
-        'table' => TICKET_STATUS_TABLE,
-        'ordering' => array('name'),
-        'pk' => array('id'),
-        'joins' => array(
-            'tickets' => array(
-                'reverse' => 'TicketModel.status',
-                )
-        )
-    );
-
-    var $_list;
-    var $_form;
-    var $_settings;
-    var $_properties;
-
-    const ENABLED   = 0x0001;
-    const INTERNAL  = 0x0002; // Forbid deletion or name and status change.
-
-    protected function hasFlag($field, $flag) {
-        return 0 !== ($this->get($field) & $flag);
-    }
-
-    protected function clearFlag($field, $flag) {
-        return $this->set($field, $this->get($field) & ~$flag);
-    }
-
-    protected function setFlag($field, $flag) {
-        return $this->set($field, $this->get($field) | $flag);
-    }
-
-    protected function hasProperties() {
-        return ($this->get('properties'));
-    }
-
-    function getForm() {
-        if (!$this->_form && $this->_list) {
-            $this->_form = DynamicForm::lookup(
-                array('type'=>'L'.$this->_list->getId()));
-        }
-        return $this->_form;
-    }
 
     function getExtraConfigOptions($source=null) {
-
-
         $status_choices = array( 0 => __('System Default'));
         if (($statuses=TicketStatusList::getStatuses(
                         array( 'enabled' => true, 'states' =>
@@ -1011,7 +1038,6 @@ implements CustomListItem, TemplateVariable {
             foreach ($statuses as $s)
                 $status_choices[$s->getId()] = $s->getName();
 
-
         return array(
             'allowreopen' => new BooleanField(array(
                 'label' =>__('Allow Reopen'),
@@ -1048,11 +1074,9 @@ implements CustomListItem, TemplateVariable {
     }
 
     function getConfigurationForm($source=null) {
-
         if (!($form = $this->getForm()))
             return null;
 
-        $config = $this->getConfiguration();
         $form = $form->getForm($source);
         $fields = $form->getFields();
         foreach ($fields as $k => $f) {
@@ -1066,19 +1090,93 @@ implements CustomListItem, TemplateVariable {
             }
         }
 
-        if (!$source && $config) {
-            foreach ($fields as $f) {
-                $name = $f->get('id');
-                if (isset($config[$name]))
-                    $f->value = $f->to_php($config[$name]);
-                else if ($f->get('default'))
-                    $f->value = $f->get('default');
-            }
-        }
+        // Enable selection and display of private states
+        $form->getField('state')->options['private_too'] = true;
 
         return $form;
     }
 
+    function getListItemBasicForm($source=null, $item=false) {
+        return new SimpleForm(array(
+            'name' => new TextboxField(array(
+                'required' => true,
+                'label' => __('Value'),
+                'configuration' => array(
+                    'translatable' => $item ? $item->getTranslateTag('value') : false,
+                    'size' => 60,
+                    'length' => 0,
+                    'autofocus' => true,
+                ),
+            )),
+            'extra' => new TextboxField(array(
+                'label' => __('Abbreviation'),
+                'configuration' => array(
+                    'size' => 60,
+                    'length' => 0,
+                ),
+            )),
+        ), $source);
+    }
+
+    function getSummaryFields() {
+        // Like the main one, except the description and state fields are
+        // welcome on the screen
+        foreach ($this->getConfigurationForm()->getFields() as $f) {
+            if (in_array($f->get('type'), array('state', 'text', 'datetime', 'phone')))
+                $prop_fields[] = $f;
+            elseif (strpos($f->get('type'), 'list-') === 0)
+                $prop_fields[] = $f;
+            elseif ($f->get('name') == 'description')
+                $prop_fields[] = $f;
+
+            // 4 property columns max
+            if (count($prop_fields) == 4)
+                break;
+        }
+        return $prop_fields;
+    }
+}
+CustomListHandler::register('ticket-status', 'TicketStatusList');
+
+class TicketStatus
+extends VerySimpleModel
+implements CustomListItem, TemplateVariable {
+
+    static $meta = array(
+        'table' => TICKET_STATUS_TABLE,
+        'ordering' => array('name'),
+        'pk' => array('id'),
+        'joins' => array(
+            'tickets' => array(
+                'reverse' => 'TicketModel.status',
+                )
+        )
+    );
+
+    var $_list;
+    var $_form;
+    var $_settings;
+    var $_properties;
+
+    const ENABLED   = 0x0001;
+    const INTERNAL  = 0x0002; // Forbid deletion or name and status change.
+
+    protected function hasFlag($field, $flag) {
+        return 0 !== ($this->get($field) & $flag);
+    }
+
+    protected function clearFlag($field, $flag) {
+        return $this->set($field, $this->get($field) & ~$flag);
+    }
+
+    protected function setFlag($field, $flag) {
+        return $this->set($field, $this->get($field) | $flag);
+    }
+
+    protected function hasProperties() {
+        return ($this->get('properties'));
+    }
+
     function isEnabled() {
         return $this->hasFlag('mode', self::ENABLED);
     }
@@ -1221,6 +1319,31 @@ implements CustomListItem, TemplateVariable {
         return $base;
     }
 
+    function getList() {
+        if (!isset($this->_list))
+            $this->_list = DynamicList::lookup(array('type' => 'ticket-status'));
+        return $this->_list;
+    }
+
+    function getConfigurationForm($source=null) {
+        if (!$this->_form) {
+            $config = $this->getConfiguration();
+            $this->_form = $this->getList()->getConfigurationForm($source);
+            if (!$source && $config) {
+                $fields = $this->_form->getFields();
+                foreach ($fields as $f) {
+                    $val = $config[$f->get('id')] ?: $config[$f->get('name')];
+                    if (isset($val))
+                        $f->value = $f->to_php($val);
+                    elseif ($f->get('default'))
+                        $f->value = $f->get('default');
+                }
+            }
+        }
+
+        return $this->_form;
+    }
+
     function getConfiguration() {
 
         if (!$this->_settings) {
@@ -1228,8 +1351,8 @@ implements CustomListItem, TemplateVariable {
             if (!$this->_settings)
                 $this->_settings = array();
 
-            if ($this->getForm()) {
-                foreach ($this->getForm()->getFields() as $f)  {
+            if ($form = $this->getList()->getForm()) {
+                foreach ($form->getFields() as $f)  {
                     $name = mb_strtolower($f->get('name'));
                     $id = $f->get('id');
                     switch($name) {
@@ -1254,7 +1377,7 @@ implements CustomListItem, TemplateVariable {
 
     function setConfiguration($vars, &$errors=array()) {
         $properties = array();
-        foreach ($this->getConfigurationForm($vars)->getFields() as $f) {
+        foreach ($this->getList()->getConfigurationForm($vars)->getFields() as $f) {
             if ($this->isInternal() //Item is internal.
                     && !$f->isEditable())
                 continue;
@@ -1302,14 +1425,12 @@ implements CustomListItem, TemplateVariable {
     }
 
     function update($vars, &$errors) {
-
-        $fields = array('value' => 'name', 'sort' => 'sort');
-        foreach($fields as $k => $v) {
+        $fields = array('name', 'sort');
+        foreach($fields as $k) {
             if (isset($vars[$k]))
-                $this->set($v, $vars[$k]);
+                $this->set($k, $vars[$k]);
         }
-
-        return $this->save(true);
+        return $this->save();
     }
 
     function delete() {
diff --git a/include/class.util.php b/include/class.util.php
index 8cdec42ed4c3c60b5163efe6ad345cf27f0a5315..b4adf4985ae2b1321d9247ab0ea6a5ae4359ae2a 100644
--- a/include/class.util.php
+++ b/include/class.util.php
@@ -39,6 +39,8 @@ class ListObject implements IteratorAggregate, ArrayAccess, Serializable, Counta
     }
 
     function insert($i, $value) {
+        if ($i < 0)
+            $i += count($this->storage) + 1;
         array_splice($this->storage, $i, 0, array($value));
     }
 
diff --git a/include/staff/dynamic-list.inc.php b/include/staff/dynamic-list.inc.php
index 7d52ad1c18c44bee9f30e451449cd79fd70b680a..cfc87a59dbf3e361c7fcea610989c04a71ab94b0 100644
--- a/include/staff/dynamic-list.inc.php
+++ b/include/staff/dynamic-list.inc.php
@@ -32,7 +32,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
         <i class="icon-plus"></i> <?php echo __('Definition'); ?></a></li>
 <?php if ($list) { ?>
     <li class="active"><a href="#items">
-        <i class="icon-list"></i> <?php echo sprintf(__('Items (%d)'), $list->items->count()); ?></a></li>
+        <i class="icon-list"></i> <?php echo sprintf(__('Items (%d)'), $list->getItems()->count()); ?></a></li>
 <?php } ?>
     <li><a href="#properties">
         <i class="icon-asterisk"></i> <?php echo __('Properties'); ?></a></li>
@@ -236,7 +236,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
 
 <script type="text/javascript">
 $(function() {
-    $(document).on('click', 'a.field-config', function(e) {
+    $('#properties, #items').on('click', 'a.field-config', function(e) {
         e.preventDefault();
         var $id = $(this).attr('id');
         var url = 'ajax.php/'+$(this).attr('href').substr(1);
@@ -253,7 +253,7 @@ $(function() {
         });
         return false;
     });
-    $(document).on('click', 'a.items-action', function(e) {
+    $('#items').on('click', 'a.items-action', function(e) {
         e.preventDefault();
         var ids = [];
         $('form#save :checkbox.mass:checked').each(function() {
diff --git a/include/staff/templates/list-item-properties.tmpl.php b/include/staff/templates/list-item-properties.tmpl.php
index 35895173e86bc61d1d864a781360a90abe737f9f..a307baa7eb3d6781ac802d13e9b26d3f24d33865 100644
--- a/include/staff/templates/list-item-properties.tmpl.php
+++ b/include/staff/templates/list-item-properties.tmpl.php
@@ -1,6 +1,6 @@
 <?php
     $properties_form = $item ? $item->getConfigurationForm($_POST ?: null)
-        : $list->getConfigurationForm();
+        : $list->getConfigurationForm($_POST ?: null);
     $hasProperties = count($properties_form->getFields()) > 0;
 ?>
 <h3 class="drag-handle"><?php echo $list->getName(); ?> &mdash; <?php
@@ -14,7 +14,7 @@
         <a href="#value"><i class="icon-reorder"></i>
         <?php echo __('Value'); ?></a>
     </li>
-    <li><a href="#properties"><i class="icon-asterisk"></i>
+    <li><a href="#item-properties"><i class="icon-asterisk"></i>
         <?php echo __('Item Properties'); ?></a>
     </li>
 </ul>
@@ -33,7 +33,7 @@
 ?>
 </div>
 
-<div class="tab_content hidden" id="properties">
+<div class="tab_content hidden" id="item-properties">
 <?php
     if ($hasProperties) {
         $form = $properties_form;
diff --git a/include/staff/templates/list-item-row.tmpl.php b/include/staff/templates/list-item-row.tmpl.php
index 267cb1e5e7e0ca7a2d1666bf8c1993ab93b82f76..574f28e97d8cc2ca9b4e1c00c96e1b293f1aee41 100644
--- a/include/staff/templates/list-item-row.tmpl.php
+++ b/include/staff/templates/list-item-row.tmpl.php
@@ -15,8 +15,8 @@
                id="item-<?php echo $id; ?>"
             ><?php
                 echo sprintf('<i class="icon-edit" %s></i> ',
-                        $item->getConfiguration()
-                        ? '': 'style="color:red; font-weight:bold;"');
+                        ($prop_fields && !$item->getConfiguration())
+                        ? 'style="color:red; font-weight:bold;"' : '');
             ?>
             <?php echo Format::htmlchars($item->getValue()); ?>
             <?php
@@ -31,9 +31,11 @@
             </a>
         </td>
 <?php $props = $item->getConfiguration();
+if ($prop_fields) {
     foreach ($prop_fields as $F) { ?>
         <td style="max-width: 20%"><span class="truncate"><?php
         echo $F->display($props[$F->get('id')]);
         ?></span></td>
-<?php } ?>
+<?php }
+} ?>
     </tr>
diff --git a/include/staff/templates/list-items.tmpl.php b/include/staff/templates/list-items.tmpl.php
index 6f4de9991db411bd2ebf08ad5b920cb988ce41cb..d843a68d2b79b9e6c9b038b296a447a889a3b9b2 100644
--- a/include/staff/templates/list-items.tmpl.php
+++ b/include/staff/templates/list-items.tmpl.php
@@ -17,20 +17,25 @@
             echo Format::htmlchars($_POST['search']); ?>"/>
     </div>
     <div class="pull-right">
-        <?php if ($list->allowAdd()) { ?>
+<?php
+if ($list->allowAdd()) { ?>
         <a class="green button action-button field-config"
             href="#list/<?php
             echo $list->getId(); ?>/item/add">
             <i class="icon-plus-sign"></i>
             <?php echo __('Add New Item'); ?>
         </a>
+<?php
+    if (method_exists($list, 'importCsv')) { ?>
         <a class="action-button field-config"
             href="#list/<?php
             echo $list->getId(); ?>/import">
             <i class="icon-upload"></i>
             <?php echo __('Import Items'); ?>
         </a>
-        <?php } ?>
+<?php
+    }
+} ?>
         <span class="action-button pull-right" data-dropdown="#action-dropdown-more">
             <i class="icon-caret-down pull-right"></i>
             <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
@@ -56,19 +61,7 @@
 
 
 <?php
-$prop_fields = array();
-if ($list) {
-    foreach ($list->getConfigurationForm()->getFields() as $f) {
-        if (in_array($f->get('type'), array('text', 'datetime', 'phone')))
-            $prop_fields[] = $f;
-        if (strpos($f->get('type'), 'list-') === 0)
-            $prop_fields[] = $f;
-
-        // 4 property columns max
-        if (count($prop_fields) == 4)
-            break;
-    }
-}
+$prop_fields = ($list) ? $list->getSummaryFields() : array();
 ?>
 
     <table class="form_table fixed" width="940" border="0" cellspacing="0" cellpadding="2">
@@ -76,9 +69,13 @@ if ($list) {
         <tr>
             <th width="28" nowrap></th>
             <th><?php echo __('Value'); ?></th>
-<?php foreach ($prop_fields as $F) { ?>
+<?php
+if ($prop_fields) {
+    foreach ($prop_fields as $F) { ?>
             <th><?php echo $F->getLocal('label'); ?></th>
-<?php } ?>
+<?php
+    }
+} ?>
         </tr>
     </thead>
 
diff --git a/scp/js/scp.js b/scp/js/scp.js
index 19a0e1376025f1589c8f87e2872db0466b63a3f8..3eca5cee3195241d5377f05db857a6d66bb5d6ab 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -654,6 +654,10 @@ $.dialog = function (url, codes, cb, options) {
                         $('div.body', $popup).html(resp);
                         $popup.effect('shake');
                         $('#msg_notice, #msg_error', $popup).delay(5000).slideUp();
+                        $('div.tab_content[id] div.error:not(:empty)', $popup).each(function() {
+                          var div = $(this).closest('.tab_content');
+                          $('a[href^=#'+div.attr('id')+']').parent().addClass('error');
+                        });
                     }
                 }
             })
diff --git a/scp/lists.php b/scp/lists.php
index 57509ce0add2202edac46e4b419592e5272ec084..c5a552f3e17dfbe78de5f09c6c089f967092e8f8 100644
--- a/scp/lists.php
+++ b/scp/lists.php
@@ -13,7 +13,8 @@ elseif ($_REQUEST['type'])
 
 if ($criteria) {
     $list = DynamicList::lookup($criteria);
-
+    if ($list)
+        $list = CustomListHandler::forList($list);
     if ($list)
          $form = $list->getForm();
     else