diff --git a/include/class.queue.php b/include/class.queue.php index c57630e69f4c84d44d709b6040f41237a64098a8..7326bc6281dff644d1f648584bb4f915e54475e7 100644 --- a/include/class.queue.php +++ b/include/class.queue.php @@ -20,7 +20,7 @@ class CustomQueue extends VerySimpleModel { 'table' => QUEUE_TABLE, 'pk' => array('id'), 'ordering' => array('sort'), - 'select_related' => array('parent'), + 'select_related' => array('parent', 'default_sort'), 'joins' => array( 'children' => array( 'reverse' => 'CustomQueue.parent', @@ -34,6 +34,10 @@ class CustomQueue extends VerySimpleModel { 'reverse' => 'QueueSortGlue.queue', 'broker' => 'QueueSortListBroker', ), + 'default_sort' => array( + 'constraint' => array('sort_id' => 'QueueSort.id'), + 'null' => true, + ), 'parent' => array( 'constraint' => array( 'parent_id' => 'CustomQueue.id', @@ -48,12 +52,13 @@ class CustomQueue extends VerySimpleModel { ) ); - const FLAG_PUBLIC = 0x0001; // Shows up in e'eryone's saved searches - const FLAG_QUEUE = 0x0002; // Shows up in queue navigation - const FLAG_CONTAINER = 0x0004; // Container for other queues ('Open') + const FLAG_PUBLIC = 0x0001; // Shows up in e'eryone's saved searches + const FLAG_QUEUE = 0x0002; // Shows up in queue navigation + const FLAG_DISABLED = 0x0004; // NOT enabled const FLAG_INHERIT_CRITERIA = 0x0008; // Include criteria from parent - const FLAG_INHERIT_COLUMNS = 0x0010; // Inherit column layout from parent - const FLAG_INHERIT_SORTING = 0x0020; // Inherit advanced sorting from parent + const FLAG_INHERIT_COLUMNS = 0x0010; // Inherit column layout from parent + const FLAG_INHERIT_SORTING = 0x0020; // Inherit advanced sorting from parent + const FLAG_INHERIT_DEF_SORT = 0x0040; // Inherit default selected sort var $criteria; @@ -536,6 +541,24 @@ class CustomQueue extends VerySimpleModel { return $this->sorts; } + function getDefaultSortId() { + if ($this->isDefaultSortInherited() && $this->parent + && ($sort_id = $this->parent->getDefaultSortId()) + ) { + return $sort_id; + } + return $this->sort_id; + } + + function getDefaultSort() { + if ($this->isDefaultSortInherited() && $this->parent + && ($sort = $this->parent->getDefaultSort()) + ) { + return $sort; + } + return $this->default_sort; + } + function getStatus() { return 'bogus'; } @@ -666,6 +689,15 @@ class CustomQueue extends VerySimpleModel { $qs = $qs->filter($q); } } + + return $qs; + } + + function applyDefaultSort($qs) { + // Apply default sort + if ($sorter = $this->getDefaultSort()) { + $qs = $sorter->applySort($qs, false, $this->getRoot()); + } return $qs; } @@ -695,6 +727,10 @@ class CustomQueue extends VerySimpleModel { return $this->hasFlag(self::FLAG_INHERIT_SORTING); } + function isDefaultSortInherited() { + return $this->hasFlag(self::FLAG_INHERIT_DEF_SORT); + } + function buildPath() { if (!$this->id) return; @@ -743,8 +779,21 @@ class CustomQueue extends VerySimpleModel { if ($this->parent_id && !$this->parent) $errors['parent_id'] = __('Select a valid queue'); - // Set basic queue information + // Configure quick filter options $this->filter = $vars['filter']; + if ($vars['sort_id']) { + if ($vars['filter'] === '::') { + if (!$this->parent) + $errors['filter'] = __('No parent selected'); + } + elseif ($vars['filter'] && !array_key_exists($vars['filter'], + static::getSearchableFields($this->getRoot())) + ) { + $errors['filter'] = __('Select an item from the list'); + } + } + + // Set basic queue information $this->path = $this->buildPath(); $this->setFlag(self::FLAG_INHERIT_CRITERIA, $this->parent_id > 0 && isset($vars['inherit'])); @@ -793,29 +842,52 @@ class CustomQueue extends VerySimpleModel { // Update advanced sorting options for the queue if (isset($vars['sorts']) && !$this->hasFlag(self::FLAG_INHERIT_SORTING)) { - $new = $vars['sorts']; - $order = array_keys($new); + $new = $order = $vars['sorts']; foreach ($this->sorts as $sort) { $key = $sort->sort_id; - if (!in_array($key, $vars['sorts'])) { + $idx = array_search($key, $vars['sorts']); + if (false === $idx) { $this->sorts->remove($sort); - continue; } - $sort->set('sort', array_search($key, $order)); - unset($new[$key]); + else { + $sort->set('sort', $idx); + unset($new[$idx]); + } } // Add new columns foreach ($new as $id) { + if (!$sort = QueueSort::lookup($id)) + continue; $glue = new QueueSortGlue(array( 'sort_id' => $id, + 'queue' => $this, 'sort' => array_search($id, $order), )); - $glue->queue = $this; - $this->sorts->add(QueueSort::lookup($id), $glue); + $this->sorts->add($sort, $glue); } // Re-sort the in-memory columns array $this->sorts->sort(function($c) { return $c->sort; }); } + if (!count($this->sorts) && $this->parent) { + // No sorting -- imply sorting inheritance + $this->setFlag(self::FLAG_INHERIT_SORTING); + } + + // Configure default sorting + $this->setFlag(self::FLAG_INHERIT_DEF_SORT, + $this->parent && $vars['sort_id'] === '::'); + if ($vars['sort_id']) { + if ($vars['sort_id'] === '::') { + if (!$this->parent) + $errors['sort_id'] = __('No parent selected'); + } + elseif ($qs = QueueSort::lookup($vars['sort_id'])) { + $this->sort_id = $vars['sort_id']; + } + else { + $errors['sort_id'] = __('Select an item from the list'); + } + } // TODO: Move this to SavedSearch::update() and adjust // AjaxSearch::_saveSearch() @@ -1299,7 +1371,7 @@ class QueueColumnCondition { } function getShortHash() { - return substr(base64_encode($this->getHash(true)), -10); + return substr(base64_encode($this->getHash(true)), 0, 7); } static function getUid() { @@ -1859,7 +1931,7 @@ extends VerySimpleModel { static function forQueue(CustomQueue $queue) { return static::objects()->filter([ - 'root' => $queue->getRoot(), + 'root' => $queue->root ?: 'T', ]); } @@ -2132,7 +2204,7 @@ extends AbstractForm { class QueueSortDataConfigForm extends AbstractForm { function getInstructions() { - return __('Add, and remove the fields in this list using the options below. Sorting is priortized in ascending order.'); + return __('Add, and remove the fields in this list using the options below. Sorting can be performed on any field, whether displayed in the queue or not.'); } function buildFields() { diff --git a/include/staff/queue.inc.php b/include/staff/queue.inc.php index 63db07b90cf9687c8b21646acd33283087ecfcdd..75a5edf56074142bbf7d4d4358623e870569ae1a 100644 --- a/include/staff/queue.inc.php +++ b/include/staff/queue.inc.php @@ -118,34 +118,55 @@ else { ?> <option value="<?php echo $path; ?>" <?php if ($path == $queue->filter) echo 'selected="selected"'; ?> - ><?php echo $label; ?></option> + ><?php echo Format::htmlchars($label); ?></option> <?php } ?> </select> + <div class="error"><?php + echo Format::htmlchars($errors['filter']); ?></div> <br/> - <br/> - <div><strong><?php echo __("Sort Options"); ?></strong></div> + + <div><strong><?php echo __("Defaut Sorting"); ?></strong></div> <hr/> + <select name="sort_id"> + <option value="" <?php if ($queue->filter == "") + echo 'selected="selected"'; ?>>— <?php echo __('None'); ?> —</option> + <option value="::" <?php if ($queue->isDefaultSortInherited()) + echo 'selected="selected"'; ?>>— <?php echo __('Inherit from parent'); + if ($queue->parent + && ($sort = $queue->parent->getDefaultSort())) + echo sprintf(' (%s)', $sort->getName()); ?> —</option> +<?php foreach ($queue->getSortOptions() as $sort) { ?> + <option value="<?php echo $sort->id; ?>" + <?php if ($sort->id == $queue->sort_id) echo 'selected="selected"'; ?> + ><?php echo Format::htmlchars($sort->getName()); ?></option> +<?php } ?> + </select> + <div class="error"><?php + echo Format::htmlchars($errors['sort_id']); ?></div> </td> </table> </div> <div class="hidden tab_content" id="columns"> - <div class="tab-desc"> - <p><b><?php echo __("Manage columns in this queue"); ?></b> - <br><?php echo __( - "Add, remove, and customize the content of the columns in this queue using the options below. Click a column header to manage or resize it"); ?></p> + <div> + <h3 class="title"><?php echo __("Manage columns in this queue"); ?> + <div class="sub-title"><?php echo __( + 'Add, and remove the fields in this list using the options below. Drag columns to reorder them.'); + ?></div> + </h3> </div> <?php include STAFFINC_DIR . "templates/queue-columns.tmpl.php"; ?> </div> - <div class="hidden tab_content" id="sorting-tab"> - <div class="tab-desc"> - <p><b><?php echo __("Manage Queue Sorting"); ?></b> - <br><?php echo __("Add, edit or remove the sorting criteria for this custom queue using the options below. Sorting is priortized in ascending order."); ?></p> - </div> - <table class="queue-sort table"> + <div class="hidden tab_content" id="sorting-tab"> + <h3 class="title"><?php echo __("Manage Queue Sorting"); ?> + <div class="sub-title"><?php echo __( + "Select the sorting options available in the sorting drop-down when viewing the queue. New items can be added via the drop-down below."); + ?></div> + </h3> + <table class="queue-sort table"> <?php if ($queue->parent) { ?> <tbody> @@ -186,8 +207,11 @@ if ($queue->parent) { ?> </div> </td> <td> - <a href="#" class="pull-right drop-sort" title="<?php echo __('Delete'); - ?>"><i class="icon-trash"></i></a> + <div class="pull-right"> + <small class="hidden faded"><?php echo __('Default'); ?></small> + <a href="#" class="drop-sort" title="<?php echo __('Delete'); + ?>"><i class="icon-trash"></i></a> + </div> </td> <tr> </tbody> @@ -204,7 +228,7 @@ if ($queue->parent) { ?> echo __('Add Sort Criteria'); ?> —</option> <?php foreach (QueueSort::forQueue($queue) as $QS) { ?> <option value="<?php echo $QS->id; ?>"><?php - echo Format::htmlchars($QS->name); ?></option> + echo Format::htmlchars($QS->getName()); ?></option> <?php } ?> <option value="0" data-quick-add>— <?php echo __('Add New Sort Criteria');?> —</option> @@ -236,7 +260,7 @@ var Q = setInterval(function() { copy.find('span').text(info['name']); copy.attr('id', '').show().insertBefore($('#sort-template')); copy.removeClass('hidden'); - copy.find('a.drop-sort').click(function() { + var a = copy.find('a.drop-sort').click(function() { $('<option>') .attr('value', copy.find('input[data-name^=sorts]').val()) .text(info.name) @@ -246,6 +270,10 @@ var Q = setInterval(function() { copy.fadeOut(function() { $(this).remove(); }); return false; }); + if (info.default) { + a.parent().find('small').show(); + a.remove(); + } var selected = $('#add-sort').find('option[value=' + sortid + ']'); selected.remove(); }; @@ -259,8 +287,9 @@ var Q = setInterval(function() { return false; }); <?php foreach ($queue->getSortOptions() as $C) { - echo sprintf('addSortOption(%d, {name: %s});', - $C->sort_id, JsonDataEncoder::encode($C->getName()) + echo sprintf('addSortOption(%d, {name: %s, default: %d});', + $C->sort_id, JsonDataEncoder::encode($C->getName()), + $queue->getDefaultSortId() == $C->sort_id ); } ?> }, 25); diff --git a/include/staff/templates/queue-preview.tmpl.php b/include/staff/templates/queue-preview.tmpl.php index 81ae549f9a102d791af619264a11a92f0e4b0806..0e1e945b93c1b8e5d224eab13f7cd5b7ab214786 100644 --- a/include/staff/templates/queue-preview.tmpl.php +++ b/include/staff/templates/queue-preview.tmpl.php @@ -13,6 +13,11 @@ $tickets = $pageNav->paginate($tickets); // Identify columns of output $columns = $queue->getColumns(); +// Apply default sort option +if ($queue_sort = $queue->getDefaultSort()) { + $tickets = $queue_sort->applySort($tickets); +} + ?> <table class="list queue" border="0" cellspacing="1" cellpadding="2" width="940"> <thead> diff --git a/include/staff/templates/queue-sort.tmpl.php b/include/staff/templates/queue-sort.tmpl.php index 5c2a14e63b2d4045f62b56daeb8fbdd5201214e3..d83e8f02f964c487a4a84373c3e0d7e04d2acf6a 100644 --- a/include/staff/templates/queue-sort.tmpl.php +++ b/include/staff/templates/queue-sort.tmpl.php @@ -2,12 +2,16 @@ if (count($queue->getSortOptions()) === 0) return; -if (strpos($_GET['sort'], 'qs-') === 0) { +if (isset($sort) && isset($sort['queuesort'])) { + $queuesort = $sort['queuesort']; + $sort_id = $queuesort->id; + $sort_dir = $sort['dir']; +} +elseif (strpos($_GET['sort'], 'qs-') === 0) { $sort_id = substr($_GET['sort'], 3); $queuesort = QueueSort::lookup($sort_id); + $sort_dir = $_GET['dir']; } - -$sort_dir = $_GET['dir']; ?> <span class="action-button muted" data-dropdown="#sort-dropdown" diff --git a/include/staff/templates/queue-tickets.tmpl.php b/include/staff/templates/queue-tickets.tmpl.php index 83ff38e0a07a91a744a7851c3691ae4800174c72..d7a180bbc5190dc57f882c72b6b1c53b66ee2e9e 100644 --- a/include/staff/templates/queue-tickets.tmpl.php +++ b/include/staff/templates/queue-tickets.tmpl.php @@ -44,6 +44,34 @@ if ($args['a'] !== 'search') unset($args['a']); $refresh_url = $path . '?' . http_build_query($args); +// Establish the selected or default sorting mechanism +if (isset($_GET['sort']) && is_numeric($_GET['sort'])) { + $sort = $_SESSION['sort'][$queue->getId()] = array( + 'col' => (int) $_GET['sort'], + 'dir' => (int) $_GET['dir'], + ); +} +elseif (isset($_GET['sort']) + // Drop the leading `qs-` + && (strpos($_GET['sort'], 'qs-') === 0) + && ($sort_id = substr($_GET['sort'], 3)) + && is_numeric($sort_id) + && ($sort = QueueSort::lookup($sort_id)) +) { + $sort = $_SESSION['sort'][$queue->getId()] = array( + 'queuesort' => $sort, + 'dir' => (int) $_GET['dir'], + ); +} +elseif (isset($_SESSION['sort'][$queue->getId()])) { + $sort = $_SESSION['sort'][$queue->getId()]; +} +elseif ($queue_sort = $queue->getDefaultSort()) { + $sort = $_SESSION['sort'][$queue->getId()] = array( + 'queuesort' => $queue_sort, + 'dir' => (int) $_GET['dir'] ?: 0, + ); +} ?> <!-- SEARCH FORM START --> @@ -162,27 +190,8 @@ if ($canManageTickets) { ?> <th style="width:12px"></th> <?php } -if (isset($_GET['sort']) && is_numeric($_GET['sort'])) { - $sort = $_SESSION['sort'][$queue->getId()] = array( - 'col' => (int) $_GET['sort'], - 'dir' => (int) $_GET['dir'], - ); -} -elseif (isset($_GET['sort']) - // Drop the leading `qs-` - && (strpos($_GET['sort'], 'qs-') === 0) - && ($sort_id = substr($_GET['sort'], 3)) - && is_numeric($sort_id) - && ($sort = QueueSort::lookup($sort_id)) -) { - $sort = $_SESSION['sort'][$queue->getId()] = array( - 'queuesort' => $sort, - 'dir' => (int) $_GET['dir'], - ); -} -else { - $sort = $_SESSION['sort'][$queue->getId()]; -} + +$sorted = false; foreach ($columns as $C) { $heading = Format::htmlchars($C->getLocalHeading()); if ($C->isSortable()) { @@ -199,9 +208,10 @@ foreach ($columns as $C) { // Sort by this column ? if (isset($sort['col']) && $sort['col'] == $C->id) { $tickets = $C->applySort($tickets, $sort['dir']); + $sorted = true; } } -if (isset($sort['queuesort'])) { +if (!$sorted && isset($sort['queuesort'])) { $sort['queuesort']->applySort($tickets, $sort['dir']); } ?> diff --git a/include/upgrader/streams/core.sig b/include/upgrader/streams/core.sig index 482fa87699383c4d90d2424748e47fd0344c75c0..891a53e7d2881a1f8a469df49bdd3de22c29a0e3 100644 --- a/include/upgrader/streams/core.sig +++ b/include/upgrader/streams/core.sig @@ -1 +1 @@ -a099b35b5ed141de6213f165b197e623 +ad9d0a5f1bd9f83a4ecb3f590b334eac diff --git a/include/upgrader/streams/core/934b8db8-a099b35b.patch.sql b/include/upgrader/streams/core/934b8db8-ad9d0a5f.patch.sql similarity index 79% rename from include/upgrader/streams/core/934b8db8-a099b35b.patch.sql rename to include/upgrader/streams/core/934b8db8-ad9d0a5f.patch.sql index 4a3b26006f6fd73d539580fef381b16dbfe1ea2e..2dad302c921dee0225f4b96104487c8c970be5fc 100644 --- a/include/upgrader/streams/core/934b8db8-a099b35b.patch.sql +++ b/include/upgrader/streams/core/934b8db8-ad9d0a5f.patch.sql @@ -1,6 +1,6 @@ /** * @version v1.11 - * @signature a099b35b5ed141de6213f165b197e623 + * @signature ad9d0a5f1bd9f83a4ecb3f590b334eac * @title Custom Queues, Advanced Sorting * * Add advanced sorting configuration to custom queues @@ -17,19 +17,19 @@ CREATE TABLE `%TABLE_PREFIX%queue_sort` ( `columns` text, `updated` datetime DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_sorts`; CREATE TABLE `%TABLE_PREFIX%queue_sorts` ( - `queue_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `queue_id` int(11) unsigned NOT NULL, `sort_id` int(11) unsigned NOT NULL, `bits` int(11) unsigned NOT NULL DEFAULT '0', `sort` int(10) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`queue_id`) + PRIMARY KEY (`queue_id`, `sort_id`) ) DEFAULT CHARSET=utf8; -- Finished with patch UPDATE `%TABLE_PREFIX%config` - SET `value` = 'a099b35b5ed141de6213f165b197e623' + SET `value` = 'ad9d0a5f1bd9f83a4ecb3f590b334eac' WHERE `key` = 'schema_signature' AND `namespace` = 'core'; diff --git a/include/upgrader/streams/core/934b8db8-a099b35b.task.php b/include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php similarity index 100% rename from include/upgrader/streams/core/934b8db8-a099b35b.task.php rename to include/upgrader/streams/core/934b8db8-ad9d0a5f.task.php diff --git a/scp/css/scp.css b/scp/css/scp.css index 9df71e3cc556af2852c3949d9f8e699d66a1b9c4..c9e2f4d192e295530bc1f3ba77b3f81dbe908be7 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -1435,6 +1435,12 @@ h3 { padding:5px 0; color:#444; } + +h3.title { color: black; line-height: 1.25em; } +h3.title > .sub-title { + font-weight: normal; + font-size: 1.1rem; +} .tixTitle { padding:0 5px 0px; } diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql index 78c51e1b7cda3e370bba3ab0fdb291f1976d6be8..1893c482e7b1a015d8e95927129ec761a28e06b6 100644 --- a/setup/inc/streams/core/install-mysql.sql +++ b/setup/inc/streams/core/install-mysql.sql @@ -876,15 +876,15 @@ CREATE TABLE `%TABLE_PREFIX%queue_sort` ( `columns` text, `updated` datetime DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_sorts`; CREATE TABLE `%TABLE_PREFIX%queue_sorts` ( - `queue_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `queue_id` int(11) unsigned NOT NULL, `sort_id` int(11) unsigned NOT NULL, `bits` int(11) unsigned NOT NULL DEFAULT '0', `sort` int(10) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`queue_id`) + PRIMARY KEY (`queue_id`, `sort_id`) ) DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%translation`;