Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15414881
D16203.id38978.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D16203.id38978.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -11,7 +11,7 @@
'core.pkg.js' => 'f2139810',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '3e81ae60',
- 'differential.pkg.js' => '01a010d6',
+ 'differential.pkg.js' => '634399e9',
'diffusion.pkg.css' => '91c5d3a6',
'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a',
@@ -495,7 +495,7 @@
'rsrc/js/core/behavior-lightbox-attachments.js' => 'f8ba29d7',
'rsrc/js/core/behavior-line-linker.js' => '1499a8cb',
'rsrc/js/core/behavior-more.js' => 'a80d0378',
- 'rsrc/js/core/behavior-object-selector.js' => '9030ebef',
+ 'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f',
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '116cf19b',
@@ -658,7 +658,7 @@
'javelin-behavior-phabricator-line-linker' => '1499a8cb',
'javelin-behavior-phabricator-nav' => '56a1ca03',
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
- 'javelin-behavior-phabricator-object-selector' => '9030ebef',
+ 'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f',
'javelin-behavior-phabricator-oncopy' => '2926fff2',
'javelin-behavior-phabricator-remarkup-assist' => '116cf19b',
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
@@ -1608,12 +1608,6 @@
'javelin-dom',
'javelin-request',
),
- '9030ebef' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-request',
- 'javelin-util',
- ),
'9196fb06' => array(
'javelin-install',
'javelin-dom',
@@ -2036,6 +2030,12 @@
'df5e11d2' => array(
'javelin-install',
),
+ 'e0ec7f2f' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-request',
+ 'javelin-util',
+ ),
'e10f8e18' => array(
'javelin-behavior',
'javelin-dom',
diff --git a/src/applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php b/src/applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php
--- a/src/applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php
+++ b/src/applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php
@@ -53,16 +53,11 @@
return false;
}
- public function willUpdateRelationships($object, array $add, array $rem) {
-
- // TODO: Communicate this in the UI before users hit this error.
- if (count($add) > 1) {
- throw new Exception(
- pht(
- 'A task can only be closed as a duplicate of exactly one other '.
- 'task.'));
- }
+ public function getMaximumSelectionSize() {
+ return 1;
+ }
+ public function willUpdateRelationships($object, array $add, array $rem) {
$task = head($add);
return $this->newMergeIntoTransactions($task);
}
diff --git a/src/applications/search/controller/PhabricatorSearchRelationshipController.php b/src/applications/search/controller/PhabricatorSearchRelationshipController.php
--- a/src/applications/search/controller/PhabricatorSearchRelationshipController.php
+++ b/src/applications/search/controller/PhabricatorSearchRelationshipController.php
@@ -39,11 +39,23 @@
$done_uri = $src_handle->getURI();
$initial_phids = $dst_phids;
+ $maximum = $relationship->getMaximumSelectionSize();
+
if ($request->isFormPost()) {
$phids = explode(';', $request->getStr('phids'));
$phids = array_filter($phids);
$phids = array_values($phids);
+ // The UI normally enforces this with Javascript, so this is just a
+ // sanity check and does not need to be particularly user-friendly.
+ if ($maximum && (count($phids) > $maximum)) {
+ throw new Exception(
+ pht(
+ 'Too many relationships (%s, of type "%s").',
+ phutil_count($phids),
+ $relationship->getRelationshipConstant()));
+ }
+
$initial_phids = $request->getStrList('initialPHIDs');
// Apply the changes as adds and removes relative to the original state
@@ -175,6 +187,7 @@
->setHeader($dialog_header)
->setButtonText($dialog_button)
->setInstructions($dialog_instructions)
+ ->setMaximumSelectionSize($maximum)
->buildDialog();
}
diff --git a/src/applications/search/relationship/PhabricatorObjectRelationship.php b/src/applications/search/relationship/PhabricatorObjectRelationship.php
--- a/src/applications/search/relationship/PhabricatorObjectRelationship.php
+++ b/src/applications/search/relationship/PhabricatorObjectRelationship.php
@@ -104,6 +104,10 @@
return "/search/rel/{$type}/{$phid}/";
}
+ public function getMaximumSelectionSize() {
+ return null;
+ }
+
public function canUndoRelationship() {
return true;
}
diff --git a/src/view/control/PhabricatorObjectSelectorDialog.php b/src/view/control/PhabricatorObjectSelectorDialog.php
--- a/src/view/control/PhabricatorObjectSelectorDialog.php
+++ b/src/view/control/PhabricatorObjectSelectorDialog.php
@@ -11,6 +11,7 @@
private $selectedFilter;
private $excluded;
private $initialPHIDs;
+ private $maximumSelectionSize;
private $title;
private $header;
@@ -87,6 +88,15 @@
return $this->initialPHIDs;
}
+ public function setMaximumSelectionSize($maximum_selection_size) {
+ $this->maximumSelectionSize = $maximum_selection_size;
+ return $this;
+ }
+
+ public function getMaximumSelectionSize() {
+ return $this->maximumSelectionSize;
+ }
+
public function buildDialog() {
$user = $this->user;
@@ -190,6 +200,8 @@
$dialog->addHiddenInput('initialPHIDs', $initial_phids);
}
+ $maximum = $this->getMaximumSelectionSize();
+
Javelin::initBehavior(
'phabricator-object-selector',
array(
@@ -202,6 +214,7 @@
'exclude' => $this->excluded,
'uri' => $this->searchURI,
'handles' => $handle_views,
+ 'maximum' => $maximum,
));
$dialog->setResizeX(true);
diff --git a/webroot/rsrc/js/core/behavior-object-selector.js b/webroot/rsrc/js/core/behavior-object-selector.js
--- a/webroot/rsrc/js/core/behavior-object-selector.js
+++ b/webroot/rsrc/js/core/behavior-object-selector.js
@@ -10,11 +10,13 @@
var n = 0;
var phids = {};
+ var display = [];
+
var handles = config.handles;
for (var k in handles) {
phids[k] = true;
}
- var button_list = {};
+
var query_timer = null;
var query_delay = 50;
@@ -41,37 +43,82 @@
return;
}
- var display = [];
- button_list = {};
+ display = [];
for (var k in r) {
handles[r[k].phid] = r[k];
- display.push(renderHandle(r[k], true));
+ display.push({phid: r[k].phid});
}
- if (!display.length) {
- display = renderNote('No results.');
- }
-
- JX.DOM.setContent(JX.$(config.results), display);
+ redrawList(true);
}
function redrawAttached() {
- var display = [];
+ var attached = [];
for (var k in phids) {
- display.push(renderHandle(handles[k], false));
+ attached.push(renderHandle(handles[k], false).item);
}
- if (!display.length) {
- display = renderNote('Nothing attached.');
+ if (!attached.length) {
+ attached = renderNote('Nothing attached.');
}
- JX.DOM.setContent(JX.$(config.current), display);
+ JX.DOM.setContent(JX.$(config.current), attached);
phid_input.value = JX.keys(phids).join(';');
}
- function renderHandle(h, attach) {
+ function redrawList(rebuild) {
+ var ii;
+ var content;
+
+ if (rebuild) {
+ if (display.length) {
+ var handle;
+
+ content = [];
+ for (ii = 0; ii < display.length; ii++) {
+ handle = handles[display[ii].phid];
+
+ display[ii].node = renderHandle(handle, true);
+ content.push(display[ii].node.item);
+ }
+ } else {
+ content = renderNote('No results.');
+ }
+
+ JX.DOM.setContent(JX.$(config.results), content);
+ }
+
+ var phid;
+ var is_disabled;
+ var button;
+
+ var at_maximum = !canSelectMore();
+
+ for (ii = 0; ii < display.length; ii++) {
+ phid = display[ii].phid;
+
+ is_disabled = false;
+
+ // If this object is already selected, you can not select it again.
+ if (phids.hasOwnProperty(phid)) {
+ is_disabled = true;
+ }
+
+ // If the maximum number of objects are already selected, you can
+ // not select more.
+ if (at_maximum) {
+ is_disabled = true;
+ }
+
+ button = display[ii].node.button;
+ JX.DOM.alterClass(button, 'disabled', is_disabled);
+ button.disabled = is_disabled;
+ }
+
+ }
+ function renderHandle(h, attach) {
var some_icon = JX.$N(
'span',
{className: 'phui-icon-view phui-font-fa ' +
@@ -111,15 +158,10 @@
meta: {handle: h, table:table}},
cells));
- if (attach) {
- button_list[h.phid] = select_object_button;
- if (h.phid in phids) {
- JX.DOM.alterClass(select_object_button, 'disabled', true);
- select_object_button.disabled = true;
- }
- }
-
- return table;
+ return {
+ item: table,
+ button: select_object_button
+ };
}
function renderNote(note) {
@@ -138,6 +180,18 @@
.send();
}
+ function canSelectMore() {
+ if (!config.maximum) {
+ return true;
+ }
+
+ if (JX.keys(phids).length < config.maximum) {
+ return true;
+ }
+
+ return false;
+ }
+
JX.DOM.listen(
JX.$(config.results),
'click',
@@ -151,10 +205,13 @@
return;
}
+ if (!canSelectMore()) {
+ return;
+ }
+
phids[phid] = true;
- JX.DOM.alterClass(button_list[phid], 'disabled', true);
- button_list[phid].disabled = true;
+ redrawList(false);
redrawAttached();
});
@@ -170,13 +227,7 @@
delete phids[phid];
- // NOTE: We may not have a button in the button list, if this result is
- // not visible in the current search results.
- if (button_list[phid]) {
- JX.DOM.alterClass(button_list[phid], 'disabled', false);
- button_list[phid].disabled = false;
- }
-
+ redrawList(false);
redrawAttached();
});
@@ -205,6 +256,7 @@
});
sendQuery();
- redrawAttached();
+ redrawList(true);
+ redrawAttached();
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 21, 2:56 AM (7 h, 7 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7714846
Default Alt Text
D16203.id38978.diff (10 KB)
Attached To
Mode
D16203: When using the "Close as Duplicate" relationship action, limit the UI to 1 task
Attached
Detach File
Event Timeline
Log In to Comment