From 3f25163dc15e2e552f5755fbeee40a259029f971 Mon Sep 17 00:00:00 2001 From: Jared Hancock <jared@osticket.com> Date: Mon, 29 Jun 2015 14:08:54 -0500 Subject: [PATCH] Add quick add for teams --- include/ajax.admin.php | 51 +++++++++++++++++-- include/class.dept.php | 7 +-- include/class.filter_action.php | 28 ++++++++-- include/class.forms.php | 15 +++++- include/class.team.php | 38 ++++++++++++-- include/staff/helptopic.inc.php | 17 ++++--- include/staff/helptopics.inc.php | 1 - ...department.tmpl.php => quick-add.tmpl.php} | 2 +- scp/ajax.php | 3 +- scp/css/scp.css | 5 +- scp/js/scp.js | 16 +++--- 11 files changed, 149 insertions(+), 34 deletions(-) rename include/staff/templates/{quick-add-department.tmpl.php => quick-add.tmpl.php} (95%) diff --git a/include/ajax.admin.php b/include/ajax.admin.php index 2e6ac9561..0cee34e4c 100644 --- a/include/ajax.admin.php +++ b/include/ajax.admin.php @@ -1,6 +1,7 @@ <?php require_once(INCLUDE_DIR . 'class.dept.php'); +require_once(INCLUDE_DIR . 'class.team.php'); class AdminAjaxAPI extends AjaxController { @@ -31,12 +32,12 @@ class AdminAjaxAPI extends AjaxController { $vars += array( 'group_membership' => Dept::ALERTS_DEPT_AND_GROUPS, ); - if ($dept->update($vars, $errors)) + if ($dept->update($vars, $errors)) { Http::response(201, $this->encode(array( 'id' => $dept->id, 'name' => $dept->name, ), 'application/json')); - + } foreach ($errors as $name=>$desc) if ($F = $form->getField($name)) $F->addError($desc); @@ -45,6 +46,50 @@ class AdminAjaxAPI extends AjaxController { $title = __("Add New Department"); $path = $ost->get_path_info(); - include STAFFINC_DIR . 'templates/quick-add-department.tmpl.php'; + include STAFFINC_DIR . 'templates/quick-add.tmpl.php'; + } + + /** + * Ajax: GET /admin/add/team + * + * Uses a dialog to add a new team + * + * Returns: + * 200 - HTML form for addition + * 201 - {id: <id>, name: <name>} + * + * Throws: + * 403 - Not logged in + */ + function addTeam() { + global $ost, $thisstaff; + + if (!$thisstaff) + Http::response(403, 'Agent login required'); + + $form = new TeamQuickAddForm($_POST); + + if ($_POST && $form->isValid()) { + $team = Team::create(); + $errors = array(); + $vars = $form->getClean(); + $vars += array( + 'isenabled' => true, + ); + if ($team->update($vars, $errors)) { + Http::response(201, $this->encode(array( + 'id' => $team->getId(), + 'name' => $team->name, + ), 'application/json')); + } + foreach ($errors as $name=>$desc) + if ($F = $form->getField($name)) + $F->addError($desc); + } + + $title = __("Add New Team"); + $path = $ost->get_path_info(); + + include STAFFINC_DIR . 'templates/quick-add.tmpl.php'; } } diff --git a/include/class.dept.php b/include/class.dept.php index bd2de00cd..473dca73b 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -557,13 +557,14 @@ implements TemplateVariable { function update($vars, &$errors) { global $cfg; - if (isset($this->id) && $this->getId() != $vars['id']) + $id = $this->id; + if ($id != $vars['id']) $errors['err']=__('Missing or invalid Dept ID (internal error).'); if (!$vars['name']) { $errors['name']=__('Name required'); - } elseif (($did=static::getIdByName($vars['name'], $vars['pid'])) - && (!isset($this->id) || $did!=$this->getId())) { + } elseif (($did = static::getIdByName($vars['name'], $vars['pid'])) + && $did != $this->id) { $errors['name']=__('Department already exists'); } diff --git a/include/class.filter_action.php b/include/class.filter_action.php index c9815d137..4cdac2e7a 100644 --- a/include/class.filter_action.php +++ b/include/class.filter_action.php @@ -281,8 +281,18 @@ class FA_RouteDepartment extends TriggerAction { function getConfigurationOptions() { return array( 'dept_id' => new ChoiceField(array( - 'configuration' => array('prompt' => __('Unchanged')), - 'choices' => Dept::getDepartments(), + 'configuration' => array( + 'prompt' => __('Unchanged'), + 'data' => array('quick-add' => 'department'), + ), + 'choices' => array_merge( + Dept::getDepartments(), + array(':new:' => '— '.__('Add New').' —') + ), + 'validators' => function($self) { + if ($self->getClean() === ':new:') + $self->addError(__('Select a department')); + } )), ); } @@ -353,8 +363,18 @@ class FA_AssignTeam extends TriggerAction { $choices = Team::getTeams(); return array( 'team_id' => new ChoiceField(array( - 'configuration' => array('prompt' => __('Unchanged')), - 'choices' => $choices, + 'configuration' => array( + 'prompt' => __('Unchanged'), + 'data' => array('quick-add' => 'team'), + ), + 'choices' => array_merge( + $choices, + array(':new:' => '— '.__('Add New').' —') + ), + 'validators' => function($self) { + if ($self->getClean() === ':new:') + $self->addError(__('Select a team')); + } )), ); } diff --git a/include/class.forms.php b/include/class.forms.php index bacfe3b36..3c898f26a 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -301,12 +301,22 @@ class Form { * */ class SimpleForm extends Form { - function __construct($fields=array(), $source=null, $options=array()) { parent::__construct($source, $options); $this->setFields($fields); } +} +abstract class AbstractForm extends Form { + function __construct($source=null, $options=array()) { + parent::__construct($source, $options); + $this->setFields($this->buildFields()); + } + /** + * Fetch the fields defined for this form. This method is only called + * once. + */ + abstract function buildFields(); } require_once(INCLUDE_DIR . "class.json.php"); @@ -2920,6 +2930,9 @@ class ChoicesWidget extends Widget { <select name="<?php echo $this->name; ?>[]" <?php echo implode(' ', array_filter(array($classes))); ?> id="<?php echo $this->id; ?>" + <?php foreach ($config['data'] as $D=>$V) { + echo ' data-'.$D.'="'.Format::htmlchars($V).'"'; + } ?> data-placeholder="<?php echo $prompt; ?>" <?php if ($config['multiselect']) echo ' multiple="multiple"'; ?>> diff --git a/include/class.team.php b/include/class.team.php index 12d14e713..1e397d684 100644 --- a/include/class.team.php +++ b/include/class.team.php @@ -162,18 +162,16 @@ implements TemplateVariable { ($vars['isenabled'] ? self::FLAG_ENABLED : 0) | (isset($vars['noalerts']) ? self::FLAG_NOALERTS : 0); $this->lead_id = $vars['lead_id'] ?: 0; - $this->name = $vars['name']; + $this->name = Format::striptags($vars['name']); $this->notes = Format::sanitize($vars['notes']); if ($this->save()) { // Remove checked members if ($vars['remove'] && is_array($vars['remove'])) { TeamMember::objects() - ->filter(array( - 'staff_id__in' => $vars['remove'])) + ->filter(array('staff_id__in' => $vars['remove'])) ->delete(); } - return true; } @@ -301,4 +299,34 @@ class TeamMember extends VerySimpleModel { ), ); } -?> + +class TeamQuickAddForm +extends AbstractForm { + function buildFields() { + return array( + 'name' => new TextboxField(array( + 'required' => true, + 'configuration' => array( + 'placeholder' => __('Name'), + 'classes' => 'span12', + 'autofocus' => true, + 'length' => 128, + ), + )), + 'lead_id' => new ChoiceField(array( + 'default' => 0, + 'choices' => array_merge( + array(0 => '— '.__('No Leader').' —'), + Staff::getStaffMembers() + ), + 'configuration' => array( + 'classes' => 'span12', + ), + )), + ); + } + + function render($staff=true) { + return parent::render($staff, false, array('template' => 'dynamic-form-simple.tmpl.php')); + } +} diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index 93e98cc08..bd3e28dc3 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -286,7 +286,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php echo __('Auto-assign To');?>: </td> <td> - <select name="assign"> + <select name="assign" data-quick-add> <option value="0">— <?php echo __('Unassigned'); ?> —</option> <?php if (($users=Staff::getStaffMembers())) { @@ -302,19 +302,20 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); } echo '</OPTGROUP>'; } - if (($teams=Team::getTeams())) { - echo sprintf('<OPTGROUP label="%s">', - sprintf(__('Teams (%d)'), count($teams))); + if ($teams = Team::getTeams()) { ?> + <optgroup data-quick-add="team" label="<?php + echo sprintf(__('Teams (%d)'), count($teams)); ?>"><?php foreach ($teams as $id => $name) { $k="t$id"; $selected = ($info['assign']==$k || $info['team_id']==$id) ? 'selected="selected"' : ''; ?> <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> <?php - } - echo '</OPTGROUP>'; - } - ?> + } ?> + <option value="0" data-quick-add data-id-prefix="t">— <?php echo __('Add New Team'); ?> —</option> + </optgroup> + <?php + } ?> </select> <span class="error"> <?php echo $errors['assign']; ?></span> <i class="help-tip icon-question-sign" href="#auto_assign_to"></i> diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 1c91d64cb..e9eda32bf 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -168,4 +168,3 @@ endif; </p> <div class="clear"></div> </div> - diff --git a/include/staff/templates/quick-add-department.tmpl.php b/include/staff/templates/quick-add.tmpl.php similarity index 95% rename from include/staff/templates/quick-add-department.tmpl.php rename to include/staff/templates/quick-add.tmpl.php index 4d0e71e79..fc5c01c66 100644 --- a/include/staff/templates/quick-add-department.tmpl.php +++ b/include/staff/templates/quick-add.tmpl.php @@ -3,7 +3,7 @@ <div class="clear"></div> <hr/> <form method="post" action="#<?php echo $path; ?>"> - <div class="inset"> + <div class="inset quick-add"> <?php $form->render(); ?> </div> <hr> diff --git a/scp/ajax.php b/scp/ajax.php index 3634a6cdb..55dee8d6d 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -227,7 +227,8 @@ $dispatcher = patterns('', )), url('^/admin', patterns('', url('^/quick-add', patterns('ajax.admin.php:AdminAjaxAPI', - url('^/department$', 'addDepartment') + url('^/department$', 'addDepartment'), + url('^/team', 'addTeam') )) )) ); diff --git a/scp/css/scp.css b/scp/css/scp.css index a3e0b4b8e..af77ddc98 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -2450,9 +2450,12 @@ td.indented { .iblock { display: inline-block; } -form.inset { +form .inset { padding: 10px; } +.dialog form .inset { + min-height: 150px; +} .span12 { width: 100%; } diff --git a/scp/js/scp.js b/scp/js/scp.js index b8e861843..041502735 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -959,18 +959,22 @@ if ($.support.pjax) { // Quick-Add dialogs $(document).on('change', 'select[data-quick-add]', function() { var $select = $(this), - selected = $select.find('option:selected'); - if (selected.data('quick-add') === undefined) + selected = $select.find('option:selected'), + type = selected.parent().closest('[data-quick-add]').data('quickAdd'); + if (!type || (selected.data('quickAdd') === undefined && selected.val() !== ':new:')) return; - $.dialog('ajax.php/admin/quick-add/' + $select.data('quick-add'), 201, + $.dialog('ajax.php/admin/quick-add/' + type, 201, function(xhr, data) { data = JSON.parse(data); if (data && data.id && data.name) { + var id = data.id; + if (selected.data('idPrefix')) + id = selected.data('idPrefix') + id; $('<option>') - .attr('value', data.id) + .attr('value', id) .text(data.name) - .insertBefore($select.find('option[data-quick-add]')); - $select.val(data.id); + .insertBefore(selected); + $select.val(id); } }); }); -- GitLab