1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Make bulk editor working set editable and more homogenous

Summary:
Ref T13025. See PHI50. Fixes T11286. Ref T10005. Begin modernizing the bulk editor.

For T10005 ("move the bulk editor to modern infrastructure"), rewrite the rendering of the editable set so that it is application-agnostic and can work with any kind of object.

For T11286 ("let users de-select items in the working set"), make the working set editable.

Test Plan:
{F5302158}

  - Deselected some objects, applied an edit, saw the edit apply to only selected objects.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13025, T11286, T10005

Differential Revision: https://secure.phabricator.com/D18805
This commit is contained in:
epriestley 2017-11-30 05:14:05 -08:00
parent 3e983b583d
commit ad659627b3
6 changed files with 175 additions and 29 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => 'fdb27ef9',
'core.pkg.css' => '5be8063f',
'core.pkg.js' => '4c79d74f',
'darkconsole.pkg.js' => '1f9a31bc',
'differential.pkg.css' => '45951e9e',
@ -135,14 +135,14 @@ return array(
'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => '08f4ccc3',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bf094950',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '73c5f5c4',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
'rsrc/css/phui/phui-action-list.css' => 'f7f61a34',
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c',
'rsrc/css/phui/phui-box.css' => '9f3745fb',
'rsrc/css/phui/phui-box.css' => '4bd6cdb9',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-cms.css' => '504b4b23',
'rsrc/css/phui/phui-comment-form.css' => 'ac68149f',
@ -523,6 +523,7 @@ return array(
'rsrc/js/core/phtize.js' => 'd254d646',
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d',
'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
'rsrc/js/phui/behavior-phui-selectable-list.js' => '464259a2',
'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b',
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
@ -673,6 +674,7 @@ return array(
'javelin-behavior-phui-dropdown-menu' => 'b95d6f7d',
'javelin-behavior-phui-file-upload' => 'b003d4fb',
'javelin-behavior-phui-hovercards' => 'bcaccd64',
'javelin-behavior-phui-selectable-list' => '464259a2',
'javelin-behavior-phui-submenu' => 'a6f7a73b',
'javelin-behavior-phui-tab-group' => '0a0b10e9',
'javelin-behavior-phuix-example' => '68af71ca',
@ -820,7 +822,7 @@ return array(
'phui-badge-view-css' => '22c0cf4f',
'phui-basic-nav-view-css' => '98c11ab3',
'phui-big-info-view-css' => 'acc3492c',
'phui-box-css' => '9f3745fb',
'phui-box-css' => '4bd6cdb9',
'phui-button-bar-css' => 'f1ff5494',
'phui-button-css' => '1863cc6e',
'phui-button-simple-css' => '8e1baf68',
@ -860,7 +862,7 @@ return array(
'phui-oi-color-css' => 'cd2b9b77',
'phui-oi-drag-ui-css' => '08f4ccc3',
'phui-oi-flush-ui-css' => '9d9685d6',
'phui-oi-list-view-css' => 'bf094950',
'phui-oi-list-view-css' => '73c5f5c4',
'phui-oi-simple-ui-css' => 'a8beebea',
'phui-pager-css' => 'edcbc226',
'phui-pinboard-view-css' => '2495140e',
@ -1226,6 +1228,11 @@ return array(
'javelin-behavior',
'javelin-dom',
),
'464259a2' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'469c0d9e' => array(
'javelin-behavior',
'javelin-dom',

View file

@ -89,12 +89,7 @@ final class ManiphestBatchEditController extends ManiphestController {
->setURI($job->getMonitorURI());
}
$handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
$list = new ManiphestTaskListView();
$list->setTasks($tasks);
$list->setUser($viewer);
$list->setHandles($handles);
$list = $this->newBulkObjectList($tasks);
$template = new AphrontTokenizerTemplateView();
$template = $template->render();
@ -142,21 +137,8 @@ final class ManiphestBatchEditController extends ManiphestController {
'statusMap' => ManiphestTaskStatus::getTaskStatusMap(),
));
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('board', $board_id)
->setID('maniphest-batch-edit-form');
foreach ($tasks as $task) {
$form->appendChild(
phutil_tag(
'input',
array(
'type' => 'hidden',
'name' => 'batch[]',
'value' => $task->getID(),
)));
}
$form = id(new PHUIFormLayoutView())
->setUser($viewer);
$form->appendChild(
phutil_tag(
@ -166,6 +148,7 @@ final class ManiphestBatchEditController extends ManiphestController {
'name' => 'actions',
'id' => 'batch-form-actions',
)));
$form->appendChild(
id(new PHUIFormInsetView())
->setTitle(pht('Actions'))
@ -210,17 +193,63 @@ final class ManiphestBatchEditController extends ManiphestController {
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$complete_form = phabricator_form(
$viewer,
array(
'action' => $request->getRequestURI(),
'method' => 'POST',
'id' => 'maniphest-batch-edit-form',
),
array(
phutil_tag(
'input',
array(
'type' => 'hidden',
'name' => 'board',
'value' => $board_id,
)),
$task_box,
$form_box,
));
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($complete_form);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
private function newBulkObjectList(array $objects) {
$viewer = $this->getViewer();
$objects = mpull($objects, null, 'getPHID');
$handles = $viewer->loadHandles(array_keys($objects));
$status_closed = PhabricatorObjectHandle::STATUS_CLOSED;
$list = id(new PHUIObjectItemListView())
->setViewer($viewer)
->setFlush(true);
foreach ($objects as $phid => $object) {
$handle = $handles[$phid];
$is_closed = ($handle->getStatus() === $status_closed);
$item = id(new PHUIObjectItemView())
->setHeader($handle->getFullName())
->setHref($handle->getURI())
->setDisabled($is_closed)
->setSelectable('batch[]', $object->getID(), true);
$list->addItem($item);
}
return $list;
}
}

View file

@ -29,6 +29,10 @@ final class PHUIObjectItemView extends AphrontTagView {
private $coverImage;
private $description;
private $selectableName;
private $selectableValue;
private $isSelected;
public function setDisabled($disabled) {
$this->disabled = $disabled;
return $this;
@ -160,6 +164,13 @@ final class PHUIObjectItemView extends AphrontTagView {
return $this;
}
public function setSelectable($name, $value, $is_selected) {
$this->selectableName = $name;
$this->selectableValue = $value;
$this->isSelected = $is_selected;
return $this;
}
public function setEpoch($epoch) {
$date = phabricator_datetime($epoch, $this->getUser());
$this->addIcon('none', $date);
@ -239,6 +250,8 @@ final class PHUIObjectItemView extends AphrontTagView {
}
protected function getTagAttributes() {
$sigils = array();
$item_classes = array();
$item_classes[] = 'phui-oi';
@ -286,6 +299,17 @@ final class PHUIObjectItemView extends AphrontTagView {
throw new Exception(pht('Invalid effect!'));
}
if ($this->isSelected) {
$item_classes[] = 'phui-oi-selected';
}
if ($this->selectableName !== null) {
$item_classes[] = 'phui-oi-selectable';
$sigils[] = 'phui-oi-selectable';
Javelin::initBehavior('phui-selectable-list');
}
if ($this->getGrippable()) {
$item_classes[] = 'phui-oi-grippable';
}
@ -300,6 +324,7 @@ final class PHUIObjectItemView extends AphrontTagView {
return array(
'class' => $item_classes,
'sigil' => $sigils,
);
}
@ -628,6 +653,24 @@ final class PHUIObjectItemView extends AphrontTagView {
$countdown);
}
if ($this->selectableName !== null) {
$checkbox = phutil_tag(
'input',
array(
'type' => 'checkbox',
'name' => $this->selectableName,
'value' => $this->selectableValue,
'checked' => ($this->isSelected ? 'checked' : null),
));
$column0 = phutil_tag(
'div',
array(
'class' => 'phui-oi-col0 phui-oi-checkbox',
),
$checkbox);
}
$column1 = phutil_tag(
'div',
array(

View file

@ -664,3 +664,22 @@ ul.phui-oi-list-view .phui-oi-selected
padding: 0 8px 8px;
text-align: left;
}
.phui-oi-col0.phui-oi-checkbox {
width: 28px;
text-align: center;
}
.phui-oi-selectable {
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
/* When the list selection state can be toggled on the client (as in the bulk
editor), keep the border color consistent to make the interaction feel more
robust. */
ul.phui-oi-list-view .phui-oi-selectable
.phui-oi-frame {
border-color: {$blueborder};
}

View file

@ -103,6 +103,10 @@ body.device .phui-box-blue-property.phui-object-box.phui-object-box-collapsed
padding: 2px 8px;
}
.phui-box-blue-property .phui-oi-list-view.phui-oi-list-flush {
padding: 0;
}
body .phui-box-blue-property.phui-object-box.phui-object-box-collapsed {
padding: 0;
}

View file

@ -0,0 +1,44 @@
/**
* @provides javelin-behavior-phui-selectable-list
* @requires javelin-behavior
* javelin-stratcom
* javelin-dom
*/
JX.behavior('phui-selectable-list', function() {
JX.Stratcom.listen('click', 'phui-oi-selectable', function(e) {
if (!e.isNormalClick()) {
return;
}
// If the user clicked a link, ignore it.
if (e.getNode('tag:a')) {
return;
}
var root = e.getNode('phui-oi-selectable');
// If the user did not click the checkbox, pretend they did. This makes
// the entire element a click target to make changing the selection set a
// bit easier.
if (!e.getNode('tag:input')) {
var checkbox = getCheckbox(root);
checkbox.checked = !checkbox.checked;
e.kill();
}
setTimeout(JX.bind(null, redraw, root), 0);
});
function getCheckbox(root) {
return JX.DOM.find(root, 'input');
}
function redraw(root) {
var checkbox = getCheckbox(root);
JX.DOM.alterClass(root, 'phui-oi-selected', !!checkbox.checked);
}
});