Page MenuHomePhorge

No OneTemporary

diff --git a/src/applications/maniphest/controller/ManiphestBatchEditController.php b/src/applications/maniphest/controller/ManiphestBatchEditController.php
index 5fb1938f84..3d69493ae1 100644
--- a/src/applications/maniphest/controller/ManiphestBatchEditController.php
+++ b/src/applications/maniphest/controller/ManiphestBatchEditController.php
@@ -1,295 +1,296 @@
<?php
/**
* @group maniphest
*/
final class ManiphestBatchEditController extends ManiphestController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$task_ids = $request->getArr('batch');
$tasks = id(new ManiphestTask())->loadAllWhere(
'id IN (%Ld)',
$task_ids);
$actions = $request->getStr('actions');
if ($actions) {
$actions = json_decode($actions, true);
}
if ($request->isFormPost() && is_array($actions)) {
foreach ($tasks as $task) {
$xactions = $this->buildTransactions($actions, $task);
if ($xactions) {
$editor = new ManiphestTransactionEditor();
$editor->setActor($user);
$editor->applyTransactions($task, $xactions);
}
}
$task_ids = implode(',', mpull($tasks, 'getID'));
return id(new AphrontRedirectResponse())
->setURI('/maniphest/view/custom/?s=oc&tasks='.$task_ids);
}
$panel = new AphrontPanelView();
- $panel->setHeader('Maniphest Batch Editor');
+ $panel->setHeader(pht('Maniphest Batch Editor'));
+ $panel->setNoBackground();
$handle_phids = mpull($tasks, 'getOwnerPHID');
$handles = $this->loadViewerHandles($handle_phids);
$list = new ManiphestTaskListView();
$list->setTasks($tasks);
$list->setUser($user);
$list->setHandles($handles);
$template = new AphrontTokenizerTemplateView();
$template = $template->render();
require_celerity_resource('maniphest-batch-editor');
Javelin::initBehavior(
'maniphest-batch-editor',
array(
'root' => 'maniphest-batch-edit-form',
'tokenizerTemplate' => $template,
'sources' => array(
'project' => array(
'src' => '/typeahead/common/projects/',
'placeholder' => 'Type a project name...',
),
'owner' => array(
'src' => '/typeahead/common/searchowner/',
'placeholder' => 'Type a user name...',
'limit' => 1,
),
),
'input' => 'batch-form-actions',
'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(),
'statusMap' => ManiphestTaskStatus::getTaskStatusMap(),
));
$form = new AphrontFormView();
$form->setUser($user);
$form->setID('maniphest-batch-edit-form');
foreach ($tasks as $task) {
$form->appendChild(
phutil_render_tag(
'input',
array(
'type' => 'hidden',
'name' => 'batch[]',
'value' => $task->getID(),
),
null));
}
$form->appendChild(
phutil_render_tag(
'input',
array(
'type' => 'hidden',
'name' => 'actions',
'id' => 'batch-form-actions',
),
null));
$form->appendChild('<p>These tasks will be edited:</p>');
$form->appendChild($list);
$form->appendChild(
id(new AphrontFormInsetView())
->setTitle('Actions')
->setRightButton(javelin_render_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'add-action',
'mustcapture' => true,
),
'Add Another Action'))
->setContent(javelin_render_tag(
'table',
array(
'sigil' => 'maniphest-batch-actions',
'class' => 'maniphest-batch-actions-table',
),
'')))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Update Tasks')
->addCancelButton('/maniphest/', 'Done'));
$panel->appendChild($form);
return $this->buildStandardPageResponse(
$panel,
array(
'title' => 'Batch Editor',
));
}
private function buildTransactions($actions, ManiphestTask $task) {
$value_map = array();
$type_map = array(
'add_comment' => ManiphestTransactionType::TYPE_NONE,
'assign' => ManiphestTransactionType::TYPE_OWNER,
'status' => ManiphestTransactionType::TYPE_STATUS,
'priority' => ManiphestTransactionType::TYPE_PRIORITY,
'add_project' => ManiphestTransactionType::TYPE_PROJECTS,
'remove_project' => ManiphestTransactionType::TYPE_PROJECTS,
);
$edge_edit_types = array(
'add_project' => true,
'remove_project' => true,
);
$xactions = array();
foreach ($actions as $action) {
if (empty($type_map[$action['action']])) {
throw new Exception("Unknown batch edit action '{$action}'!");
}
$type = $type_map[$action['action']];
// Figure out the current value, possibly after modifications by other
// batch actions of the same type. For example, if the user chooses to
// "Add Comment" twice, we should add both comments. More notably, if the
// user chooses "Remove Project..." and also "Add Project...", we should
// avoid restoring the removed project in the second transaction.
if (array_key_exists($type, $value_map)) {
$current = $value_map[$type];
} else {
switch ($type) {
case ManiphestTransactionType::TYPE_NONE:
$current = null;
break;
case ManiphestTransactionType::TYPE_OWNER:
$current = $task->getOwnerPHID();
break;
case ManiphestTransactionType::TYPE_STATUS:
$current = $task->getStatus();
break;
case ManiphestTransactionType::TYPE_PRIORITY:
$current = $task->getPriority();
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$current = $task->getProjectPHIDs();
break;
}
}
// Check if the value is meaningful / provided, and normalize it if
// necessary. This discards, e.g., empty comments and empty owner
// changes.
$value = $action['value'];
switch ($type) {
case ManiphestTransactionType::TYPE_NONE:
if (!strlen($value)) {
continue 2;
}
break;
case ManiphestTransactionType::TYPE_OWNER:
if (empty($value)) {
continue 2;
}
$value = head($value);
if ($value === ManiphestTaskOwner::OWNER_UP_FOR_GRABS) {
$value = null;
}
break;
case ManiphestTransactionType::TYPE_PROJECTS:
if (empty($value)) {
continue 2;
}
break;
}
// If the edit doesn't change anything, go to the next action. This
// check is only valid for changes like "owner", "status", etc, not
// for edge edits, because we should still apply an edit like
// "Remove Projects: A, B" to a task with projects "A, B".
if (empty($edge_edit_types[$action['action']])) {
if ($value == $current) {
continue;
}
}
// Apply the value change; for most edits this is just replacement, but
// some need to merge the current and edited values (add/remove project).
switch ($type) {
case ManiphestTransactionType::TYPE_NONE:
if (strlen($current)) {
$value = $current."\n\n".$value;
}
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$is_remove = ($action['action'] == 'remove_project');
$current = array_fill_keys($current, true);
$value = array_fill_keys($value, true);
$new = $current;
$did_something = false;
if ($is_remove) {
foreach ($value as $phid => $ignored) {
if (isset($new[$phid])) {
unset($new[$phid]);
$did_something = true;
}
}
} else {
foreach ($value as $phid => $ignored) {
if (empty($new[$phid])) {
$new[$phid] = true;
$did_something = true;
}
}
}
if (!$did_something) {
continue 2;
}
$value = array_keys($new);
break;
}
$value_map[$type] = $value;
}
$template = new ManiphestTransaction();
$template->setAuthorPHID($this->getRequest()->getUser()->getPHID());
// TODO: Set content source to "batch edit".
foreach ($value_map as $type => $value) {
$xaction = clone $template;
$xaction->setTransactionType($type);
switch ($type) {
case ManiphestTransactionType::TYPE_NONE:
$xaction->setComments($value);
break;
default:
$xaction->setNewValue($value);
break;
}
$xactions[] = $xaction;
}
return $xactions;
}
}
diff --git a/webroot/rsrc/css/application/maniphest/task-summary.css b/webroot/rsrc/css/application/maniphest/task-summary.css
index 89c32a0d7f..34050b4fc1 100644
--- a/webroot/rsrc/css/application/maniphest/task-summary.css
+++ b/webroot/rsrc/css/application/maniphest/task-summary.css
@@ -1,200 +1,201 @@
/**
* @provides maniphest-task-summary-css
*/
.maniphest-task-summary {
width: 100%;
margin: 4px 0;
border-collapse: separate;
font-size: 12px;
color: #333;
}
.maniphest-task-summary td {
padding: 6px 4px;
background: #fff;
white-space: nowrap;
border-style: solid;
border-top-color: #d5dadf;
border-bottom-color: #d5dadf;
border-width: 1px 0;
}
.maniphest-task-summary td em {
color: #888888;
}
.maniphest-batch-selected td {
background: #fff;
}
.maniphest-task-summary td.maniphest-task-handle {
padding: 0 4px;
width: 1px;
border-right-width: 1px;
border-right-color: #d5dadf;
}
.maniphest-task-summary td.maniphest-task-batch {
padding-right: 0px;
width: 16px;
text-align: center;
overflow: hidden;
}
.maniphest-task-summary td.maniphest-task-batch,
.maniphest-task-summary td.maniphest-task-batch input {
cursor: pointer;
}
.maniphest-task-summary td.maniphest-task-batch input {
margin: 0;
}
.maniphest-task-summary td.maniphest-task-number {
font-weight: bold;
color: #333;
width: 50px;
text-align: right;
}
.maniphest-task-summary td.maniphest-task-status {
width: 60px;
text-align: center;
}
.maniphest-task-summary td.maniphest-task-owner {
width: 100px;
}
.maniphest-task-summary td.maniphest-task-name {
font-weight: bold;
white-space: normal;
overflow: hidden;
}
.maniphest-task-summary td.maniphest-task-projects {
width: 180px;
text-align: right;
white-space: normal;
}
.maniphest-task-summary td.maniphest-task-updated {
text-align: right;
width: 85px;
padding-right: 8px;
border-right-width: 1px;
border-right-style: solid;
border-right-color: #d5dadf;
}
.maniphest-task-summary .pri-bullet {
}
.maniphest-task-summary .pri-unbreak {
border-color: #ff0000;
background-color: #ff0000;
}
.maniphest-task-summary .pri-triage {
border-color: #ee00ee;
background-color: #ee00ee;
}
.maniphest-task-summary .pri-high {
border-color: #ff6622;
background-color: #ff6622;
}
.maniphest-task-summary .pri-normal {
border-color: #ffaa66;
background-color: #ffaa66;
}
.maniphest-task-summary .pri-low {
border-color: #eecc66;
background-color: #eecc66;
}
.maniphest-task-summary .pri-wish {
border-color: #0099ff;
background-color: #0099ff;
}
.maniphest-task-group-header {
font-size: 16px;
font-weight: bold;
color: #555;
padding: 5px 0;
+ margin-left: 20px;
}
.maniphest-total-result-count {
text-align: right;
padding-right: 2em;
font-size: 11px;
color: #666666;
}
.batch-editor-header {
font-size: 16px;
color: #555;
padding: 8px 0px;
font-weight: bold;
}
.maniphest-batch-editor {
margin: 20px;
}
.maniphest-batch-editor-layout {
width: 100%;
border-top: 1px solid #d5dadf;
background: #f4f5f8;
}
.maniphest-batch-editor-layout td {
padding: 10px 8px;
white-space: nowrap;
}
.maniphest-batch-editor-layout a.button,
.maniphest-batch-editor-layout button {
margin: 0px 4px;
}
.maniphest-batch-editor-layout .batch-select-submit-cell {
text-align: right;
}
#batch-select-status-cell {
text-align: right;
color: #666666;
font-size: 11px;
vertical-align: middle;
width: 100%;
}
td.maniphest-active-handle {
cursor: move;
background-image: url('/rsrc/image/grippy_texture.png');
background-position: 3px 0px;
background-repeat: repeat-y;
}
.maniphest-subpriority-target {
position: relative;
border: 1px dashed #aaaaaa;
background: #f9f9f9;
}
.maniphest-task-loading {
opacity: 0.5;
}
.maniphest-task-dragging {
position: relative;
opacity: 0.5;
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 15:09 (3 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1125827
Default Alt Text
(13 KB)

Event Timeline