1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-30 17:30:59 +01:00

Allow Maniphest tasks to be edited from the list view

Summary:
Fixes T1945. Ref T2947. At various times, installs (Disqus, Dropbox, etc.) have asked for a way to edit tasks more quickly. Provide edit-from-lists.

{F44700}

{F44701}

The one rough edge on this is that if you change the task priority we update it inline but don't move it. It's probably infeasible to actually move it, but maybe we could give it some sort of visual style to indicate that it's dirty.

Test Plan: Edited tasks normally and via this action thing.

Reviewers: chad, btrahan

Reviewed By: chad

CC: tido, deuresti, ahoffer, aran

Maniphest Tasks: T1945, T2947

Differential Revision: https://secure.phabricator.com/D6086
This commit is contained in:
epriestley 2013-05-30 18:55:25 -07:00
parent fb765b8c93
commit 282b3f7988
7 changed files with 148 additions and 47 deletions

View file

@ -1780,6 +1780,21 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/maniphest/behavior-task-preview.js', 'disk' => '/rsrc/js/application/maniphest/behavior-task-preview.js',
), ),
'javelin-behavior-maniphest-list-editor' =>
array(
'uri' => '/res/170f8457/rsrc/js/application/maniphest/behavior-list-edit.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-stratcom',
3 => 'javelin-workflow',
4 => 'javelin-fx',
5 => 'javelin-util',
),
'disk' => '/rsrc/js/application/maniphest/behavior-list-edit.js',
),
'javelin-behavior-maniphest-subpriority-editor' => 'javelin-behavior-maniphest-subpriority-editor' =>
array( array(
'uri' => '/res/21b73c2a/rsrc/js/application/maniphest/behavior-subpriorityeditor.js', 'uri' => '/res/21b73c2a/rsrc/js/application/maniphest/behavior-subpriorityeditor.js',
@ -2737,7 +2752,7 @@ celerity_register_resource_map(array(
), ),
'javelin-workflow' => 'javelin-workflow' =>
array( array(
'uri' => '/res/8274d65f/rsrc/externals/javelin/lib/Workflow.js', 'uri' => '/res/7626494b/rsrc/externals/javelin/lib/Workflow.js',
'type' => 'js', 'type' => 'js',
'requires' => 'requires' =>
array( array(
@ -4156,7 +4171,7 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/96909266/diffusion.pkg.js', 'uri' => '/res/pkg/96909266/diffusion.pkg.js',
'type' => 'js', 'type' => 'js',
), ),
'c1359b5d' => 'a9f14d76' =>
array( array(
'name' => 'javelin.pkg.js', 'name' => 'javelin.pkg.js',
'symbols' => 'symbols' =>
@ -4182,7 +4197,7 @@ celerity_register_resource_map(array(
18 => 'javelin-tokenizer', 18 => 'javelin-tokenizer',
19 => 'javelin-history', 19 => 'javelin-history',
), ),
'uri' => '/res/pkg/c1359b5d/javelin.pkg.js', 'uri' => '/res/pkg/a9f14d76/javelin.pkg.js',
'type' => 'js', 'type' => 'js',
), ),
'6b1fccc6' => '6b1fccc6' =>
@ -4242,7 +4257,7 @@ celerity_register_resource_map(array(
'global-drag-and-drop-css' => '1b14560c', 'global-drag-and-drop-css' => '1b14560c',
'inline-comment-summary-css' => 'dd27a69b', 'inline-comment-summary-css' => 'dd27a69b',
'javelin-aphlict' => '98f60e3f', 'javelin-aphlict' => '98f60e3f',
'javelin-behavior' => 'c1359b5d', 'javelin-behavior' => 'a9f14d76',
'javelin-behavior-aphlict-dropdown' => '98f60e3f', 'javelin-behavior-aphlict-dropdown' => '98f60e3f',
'javelin-behavior-aphlict-listen' => '98f60e3f', 'javelin-behavior-aphlict-listen' => '98f60e3f',
'javelin-behavior-aphront-basic-tokenizer' => '98f60e3f', 'javelin-behavior-aphront-basic-tokenizer' => '98f60e3f',
@ -4294,25 +4309,25 @@ celerity_register_resource_map(array(
'javelin-behavior-repository-crossreference' => '9488bb69', 'javelin-behavior-repository-crossreference' => '9488bb69',
'javelin-behavior-toggle-class' => '98f60e3f', 'javelin-behavior-toggle-class' => '98f60e3f',
'javelin-behavior-workflow' => '98f60e3f', 'javelin-behavior-workflow' => '98f60e3f',
'javelin-dom' => 'c1359b5d', 'javelin-dom' => 'a9f14d76',
'javelin-event' => 'c1359b5d', 'javelin-event' => 'a9f14d76',
'javelin-history' => 'c1359b5d', 'javelin-history' => 'a9f14d76',
'javelin-install' => 'c1359b5d', 'javelin-install' => 'a9f14d76',
'javelin-json' => 'c1359b5d', 'javelin-json' => 'a9f14d76',
'javelin-mask' => 'c1359b5d', 'javelin-mask' => 'a9f14d76',
'javelin-request' => 'c1359b5d', 'javelin-request' => 'a9f14d76',
'javelin-resource' => 'c1359b5d', 'javelin-resource' => 'a9f14d76',
'javelin-stratcom' => 'c1359b5d', 'javelin-stratcom' => 'a9f14d76',
'javelin-tokenizer' => 'c1359b5d', 'javelin-tokenizer' => 'a9f14d76',
'javelin-typeahead' => 'c1359b5d', 'javelin-typeahead' => 'a9f14d76',
'javelin-typeahead-normalizer' => 'c1359b5d', 'javelin-typeahead-normalizer' => 'a9f14d76',
'javelin-typeahead-ondemand-source' => 'c1359b5d', 'javelin-typeahead-ondemand-source' => 'a9f14d76',
'javelin-typeahead-preloaded-source' => 'c1359b5d', 'javelin-typeahead-preloaded-source' => 'a9f14d76',
'javelin-typeahead-source' => 'c1359b5d', 'javelin-typeahead-source' => 'a9f14d76',
'javelin-uri' => 'c1359b5d', 'javelin-uri' => 'a9f14d76',
'javelin-util' => 'c1359b5d', 'javelin-util' => 'a9f14d76',
'javelin-vector' => 'c1359b5d', 'javelin-vector' => 'a9f14d76',
'javelin-workflow' => 'c1359b5d', 'javelin-workflow' => 'a9f14d76',
'lightbox-attachment-css' => '1b14560c', 'lightbox-attachment-css' => '1b14560c',
'maniphest-task-summary-css' => '6b1fccc6', 'maniphest-task-summary-css' => '6b1fccc6',
'maniphest-transaction-detail-css' => '6b1fccc6', 'maniphest-transaction-detail-css' => '6b1fccc6',

View file

@ -84,4 +84,27 @@ abstract class ManiphestController extends PhabricatorController {
return $this->defaultQuery; return $this->defaultQuery;
} }
protected function renderSingleTask(ManiphestTask $task) {
$user = $this->getRequest()->getUser();
$phids = $task->getProjectPHIDs();
if ($task->getOwnerPHID()) {
$phids[] = $task->getOwnerPHID();
}
$handles = id(new PhabricatorObjectHandleData($phids))
->setViewer($user)
->loadHandles();
$view = id(new ManiphestTaskListView())
->setUser($user)
->setShowSubpriorityControls(true)
->setShowBatchControls(true)
->setHandles($handles)
->setTasks(array($task));
return $view;
}
} }

View file

@ -51,25 +51,9 @@ final class ManiphestSubpriorityController extends ManiphestController {
$task->setSubpriority($new_sub); $task->setSubpriority($new_sub);
$task->save(); $task->save();
$phids = $task->getProjectPHIDs();
if ($task->getOwnerPHID()) {
$phids[] = $task->getOwnerPHID();
}
$handles = id(new PhabricatorObjectHandleData($phids))
->setViewer($user)
->loadHandles();
$view = id(new ManiphestTaskListView())
->setUser($user)
->setShowSubpriorityControls(true)
->setShowBatchControls(true)
->setHandles($handles)
->setTasks(array($task));
return id(new AphrontAjaxResponse())->setContent( return id(new AphrontAjaxResponse())->setContent(
array( array(
'tasks' => $view, 'tasks' => $this->renderSingleTask($task),
)); ));
} }

View file

@ -242,6 +242,13 @@ final class ManiphestTaskEditController extends ManiphestController {
$workflow = $parent_task->getID(); $workflow = $parent_task->getID();
} }
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())->setContent(
array(
'tasks' => $this->renderSingleTask($task),
));
}
$redirect_uri = '/T'.$task->getID(); $redirect_uri = '/T'.$task->getID();
if ($workflow) { if ($workflow) {
@ -354,12 +361,15 @@ final class ManiphestTaskEditController extends ManiphestController {
$project_tokenizer_id = celerity_generate_unique_node_id(); $project_tokenizer_id = celerity_generate_unique_node_id();
$form = new AphrontFormView(); if ($request->isAjax()) {
$form->setFlexible(true); $form = new AphrontFormLayoutView();
$form } else {
->setUser($user) $form = new AphrontFormView();
->setAction($request->getRequestURI()->getPath()) $form->setFlexible(true);
->addHiddenInput('template', $template_id); $form
->setUser($user)
->addHiddenInput('template', $template_id);
}
if ($parent_task) { if ($parent_task) {
$form $form
@ -485,6 +495,22 @@ final class ManiphestTaskEditController extends ManiphestController {
$form $form
->appendChild($description_control); ->appendChild($description_control);
if ($request->isAjax()) {
$dialog = id(new AphrontDialogView())
->setUser($user)
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle($header_name)
->appendChild(
array(
$error_view,
$form,
))
->addCancelButton($cancel_uri)
->addSubmitButton($button_name);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$form $form
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())

View file

@ -49,6 +49,10 @@ final class ManiphestTaskListView extends ManiphestView {
ManiphestTaskPriority::PRIORITY_WISH => 'sky', ManiphestTaskPriority::PRIORITY_WISH => 'sky',
); );
if ($this->showBatchControls) {
Javelin::initBehavior('maniphest-list-editor');
}
foreach ($this->tasks as $task) { foreach ($this->tasks as $task) {
$item = new PhabricatorObjectItemView(); $item = new PhabricatorObjectItemView();
$item->setObjectName('T'.$task->getID()); $item->setObjectName('T'.$task->getID());
@ -97,6 +101,14 @@ final class ManiphestTaskListView extends ManiphestView {
'taskID' => $task->getID(), 'taskID' => $task->getID(),
)); ));
if ($this->showBatchControls) {
$item->addAction(
id(new PhabricatorMenuItemView())
->setIcon('edit')
->addSigil('maniphest-edit-task')
->setHref('/maniphest/task/edit/'.$task->getID().'/'));
}
$list->addItem($item); $list->addItem($item);
} }

View file

@ -144,7 +144,13 @@ JX.install('Workflow', {
var d = JX.Vector.getDim(this._root); var d = JX.Vector.getDim(this._root);
var v = JX.Vector.getViewport(); var v = JX.Vector.getViewport();
var s = JX.Vector.getScroll(); var s = JX.Vector.getScroll();
JX.$V((v.x - d.x) / 2, s.y + 100).setPos(this._root);
// Normally, we position dialogs 100px from the top of the screen.
// Use more space if the dialog is large (at least roughly the size
// of the viewport).
var offset = Math.min(Math.max(20, (v.y - d.y) / 2), 100);
JX.$V((v.x - d.x) / 2, s.y + offset).setPos(this._root);
try { try {
JX.DOM.focus(JX.DOM.find(this._root, 'button', '__default__')); JX.DOM.focus(JX.DOM.find(this._root, 'button', '__default__'));
var inputs = JX.DOM.scry(this._root, 'input') var inputs = JX.DOM.scry(this._root, 'input')
@ -163,6 +169,12 @@ JX.install('Workflow', {
} }
target && JX.DOM.focus(target); target && JX.DOM.focus(target);
} catch (_ignored) {} } catch (_ignored) {}
// The `focus()` call may have scrolled the window. Scroll it back to
// where it was before -- we want to focus the control, but not adjust
// the scroll position.
window.scrollTo(s.x, s.y);
} else if (this.getHandler()) { } else if (this.getHandler()) {
this.getHandler()(r); this.getHandler()(r);
this._pop(); this._pop();

View file

@ -0,0 +1,29 @@
/**
* @provides javelin-behavior-maniphest-list-editor
* @requires javelin-behavior
* javelin-dom
* javelin-stratcom
* javelin-workflow
* javelin-fx
* javelin-util
*/
JX.behavior('maniphest-list-editor', function(config) {
var onedit = function(task, r) {
var nodes = JX.$H(r.tasks).getFragment().firstChild;
var new_task = JX.DOM.find(nodes, 'li', 'maniphest-task');
JX.DOM.replace(task, new_task);
new JX.FX(new_task).setDuration(500).start({opacity: [0, 1]});
};
JX.Stratcom.listen('click', 'maniphest-edit-task', function(e) {
e.kill();
var task = e.getNode('maniphest-task');
JX.Workflow.newFromLink(e.getNode('maniphest-edit-task'))
.setHandler(JX.bind(null, onedit, task))
.start();
});
});