From 1644b45050579d323d5337f452e6f564b676b1cf Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 18 May 2017 21:50:27 -0700 Subject: [PATCH 01/61] Disperse task subpriorities in blocks Summary: Ref T7664. The current algorithm for moving task subpriorities can end up stuck in a real sticky swamp in some unusual situations. Instead, use an algorithm which works like this: - When we notice two tasks are too close together, look at the area around those tasks (just a few paces). - If things look pretty empty, we can just spread the tasks out a little bit. - But, if things are still real crowded, take another look further. - Keep doing that until we're looking at a real nice big spot which doesn't have too many tasks in it in total, even if they're all in one place right now. - Then, move 'em out! Also: - Just swallow our pride and do the gross `INSERT INTO ... "", "", "", "", "", "", ... ON DUPLICATE KEY UPDATE` to bulk update. - Fix an issue where a single move could cause two different subpriority recalculations. Test Plan: - Changed `ManiphesTaskTestCase->testTaskAdjacentBlocks()` to insert 1,000 tasks with identical subpriorities, saw them spread out in 11 queries instead of >1,000. - Dragged tons of tasks around on workboards. - Ran unit tests. Reviewers: chad Reviewed By: chad Maniphest Tasks: T7664 Differential Revision: https://secure.phabricator.com/D17959 --- .../__tests__/ManiphestTaskTestCase.php | 28 +++ .../editor/ManiphestTransactionEditor.php | 230 +++++++++++++----- .../maniphest/query/ManiphestTaskQuery.php | 22 -- .../PhabricatorProjectMoveController.php | 3 + 4 files changed, 195 insertions(+), 88 deletions(-) diff --git a/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php b/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php index 5f5c198a84..1e571190d7 100644 --- a/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php +++ b/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php @@ -125,6 +125,34 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase { 9, count($subpri), pht('Expected subpriorities to be distributed.')); + + // Move task 9 to the end. + $this->moveTask($viewer, $t[9], $t[1], true); + $tasks = $this->loadTasks($viewer, $auto_base); + $this->assertEqual( + array(8, 7, 6, 5, 4, 3, 2, 1, 9), + array_keys($tasks)); + + // Move task 3 to the beginning. + $this->moveTask($viewer, $t[3], $t[8], false); + $tasks = $this->loadTasks($viewer, $auto_base); + $this->assertEqual( + array(3, 8, 7, 6, 5, 4, 2, 1, 9), + array_keys($tasks)); + + // Move task 3 to the end. + $this->moveTask($viewer, $t[3], $t[9], true); + $tasks = $this->loadTasks($viewer, $auto_base); + $this->assertEqual( + array(8, 7, 6, 5, 4, 2, 1, 9, 3), + array_keys($tasks)); + + // Move task 5 to before task 4 (this is its current position). + $this->moveTask($viewer, $t[5], $t[4], false); + $tasks = $this->loadTasks($viewer, $auto_base); + $this->assertEqual( + array(8, 7, 6, 5, 4, 2, 1, 9, 3), + array_keys($tasks)); } private function newTask(PhabricatorUser $viewer, $title) { diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php index c9e17cd4de..1b780549dc 100644 --- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php +++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php @@ -384,8 +384,7 @@ final class ManiphestTransactionEditor */ public static function getAdjacentSubpriority( ManiphestTask $dst, - $is_after, - $allow_recursion = true) { + $is_after) { $query = id(new ManiphestTaskQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) @@ -407,76 +406,25 @@ final class ManiphestTransactionEditor // If we find an adjacent task, we average the two subpriorities and // return the result. if ($adjacent) { - $epsilon = 0.01; + $epsilon = 1.0; // If the adjacent task has a subpriority that is identical or very - // close to the task we're looking at, we're going to move it and all - // tasks with the same subpriority a little farther down the subpriority - // scale. - if ($allow_recursion && - (abs($adjacent->getSubpriority() - $base) < $epsilon)) { - $conn_w = $adjacent->establishConnection('w'); + // close to the task we're looking at, we're going to spread out all + // the nearby tasks. - $min = ($adjacent->getSubpriority() - ($epsilon)); - $max = ($adjacent->getSubpriority() + ($epsilon)); - - // Get all of the tasks with the similar subpriorities to the adjacent - // task, including the adjacent task itself. - $query = id(new ManiphestTaskQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withPriorities(array($adjacent->getPriority())) - ->withSubpriorityBetween($min, $max); - - if (!$is_after) { - $query->setOrderVector(array('-priority', '-subpriority', '-id')); + $adjacent_sub = $adjacent->getSubpriority(); + if ((abs($adjacent_sub - $base) < $epsilon)) { + $base = self::disperseBlock( + $dst, + $epsilon * 2); + if ($is_after) { + $sub = $base - $epsilon; } else { - $query->setOrderVector(array('priority', 'subpriority', 'id')); - } - - $shift_all = $query->execute(); - $shift_last = last($shift_all); - - // Select the most extreme subpriority in the result set as the - // base value. - $shift_base = head($shift_all)->getSubpriority(); - - // Find the subpriority before or after the task at the end of the - // block. - list($shift_pri, $shift_sub) = self::getAdjacentSubpriority( - $shift_last, - $is_after, - $allow_recursion = false); - - $delta = ($shift_sub - $shift_base); - $count = count($shift_all); - - $shift = array(); - $cursor = 1; - foreach ($shift_all as $shift_task) { - $shift_target = $shift_base + (($cursor / $count) * $delta); - $cursor++; - - queryfx( - $conn_w, - 'UPDATE %T SET subpriority = %f WHERE id = %d', - $adjacent->getTableName(), - $shift_target, - $shift_task->getID()); - - // If we're shifting the adjacent task, update it. - if ($shift_task->getID() == $adjacent->getID()) { - $adjacent->setSubpriority($shift_target); - } - - // If we're shifting the original target task, update the base - // subpriority. - if ($shift_task->getID() == $dst->getID()) { - $base = $shift_target; - } + $sub = $base + $epsilon; } + } else { + $sub = ($adjacent_sub + $base) / 2; } - - $sub = ($adjacent->getSubpriority() + $base) / 2; } else { // Otherwise, we take a step away from the target's subpriority and // use that. @@ -490,6 +438,156 @@ final class ManiphestTransactionEditor return array($dst->getPriority(), $sub); } + /** + * Distribute a cluster of tasks with similar subpriorities. + */ + private static function disperseBlock( + ManiphestTask $task, + $spacing) { + + $conn = $task->establishConnection('w'); + + // Find a block of subpriority space which is, on average, sparse enough + // to hold all the tasks that are inside it with a reasonable level of + // separation between them. + + // We'll start by looking near the target task for a range of numbers + // which has more space available than tasks. For example, if the target + // task has subpriority 33 and we want to separate each task by at least 1, + // we might start by looking in the range [23, 43]. + + // If we find fewer than 20 tasks there, we have room to reassign them + // with the desired level of separation. We space them out, then we're + // done. + + // However: if we find more than 20 tasks, we don't have enough room to + // distribute them. We'll widen our search and look in a bigger range, + // maybe [13, 53]. This range has more space, so if we find fewer than + // 40 tasks in this range we can spread them out. If we still find too + // many tasks, we keep widening the search. + + $base = $task->getSubpriority(); + + $scale = 4.0; + while (true) { + $range = ($spacing * $scale) / 2.0; + $min = ($base - $range); + $max = ($base + $range); + + $result = queryfx_one( + $conn, + 'SELECT COUNT(*) N FROM %T WHERE priority = %d AND + subpriority BETWEEN %f AND %f', + $task->getTableName(), + $task->getPriority(), + $min, + $max); + + $count = $result['N']; + if ($count < $scale) { + // We have found a block which we can make sparse enough, so bail and + // continue below with our selection. + break; + } + + // This block had too many tasks for its size, so try again with a + // bigger block. + $scale *= 2.0; + } + + $rows = queryfx_all( + $conn, + 'SELECT id FROM %T WHERE priority = %d AND + subpriority BETWEEN %f AND %f + ORDER BY priority, subpriority, id', + $task->getTableName(), + $task->getPriority(), + $min, + $max); + + $task_id = $task->getID(); + $result = null; + + // NOTE: In strict mode (which we encourage enabling) we can't structure + // this bulk update as an "INSERT ... ON DUPLICATE KEY UPDATE" unless we + // provide default values for ALL of the columns that don't have defaults. + + // This is gross, but we may be moving enough rows that individual + // queries are unreasonably slow. An alternate construction which might + // be worth evaluating is to use "CASE". Another approach is to disable + // strict mode for this query. + + $extra_columns = array( + 'phid' => '""', + 'authorPHID' => '""', + 'status' => '""', + 'priority' => 0, + 'title' => '""', + 'originalTitle' => '""', + 'description' => '""', + 'dateCreated' => 0, + 'dateModified' => 0, + 'mailKey' => '""', + 'viewPolicy' => '""', + 'editPolicy' => '""', + 'ownerOrdering' => '""', + 'spacePHID' => '""', + 'bridgedObjectPHID' => '""', + 'properties' => '""', + 'points' => 0, + 'subtype' => '""', + ); + + $defaults = implode(', ', $extra_columns); + + $sql = array(); + $offset = 0; + + // Often, we'll have more room than we need in the range. Distribute the + // tasks evenly over the whole range so that we're less likely to end up + // with tasks spaced exactly the minimum distance apart, which may + // get shifted again later. We have one fewer space to distribute than we + // have tasks. + $divisor = (double)(count($rows) - 1.0); + if ($divisor > 0) { + $available_distance = (($max - $min) / $divisor); + } else { + $available_distance = 0.0; + } + + foreach ($rows as $row) { + $subpriority = $min + ($offset * $available_distance); + + // If this is the task that we're spreading out relative to, keep track + // of where it is ending up so we can return the new subpriority. + $id = $row['id']; + if ($id == $task_id) { + $result = $subpriority; + } + + $sql[] = qsprintf( + $conn, + '(%d, %Q, %f)', + $id, + $defaults, + $subpriority); + + $offset++; + } + + foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { + queryfx( + $conn, + 'INSERT INTO %T (id, %Q, subpriority) VALUES %Q + ON DUPLICATE KEY UPDATE subpriority = VALUES(subpriority)', + $task->getTableName(), + implode(', ', array_keys($extra_columns)), + $chunk); + } + + return $result; + } + protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index 4cf47f40cb..704a67f548 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -17,8 +17,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { private $dateCreatedBefore; private $dateModifiedAfter; private $dateModifiedBefore; - private $subpriorityMin; - private $subpriorityMax; private $bridgedObjectPHIDs; private $hasOpenParents; private $hasOpenSubtasks; @@ -112,12 +110,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { return $this; } - public function withSubpriorityBetween($min, $max) { - $this->subpriorityMin = $min; - $this->subpriorityMax = $max; - return $this; - } - public function withSubscribers(array $subscribers) { $this->subscriberPHIDs = $subscribers; return $this; @@ -408,20 +400,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { $this->subpriorities); } - if ($this->subpriorityMin !== null) { - $where[] = qsprintf( - $conn, - 'task.subpriority >= %f', - $this->subpriorityMin); - } - - if ($this->subpriorityMax !== null) { - $where[] = qsprintf( - $conn, - 'task.subpriority <= %f', - $this->subpriorityMax); - } - if ($this->bridgedObjectPHIDs !== null) { $where[] = qsprintf( $conn, diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php index 68915664cb..801acbb90e 100644 --- a/src/applications/project/controller/PhabricatorProjectMoveController.php +++ b/src/applications/project/controller/PhabricatorProjectMoveController.php @@ -148,6 +148,9 @@ final class PhabricatorProjectMoveController list($pri, $sub) = ManiphestTransactionEditor::getAdjacentSubpriority( $task, $is_after); + + // If we find a priority on the first try, don't keep going. + break; } $xactions = array(); From 5f49f9c793e370157559f0c5c78f716f01c8e58b Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 19 May 2017 21:40:08 -0700 Subject: [PATCH 02/61] Add sound to logged out Conpherence Summary: Fixes T12735. Adds a sound if the user is logged out, skips checking a setting. Test Plan: set participants to null and verify sound plays, no exceptions1111 Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12735 Differential Revision: https://secure.phabricator.com/D17973 --- .../controller/ConpherenceUpdateController.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/applications/conpherence/controller/ConpherenceUpdateController.php b/src/applications/conpherence/controller/ConpherenceUpdateController.php index a814c64452..a792a5a4d4 100644 --- a/src/applications/conpherence/controller/ConpherenceUpdateController.php +++ b/src/applications/conpherence/controller/ConpherenceUpdateController.php @@ -369,9 +369,17 @@ final class ConpherenceUpdateController ->setViewer($user); $dropdown_query->execute(); - $sounds = $this->getSoundForParticipant($user, $participant); - $receive_sound = $sounds[ConpherenceRoomSettings::SOUND_RECEIVE]; - $mention_sound = $sounds[ConpherenceRoomSettings::SOUND_MENTION]; + $map = ConpherenceRoomSettings::getSoundMap(); + $default_receive = ConpherenceRoomSettings::DEFAULT_RECEIVE_SOUND; + $receive_sound = $map[$default_receive]['rsrc']; + $mention_sound = null; + + // Get the user's defaults if logged in + if ($participant) { + $sounds = $this->getSoundForParticipant($user, $participant); + $receive_sound = $sounds[ConpherenceRoomSettings::SOUND_RECEIVE]; + $mention_sound = $sounds[ConpherenceRoomSettings::SOUND_MENTION]; + } $content = array( 'non_update' => $non_update, From 6945e80feed50c4c584e383b17c0684a9840cf93 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 04:27:21 -0700 Subject: [PATCH 03/61] For the diff banner, detect the current changeset better Summary: Ref T12733. Currently, we detect the changeset which is in the middle of the screen as the current changeset. This doesn't always get us the most intuitive changeset, particularly after a navigation from the scroll objective list: when you jump to changeset "X", you'd tend to expect "X" to be shown in the header, but the //next// changeset may be shown if "X" is too short. Instead, select the changeset near the top of the screen (spanning an invisible line slightly below the banner). Test Plan: Scrolled and jumped through a document with long and short changesets, saw a more intuitive changeset selected by the banner. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17976 --- resources/celerity/map.php | 14 +++++++------- .../js/application/diff/DiffChangesetList.js | 16 ++++++++++------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e50d8bbd1a..019856296b 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => 'e822b496', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4d7dd14e', - 'differential.pkg.js' => '68a4fa60', + 'differential.pkg.js' => '6d05ad4c', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -391,7 +391,7 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', - 'rsrc/js/application/diff/DiffChangesetList.js' => '5c68c40c', + 'rsrc/js/application/diff/DiffChangesetList.js' => '541206ba', 'rsrc/js/application/diff/DiffInline.js' => '77e14b60', 'rsrc/js/application/diff/ScrollObjective.js' => '0eee7a00', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '1ca4d9db', @@ -778,7 +778,7 @@ return array( 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', - 'phabricator-diff-changeset-list' => '5c68c40c', + 'phabricator-diff-changeset-list' => '541206ba', 'phabricator-diff-inline' => '77e14b60', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', @@ -1316,6 +1316,10 @@ return array( '5294060f' => array( 'phui-theme-css', ), + '541206ba' => array( + 'javelin-install', + 'phabricator-scroll-objective-list', + ), '54774a28' => array( 'phui-inline-comment-view-css', ), @@ -1368,10 +1372,6 @@ return array( 'javelin-stratcom', 'javelin-dom', ), - '5c68c40c' => array( - 'javelin-install', - 'phabricator-scroll-objective-list', - ), '5e2634b9' => array( 'javelin-behavior', 'javelin-aphlict', diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index e256372852..b615ca79eb 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -1358,16 +1358,20 @@ JX.install('DiffChangesetList', { return null; } - var v = JX.Vector.getViewport(); + // We're going to find the changeset which spans an invisible line a + // little underneath the bottom of the banner. This makes the header + // tick over from "A.txt" to "B.txt" just as "A.txt" scrolls completely + // offscreen. + var detect_height = 64; + for (var ii = 0; ii < this._changesets.length; ii++) { var changeset = this._changesets[ii]; var c = changeset.getVectors(); - // If the changeset starts above the upper half of the screen... - if (c.pos.y < (s.y + (v.y / 2))) { - // ...and ends below the lower half of the screen, this is the - // current visible changeset. - if ((c.pos.y + c.dim.y) > (s.y + (v.y / 2))) { + // If the changeset starts above the line... + if (c.pos.y <= (s.y + detect_height)) { + // ...and ends below the line, this is the current visible changeset. + if ((c.pos.y + c.dim.y) >= (s.y + detect_height)) { return changeset; } } From bdecff7d67ce149c3dfe65629cdf8c90a919f95e Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 07:18:34 -0700 Subject: [PATCH 04/61] Show "objectives" UI only if prototypes are enabled Summary: See D17955. Test Plan: Loaded a revision, no longer saw annotations with prototypes off. Still saw annotations with prototypes on. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17983 --- resources/celerity/map.php | 34 +++++++++---------- .../view/DifferentialChangesetListView.php | 4 +++ .../js/application/diff/DiffChangesetList.js | 10 +++++- .../differential/behavior-populate.js | 3 +- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 019856296b..5b6c54b2f1 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => 'e822b496', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4d7dd14e', - 'differential.pkg.js' => '6d05ad4c', + 'differential.pkg.js' => '0dfe037d', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -391,14 +391,14 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', - 'rsrc/js/application/diff/DiffChangesetList.js' => '541206ba', + 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', 'rsrc/js/application/diff/DiffInline.js' => '77e14b60', 'rsrc/js/application/diff/ScrollObjective.js' => '0eee7a00', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '1ca4d9db', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', - 'rsrc/js/application/differential/behavior-populate.js' => '5e41c819', + 'rsrc/js/application/differential/behavior-populate.js' => '1de8bf63', 'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d', 'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'c93358e3', 'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'd835b03a', @@ -620,7 +620,7 @@ return array( 'javelin-behavior-diff-preview-link' => '051c7832', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-feedback-preview' => '51c5ad07', - 'javelin-behavior-differential-populate' => '5e41c819', + 'javelin-behavior-differential-populate' => '1de8bf63', 'javelin-behavior-differential-user-select' => 'a8d8459d', 'javelin-behavior-diffusion-browse-file' => '054a0f0b', 'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04', @@ -778,7 +778,7 @@ return array( 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', - 'phabricator-diff-changeset-list' => '541206ba', + 'phabricator-diff-changeset-list' => 'a716ca27', 'phabricator-diff-inline' => '77e14b60', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', @@ -1042,6 +1042,14 @@ return array( 'javelin-workflow', 'phabricator-scroll-objective', ), + '1de8bf63' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'phabricator-tooltip', + 'phabricator-diff-changeset-list', + 'phabricator-diff-changeset', + ), '1def2711' => array( 'javelin-install', 'javelin-dom', @@ -1316,10 +1324,6 @@ return array( '5294060f' => array( 'phui-theme-css', ), - '541206ba' => array( - 'javelin-install', - 'phabricator-scroll-objective-list', - ), '54774a28' => array( 'phui-inline-comment-view-css', ), @@ -1378,14 +1382,6 @@ return array( 'phabricator-phtize', 'javelin-dom', ), - '5e41c819' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'phabricator-tooltip', - 'phabricator-diff-changeset-list', - 'phabricator-diff-changeset', - ), '5e9f347c' => array( 'javelin-behavior', 'multirow-row-manager', @@ -1730,6 +1726,10 @@ return array( 'javelin-stratcom', 'javelin-dom', ), + 'a716ca27' => array( + 'javelin-install', + 'phabricator-scroll-objective-list', + ), 'a80d0378' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index 4ac2612ecd..ea8a5e42f1 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -203,11 +203,15 @@ final class DifferentialChangesetListView extends AphrontView { $this->requireResource('aphront-tooltip-css'); + $show_objectives = + PhabricatorEnv::getEnvConfig('phabricator.show-prototypes'); + $this->initBehavior( 'differential-populate', array( 'changesetViewIDs' => $ids, 'inlineURI' => $this->inlineURI, + 'showObjectives' => $show_objectives, 'pht' => array( 'Open in Editor' => pht('Open in Editor'), 'Show All Context' => pht('Show All Context'), diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index b615ca79eb..8e35a92f80 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -120,6 +120,7 @@ JX.install('DiffChangesetList', { _rangeTarget: null, _bannerNode: null, + _showObjectives: false, sleep: function() { this._asleep = true; @@ -137,7 +138,9 @@ JX.install('DiffChangesetList', { this._redrawFocus(); this._redrawSelection(); - this._objectives.show(); + if (this._showObjectives) { + this._objectives.show(); + } if (this._initialized) { return; @@ -195,6 +198,11 @@ JX.install('DiffChangesetList', { this._installKey('q', label, this._onkeyhide); }, + setShowObjectives: function(show) { + this._showObjectives = show; + return this; + }, + isAsleep: function() { return this._asleep; }, diff --git a/webroot/rsrc/js/application/differential/behavior-populate.js b/webroot/rsrc/js/application/differential/behavior-populate.js index e5b0d5039d..b1b5bd415c 100644 --- a/webroot/rsrc/js/application/differential/behavior-populate.js +++ b/webroot/rsrc/js/application/differential/behavior-populate.js @@ -60,7 +60,8 @@ JX.behavior('differential-populate', function(config, statics) { var changeset_list = new JX.DiffChangesetList() .setTranslations(JX.phtize(config.pht)) - .setInlineURI(config.inlineURI); + .setInlineURI(config.inlineURI) + .setShowObjectives(config.showObjectives); // Install and activate the current page. var page_id = JX.Quicksand.getCurrentPageID(); From aba209e9990fe1c975c0786be1bfbc4a9a9d173c Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 04:10:32 -0700 Subject: [PATCH 05/61] Hide the Differential scroll objective list on trackpad systems Summary: Ref T12733. In the longer run I'd like to just push this out from the edge, but that currently gets us into trouble since we start bumping into content. On my system, the trackpad scrollbar also expands in size when moused over, so the minimum number of pixels we need to push it out is approximatley 15px. This hits body content and the persistent chat. For now, just disable this element on trackpad systems. Test Plan: Disconnected all USB peripherals, quit and relaunched Safari, saw no objective list. Reconnected mouse, relaunched Safari, saw objective list. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17974 --- resources/celerity/map.php | 47 ++++++++++--------- .../differential/changeset-view.css | 5 ++ .../rsrc/externals/javelin/lib/Scrollbar.js | 8 ++-- .../application/diff/ScrollObjectiveList.js | 6 +++ 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 5b6c54b2f1..bf2fa84a72 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,10 +10,10 @@ return array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', 'core.pkg.css' => '5ffe8b79', - 'core.pkg.js' => 'e822b496', + 'core.pkg.js' => '6b2da600', 'darkconsole.pkg.js' => '1f9a31bc', - 'differential.pkg.css' => '4d7dd14e', - 'differential.pkg.js' => '0dfe037d', + 'differential.pkg.css' => 'bf87589e', + 'differential.pkg.js' => 'ee4f14c5', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -64,7 +64,7 @@ return array( 'rsrc/css/application/dashboard/dashboard.css' => 'fe5b1869', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', - 'rsrc/css/application/differential/changeset-view.css' => '54774a28', + 'rsrc/css/application/differential/changeset-view.css' => 'fa476ec0', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => 'ffd1a542', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', @@ -247,7 +247,7 @@ return array( 'rsrc/externals/javelin/lib/Resource.js' => '44959b73', 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', - 'rsrc/externals/javelin/lib/Scrollbar.js' => '087e919c', + 'rsrc/externals/javelin/lib/Scrollbar.js' => '9065f639', 'rsrc/externals/javelin/lib/Sound.js' => '949c0fe5', 'rsrc/externals/javelin/lib/URI.js' => 'c989ade3', 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', @@ -394,7 +394,7 @@ return array( 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', 'rsrc/js/application/diff/DiffInline.js' => '77e14b60', 'rsrc/js/application/diff/ScrollObjective.js' => '0eee7a00', - 'rsrc/js/application/diff/ScrollObjectiveList.js' => '1ca4d9db', + 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', @@ -567,7 +567,7 @@ return array( 'conpherence-thread-manager' => '4d863052', 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', - 'differential-changeset-view-css' => '54774a28', + 'differential-changeset-view-css' => 'fa476ec0', 'differential-core-view-css' => '5b7b8ff4', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', @@ -732,7 +732,7 @@ return array( 'javelin-resource' => '44959b73', 'javelin-routable' => 'b3e7d692', 'javelin-router' => '29274e2b', - 'javelin-scrollbar' => '087e919c', + 'javelin-scrollbar' => '9065f639', 'javelin-sound' => '949c0fe5', 'javelin-stratcom' => '6ad39b6f', 'javelin-tokenizer' => '8d3bc1b2', @@ -800,7 +800,7 @@ return array( 'phabricator-prefab' => 'c5af80a2', 'phabricator-remarkup-css' => 'd1a5e11e', 'phabricator-scroll-objective' => '0eee7a00', - 'phabricator-scroll-objective-list' => '1ca4d9db', + 'phabricator-scroll-objective-list' => '085dd101', 'phabricator-search-results-css' => 'f87d23ad', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', @@ -956,11 +956,14 @@ return array( 'javelin-stratcom', 'javelin-util', ), - '087e919c' => array( - 'javelin-install', + '085dd101' => array( 'javelin-dom', + 'javelin-util', 'javelin-stratcom', - 'javelin-vector', + 'javelin-install', + 'javelin-workflow', + 'javelin-scrollbar', + 'phabricator-scroll-objective', ), '08f4ccc3' => array( 'phui-oi-list-view-css', @@ -1034,14 +1037,6 @@ return array( 'javelin-request', 'javelin-uri', ), - '1ca4d9db' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'phabricator-scroll-objective', - ), '1de8bf63' => array( 'javelin-behavior', 'javelin-dom', @@ -1324,9 +1319,6 @@ return array( '5294060f' => array( 'phui-theme-css', ), - '54774a28' => array( - 'phui-inline-comment-view-css', - ), '54b612ba' => array( 'javelin-color', 'javelin-install', @@ -1611,6 +1603,12 @@ return array( 'javelin-dom', 'javelin-request', ), + '9065f639' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-vector', + ), '92b9ec77' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2208,6 +2206,9 @@ return array( 'javelin-install', 'javelin-dom', ), + 'fa476ec0' => array( + 'phui-inline-comment-view-css', + ), 'fbe497e7' => array( 'javelin-behavior', 'javelin-util', diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index eee0e167f3..6a2552fbd1 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -423,6 +423,11 @@ tr.differential-inline-loading { overflow: hidden; } +.scroll-objective-list.has-aesthetic-scrollbar { + /* For now, hide this element on systems with aesthetic scrollbars. */ + display: none; +} + .scroll-objective { display: block; position: absolute; diff --git a/webroot/rsrc/externals/javelin/lib/Scrollbar.js b/webroot/rsrc/externals/javelin/lib/Scrollbar.js index 7596939581..cd69eb4def 100644 --- a/webroot/rsrc/externals/javelin/lib/Scrollbar.js +++ b/webroot/rsrc/externals/javelin/lib/Scrollbar.js @@ -34,7 +34,7 @@ JX.install('Scrollbar', { // width. If it doesn't, we're already in an environment with an aesthetic // scrollbar (like Safari on OSX with no mouse connected, or an iPhone) // and we don't need to do anything. - if (JX.Scrollbar._getScrollbarControlWidth() === 0) { + if (JX.Scrollbar.getScrollbarControlWidth() === 0) { return; } @@ -104,7 +104,7 @@ JX.install('Scrollbar', { /** * Compute the width of the browser's scrollbar control, in pixels. */ - _getScrollbarControlWidth: function() { + getScrollbarControlWidth: function() { var self = JX.Scrollbar; if (self._controlWidth === null) { @@ -140,7 +140,7 @@ JX.install('Scrollbar', { // If this browser and OS don't render a real scrollbar control, we // need to leave a margin. Generally, this is OSX with no mouse attached. - if (self._getScrollbarControlWidth() === 0) { + if (self.getScrollbarControlWidth() === 0) { return 12; } @@ -357,7 +357,7 @@ JX.install('Scrollbar', { */ _resizeViewport: function() { var fdim = JX.Vector.getDim(this._frame); - fdim.x += JX.Scrollbar._getScrollbarControlWidth(); + fdim.x += JX.Scrollbar.getScrollbarControlWidth(); fdim.setDim(this._viewport); }, diff --git a/webroot/rsrc/js/application/diff/ScrollObjectiveList.js b/webroot/rsrc/js/application/diff/ScrollObjectiveList.js index f5beb751e6..7aae1fb1b4 100644 --- a/webroot/rsrc/js/application/diff/ScrollObjectiveList.js +++ b/webroot/rsrc/js/application/diff/ScrollObjectiveList.js @@ -5,6 +5,7 @@ * javelin-stratcom * javelin-install * javelin-workflow + * javelin-scrollbar * phabricator-scroll-objective * @javelin */ @@ -81,6 +82,11 @@ JX.install('ScrollObjectiveList', { document.body.appendChild(node); + // If we're on OSX without a mouse or some other system with zero-width + // trackpad-style scrollbars, adjust the display appropriately. + var aesthetic = (JX.Scrollbar.getScrollbarControlWidth() === 0); + JX.DOM.alterClass(node, 'has-aesthetic-scrollbar', aesthetic); + var d = JX.Vector.getDocument(); var list_dimensions = JX.Vector.getDim(node); From 8b2a06387dbcb3d2e4621c6debf5234c46abbe0d Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 04:19:30 -0700 Subject: [PATCH 06/61] Stop long filenames in objective list tooltips from being cut off Summary: Ref T12733. Currently, long filenames get cut off at 160px. Instead, don't cut them off. Test Plan: Before: {F4968401} After: {F4968402} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17975 --- resources/celerity/map.php | 38 +++++++++---------- .../js/application/diff/ScrollObjective.js | 1 + webroot/rsrc/js/core/ToolTip.js | 6 ++- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index bf2fa84a72..bbd3c5e317 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,10 +10,10 @@ return array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', 'core.pkg.css' => '5ffe8b79', - 'core.pkg.js' => '6b2da600', + 'core.pkg.js' => 'a8eda64a', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => 'bf87589e', - 'differential.pkg.js' => 'ee4f14c5', + 'differential.pkg.js' => '24d1acf0', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -393,7 +393,7 @@ return array( 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', 'rsrc/js/application/diff/DiffInline.js' => '77e14b60', - 'rsrc/js/application/diff/ScrollObjective.js' => '0eee7a00', + 'rsrc/js/application/diff/ScrollObjective.js' => '2e069f79', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', @@ -480,7 +480,7 @@ return array( 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '320810c8', 'rsrc/js/core/Title.js' => '485aaa6c', - 'rsrc/js/core/ToolTip.js' => '8fadb715', + 'rsrc/js/core/ToolTip.js' => '74caa17f', 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', @@ -799,7 +799,7 @@ return array( 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'c5af80a2', 'phabricator-remarkup-css' => 'd1a5e11e', - 'phabricator-scroll-objective' => '0eee7a00', + 'phabricator-scroll-objective' => '2e069f79', 'phabricator-scroll-objective-list' => '085dd101', 'phabricator-search-results-css' => 'f87d23ad', 'phabricator-shaped-request' => '7cbe244b', @@ -808,7 +808,7 @@ return array( 'phabricator-standard-page-view' => 'eb5b80c5', 'phabricator-textareautils' => '320810c8', 'phabricator-title' => '485aaa6c', - 'phabricator-tooltip' => '8fadb715', + 'phabricator-tooltip' => '74caa17f', 'phabricator-ui-example-css' => '528b19de', 'phabricator-uiexample-javelin-view' => 'd4a14807', 'phabricator-uiexample-reactor-button' => 'd19198c8', @@ -980,13 +980,6 @@ return array( 'javelin-dom', 'javelin-router', ), - '0eee7a00' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - ), '0f764c35' => array( 'javelin-install', 'javelin-util', @@ -1120,6 +1113,13 @@ return array( 'javelin-install', 'javelin-event', ), + '2e069f79' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + ), '2ee659ce' => array( 'javelin-install', ), @@ -1462,6 +1462,12 @@ return array( 'javelin-vector', 'javelin-dom', ), + '74caa17f' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1587,12 +1593,6 @@ return array( 'javelin-stratcom', 'javelin-install', ), - '8fadb715' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-vector', - ), '8ff5e24c' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/webroot/rsrc/js/application/diff/ScrollObjective.js b/webroot/rsrc/js/application/diff/ScrollObjective.js index 4e6fa55d6a..c9fd4bb67e 100644 --- a/webroot/rsrc/js/application/diff/ScrollObjective.js +++ b/webroot/rsrc/js/application/diff/ScrollObjective.js @@ -100,6 +100,7 @@ JX.install('ScrollObjective', { JX.Stratcom.addSigil(node, 'has-tooltip'); JX.Stratcom.getData(node).tip = tip; JX.Stratcom.getData(node).align = 'W'; + JX.Stratcom.getData(node).size = 'auto'; return this; }, diff --git a/webroot/rsrc/js/core/ToolTip.js b/webroot/rsrc/js/core/ToolTip.js index 6fef44ab55..64a2deb301 100644 --- a/webroot/rsrc/js/core/ToolTip.js +++ b/webroot/rsrc/js/core/ToolTip.js @@ -50,7 +50,11 @@ JX.install('Tooltip', { { className: 'jx-tooltip-container' }, node_inner); - node.style.maxWidth = scale + 'px'; + if (scale == 'auto') { + node.style.maxWidth = ''; + } else { + node.style.maxWidth = scale + 'px'; + } JX.Tooltip.hide(); self._node = node; From af07600aaac7da1ca89f985f21dd72ed50bba085 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 04:58:09 -0700 Subject: [PATCH 07/61] Make Differential objective markers show a brighter "editing" state Summary: Ref T12733. - While editing a comment, show a pink star ({icon star, color=pink}) with a tooltip. - Slight UI tweaks, including draft comments getting an indigo pencil ({icon pencil, color=indigo}). Test Plan: {F4968470} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17977 --- resources/celerity/map.php | 40 +++++++++---------- .../view/DifferentialChangesetListView.php | 2 + .../differential/changeset-view.css | 5 ++- .../rsrc/js/application/diff/DiffInline.js | 29 +++++++++++++- webroot/rsrc/js/core/ToolTip.js | 4 ++ 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index bbd3c5e317..97b4f15a35 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,10 +10,10 @@ return array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', 'core.pkg.css' => '5ffe8b79', - 'core.pkg.js' => 'a8eda64a', + 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', - 'differential.pkg.css' => 'bf87589e', - 'differential.pkg.js' => '24d1acf0', + 'differential.pkg.css' => '7d4cfa59', + 'differential.pkg.js' => 'f94e941c', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -64,7 +64,7 @@ return array( 'rsrc/css/application/dashboard/dashboard.css' => 'fe5b1869', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', - 'rsrc/css/application/differential/changeset-view.css' => 'fa476ec0', + 'rsrc/css/application/differential/changeset-view.css' => 'acfd58f6', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => 'ffd1a542', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', @@ -392,7 +392,7 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => '77e14b60', + 'rsrc/js/application/diff/DiffInline.js' => 'fa07d36e', 'rsrc/js/application/diff/ScrollObjective.js' => '2e069f79', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', @@ -480,7 +480,7 @@ return array( 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '320810c8', 'rsrc/js/core/Title.js' => '485aaa6c', - 'rsrc/js/core/ToolTip.js' => '74caa17f', + 'rsrc/js/core/ToolTip.js' => '358b8c04', 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', @@ -567,7 +567,7 @@ return array( 'conpherence-thread-manager' => '4d863052', 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', - 'differential-changeset-view-css' => 'fa476ec0', + 'differential-changeset-view-css' => 'acfd58f6', 'differential-core-view-css' => '5b7b8ff4', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', @@ -779,7 +779,7 @@ return array( 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => '77e14b60', + 'phabricator-diff-inline' => 'fa07d36e', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -808,7 +808,7 @@ return array( 'phabricator-standard-page-view' => 'eb5b80c5', 'phabricator-textareautils' => '320810c8', 'phabricator-title' => '485aaa6c', - 'phabricator-tooltip' => '74caa17f', + 'phabricator-tooltip' => '358b8c04', 'phabricator-ui-example-css' => '528b19de', 'phabricator-uiexample-javelin-view' => 'd4a14807', 'phabricator-uiexample-reactor-button' => 'd19198c8', @@ -1137,6 +1137,12 @@ return array( 'javelin-dom', 'javelin-workflow', ), + '358b8c04' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1462,12 +1468,6 @@ return array( 'javelin-vector', 'javelin-dom', ), - '74caa17f' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-vector', - ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1480,9 +1480,6 @@ return array( 'javelin-reactor', 'javelin-util', ), - '77e14b60' => array( - 'javelin-dom', - ), '782ab6e7' => array( 'javelin-behavior', 'javelin-dom', @@ -1788,6 +1785,9 @@ return array( 'phuix-autocomplete', 'javelin-mask', ), + 'acfd58f6' => array( + 'phui-inline-comment-view-css', + ), 'ae95d984' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2206,8 +2206,8 @@ return array( 'javelin-install', 'javelin-dom', ), - 'fa476ec0' => array( - 'phui-inline-comment-view-css', + 'fa07d36e' => array( + 'javelin-dom', ), 'fbe497e7' => array( 'javelin-behavior', diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index ea8a5e42f1..880fcb872d 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -232,6 +232,8 @@ final class DifferentialChangesetListView extends AphrontView { 'Loading...' => pht('Loading...'), + 'Editing Comment' => pht('Editing Comment'), + 'Jump to next change.' => pht('Jump to next change.'), 'Jump to previous change.' => pht('Jump to previous change.'), 'Jump to next file.' => pht('Jump to next file.'), diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index 6a2552fbd1..6a29e1269b 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -419,7 +419,7 @@ tr.differential-inline-loading { border-style: solid; border-color: rgba(255, 255, 255, 0.95); border-width: 1px 0 1px 1px; - box-shadow: -1px 0 2px rgba(255, 255, 255, 0.25); + box-shadow: -1px 0 2px rgba(255, 255, 255, 0.10); overflow: hidden; } @@ -433,7 +433,8 @@ tr.differential-inline-loading { position: absolute; box-sizing: border-box; cursor: pointer; - left: 8px; + text-align: middle; + left: 7px; } .scroll-objective .phui-icon-view { diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index e66fb544c5..32cf0ac5a1 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -32,6 +32,7 @@ JX.install('DiffInline', { _isDraft: null, _isFixed: null, + _isEditing: false, bindToRow: function(row) { this._row = row; @@ -176,6 +177,12 @@ JX.install('DiffInline', { return this._changeset; }, + setEditing: function(editing) { + this._isEditing = editing; + this.updateObjective(); + return this; + }, + _onobjective: function() { this.getChangeset().getChangesetList().selectInline(this); }, @@ -194,12 +201,20 @@ JX.install('DiffInline', { return; } + var pht = changeset.getChangesetList().getTranslations(); + var icon = 'fa-comment'; var color = 'bluegrey'; + var tooltip = null; - if (this._isDraft) { + if (this._isEditing) { + icon = 'fa-star'; + color = 'pink'; + tooltip = pht('Editing Comment'); + } else if (this._isDraft) { // This inline is an unsubmitted draft. icon = 'fa-pencil'; + color = 'indigo'; } else if (this._isFixed) { // This inline has been marked done. icon = 'fa-check'; @@ -212,6 +227,7 @@ JX.install('DiffInline', { objective .setIcon(icon) .setColor(color) + .setTooltip(tooltip) .show(); }, @@ -511,7 +527,12 @@ JX.install('DiffInline', { this._undoRow = this._drawRows(template, cursor, mode, text); }, + _drawContentRows: function(rows) { + return this._drawRows(rows, null, 'content'); + }, + _drawEditRows: function(rows) { + this.setEditing(true); return this._drawRows(rows, null, 'edit'); }, @@ -560,6 +581,8 @@ JX.install('DiffInline', { 'click', 'inline-edit-cancel', JX.bind(this, this._oncancel, row_meta))); + } else if (type == 'content') { + // No special listeners for these rows. } else { row_meta.listeners.push( JX.DOM.listen( @@ -645,6 +668,7 @@ JX.install('DiffInline', { } this._removeRow(row); + this.setEditing(false); this.setInvisible(false); @@ -670,6 +694,7 @@ JX.install('DiffInline', { this.setLoading(false); this.setInvisible(false); + this.setEditing(false); this._onupdate(response); }, @@ -677,7 +702,7 @@ JX.install('DiffInline', { _onupdate: function(response) { var new_row; if (response.markup) { - new_row = this._drawEditRows(JX.$H(response.markup).getNode()).node; + new_row = this._drawContentRows(JX.$H(response.markup).getNode()).node; } // TODO: Save the old row so the action it's undo-able if it was a diff --git a/webroot/rsrc/js/core/ToolTip.js b/webroot/rsrc/js/core/ToolTip.js index 64a2deb301..635c9466ad 100644 --- a/webroot/rsrc/js/core/ToolTip.js +++ b/webroot/rsrc/js/core/ToolTip.js @@ -21,6 +21,10 @@ JX.install('Tooltip', { return; } + if (content === null) { + return; + } + if (__DEV__) { switch (align) { case 'N': From c056ff56cc957135f78768a9ace60014dd731a64 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 05:26:51 -0700 Subject: [PATCH 08/61] Fix a diff objective issue where objectives could appear in the wrong place Summary: Ref T12733. When creating a new comment, the objective could appear to far up in the scrollbar because we were anchoring it to an invisible row. Instead, anchor to the "edit" row while editing. Test Plan: Created a new comment at the very top of a file, saw "File, Star" icons instead of "Star, File". Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17978 --- resources/celerity/map.php | 30 +++++++++---------- .../rsrc/js/application/diff/DiffInline.js | 16 ++++++++-- .../js/application/diff/ScrollObjective.js | 1 + 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 97b4f15a35..968862b535 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', - 'differential.pkg.js' => 'f94e941c', + 'differential.pkg.js' => 'fc6a23eb', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -392,8 +392,8 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => 'fa07d36e', - 'rsrc/js/application/diff/ScrollObjective.js' => '2e069f79', + 'rsrc/js/application/diff/DiffInline.js' => '93cbb03f', + 'rsrc/js/application/diff/ScrollObjective.js' => '9df4e4e2', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', @@ -779,7 +779,7 @@ return array( 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => 'fa07d36e', + 'phabricator-diff-inline' => '93cbb03f', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -799,7 +799,7 @@ return array( 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'c5af80a2', 'phabricator-remarkup-css' => 'd1a5e11e', - 'phabricator-scroll-objective' => '2e069f79', + 'phabricator-scroll-objective' => '9df4e4e2', 'phabricator-scroll-objective-list' => '085dd101', 'phabricator-search-results-css' => 'f87d23ad', 'phabricator-shaped-request' => '7cbe244b', @@ -1113,13 +1113,6 @@ return array( 'javelin-install', 'javelin-event', ), - '2e069f79' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - ), '2ee659ce' => array( 'javelin-install', ), @@ -1611,6 +1604,9 @@ return array( 'javelin-stratcom', 'javelin-dom', ), + '93cbb03f' => array( + 'javelin-dom', + ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1675,6 +1671,13 @@ return array( '9d9685d6' => array( 'phui-oi-list-view-css', ), + '9df4e4e2' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2206,9 +2209,6 @@ return array( 'javelin-install', 'javelin-dom', ), - 'fa07d36e' => array( - 'javelin-dom', - ), 'fbe497e7' => array( 'javelin-behavior', 'javelin-util', diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index 32cf0ac5a1..77a0da3ec7 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -74,9 +74,10 @@ JX.install('DiffInline', { this._changesetID = data.changesetID; - this.updateObjective(); this.setInvisible(false); + this.updateObjective(); + return this; }, @@ -166,9 +167,11 @@ JX.install('DiffInline', { this._changeset = changeset; var objectives = changeset.getChangesetList().getObjectives(); + + // Create this inline's objective, but don't show it yet. this._objective = objectives.newObjective() - .setCallback(JX.bind(this, this._onobjective)); - this.updateObjective(); + .setCallback(JX.bind(this, this._onobjective)) + .hide(); return this; }, @@ -206,11 +209,17 @@ JX.install('DiffInline', { var icon = 'fa-comment'; var color = 'bluegrey'; var tooltip = null; + var anchor = this._row; if (this._isEditing) { icon = 'fa-star'; color = 'pink'; tooltip = pht('Editing Comment'); + + // If we're editing, anchor to the row with the editor instead of the + // actual comment row (which is invisible and can have a misleading + // position). + anchor = this._row.nextSibling; } else if (this._isDraft) { // This inline is an unsubmitted draft. icon = 'fa-pencil'; @@ -225,6 +234,7 @@ JX.install('DiffInline', { } objective + .setAnchor(anchor) .setIcon(icon) .setColor(color) .setTooltip(tooltip) diff --git a/webroot/rsrc/js/application/diff/ScrollObjective.js b/webroot/rsrc/js/application/diff/ScrollObjective.js index c9fd4bb67e..b8fb169914 100644 --- a/webroot/rsrc/js/application/diff/ScrollObjective.js +++ b/webroot/rsrc/js/application/diff/ScrollObjective.js @@ -111,6 +111,7 @@ JX.install('ScrollObjective', { hide: function() { this._visible = false; + return this; }, isVisible: function() { From 7a40dd380ee7514f802c292e1522245800c77272 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 05:33:59 -0700 Subject: [PATCH 09/61] When a user cancels a new inline, clear it from the objective list Summary: Ref T12733. Currently, creating a new inline and then canceling it leaves a marker in the objective list. Instead, remove the marker. Test Plan: - Created an empty inline, cancelled. Created a non-empty inline, cancelled. No objective marker in either case. - Created a new normal inline, objective marker. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17979 --- resources/celerity/map.php | 12 ++++++------ webroot/rsrc/js/application/diff/DiffInline.js | 11 +++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 968862b535..402ae9013e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', - 'differential.pkg.js' => 'fc6a23eb', + 'differential.pkg.js' => 'd7e3edd5', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -392,7 +392,7 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => '93cbb03f', + 'rsrc/js/application/diff/DiffInline.js' => 'ca0fafde', 'rsrc/js/application/diff/ScrollObjective.js' => '9df4e4e2', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', @@ -779,7 +779,7 @@ return array( 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => '93cbb03f', + 'phabricator-diff-inline' => 'ca0fafde', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1604,9 +1604,6 @@ return array( 'javelin-stratcom', 'javelin-dom', ), - '93cbb03f' => array( - 'javelin-dom', - ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1979,6 +1976,9 @@ return array( 'phabricator-shaped-request', 'conpherence-thread-manager', ), + 'ca0fafde' => array( + 'javelin-dom', + ), 'caade6f2' => array( 'javelin-behavior', 'javelin-request', diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index 77a0da3ec7..e7c18ef6ad 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -33,6 +33,7 @@ JX.install('DiffInline', { _isDraft: null, _isFixed: null, _isEditing: false, + _isNew: false, bindToRow: function(row) { this._row = row; @@ -73,6 +74,7 @@ JX.install('DiffInline', { this._isGhost = data.isGhost; this._changesetID = data.changesetID; + this._isNew = false; this.setInvisible(false); @@ -87,6 +89,7 @@ JX.install('DiffInline', { this._length = parseInt(data.length, 10); this._isNewFile = data.isNewFile; this._changesetID = data.changesetID; + this._isNew = true; // Insert the comment after any other comments which already appear on // the same row. @@ -110,6 +113,7 @@ JX.install('DiffInline', { this._length = inline._length; this._isNewFile = inline._isNewFile; this._changesetID = inline._changesetID; + this._isNew = true; this._replyToCommentPHID = inline._phid; @@ -198,6 +202,13 @@ JX.install('DiffInline', { return; } + // If this is a new comment which we aren't editing, don't show anything: + // the use started a comment or reply, then cancelled it. + if (this._isNew && !this._isEditing) { + objective.hide(); + return; + } + var changeset = this.getChangeset(); if (!changeset.isVisible()) { objective.hide(); From 4dff754502bdbf57b964eccc12aa774b6cecf171 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 05:39:07 -0700 Subject: [PATCH 10/61] Show a snippet when hovering inlines in the objective list Summary: Ref T12733. Shows a comment snippet when hovering inlines in the objective list. Test Plan: {F4968490} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17980 --- resources/celerity/map.php | 12 ++++++------ .../diff/view/PHUIDiffInlineCommentDetailView.php | 9 +++++---- webroot/rsrc/js/application/diff/DiffInline.js | 4 +++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 402ae9013e..46443e7ecc 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', - 'differential.pkg.js' => 'd7e3edd5', + 'differential.pkg.js' => '06cddcc0', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -392,7 +392,7 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => 'ca0fafde', + 'rsrc/js/application/diff/DiffInline.js' => '4478f8ac', 'rsrc/js/application/diff/ScrollObjective.js' => '9df4e4e2', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', @@ -779,7 +779,7 @@ return array( 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => 'ca0fafde', + 'phabricator-diff-inline' => '4478f8ac', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1203,6 +1203,9 @@ return array( 'javelin-workflow', 'javelin-workboard-controller', ), + '4478f8ac' => array( + 'javelin-dom', + ), '44959b73' => array( 'javelin-util', 'javelin-uri', @@ -1976,9 +1979,6 @@ return array( 'phabricator-shaped-request', 'conpherence-thread-manager', ), - 'ca0fafde' => array( - 'javelin-dom', - ), 'caade6f2' => array( 'javelin-behavior', 'javelin-request', diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 9fc1e1bded..821834431a 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -421,6 +421,11 @@ final class PHUIDiffInlineCommentDetailView $actions, )); + $snippet = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(96) + ->truncateString($inline->getContent()); + $metadata['snippet'] = pht('%s: %s', $author, $snippet); + $markup = javelin_tag( 'div', array( @@ -444,10 +449,6 @@ final class PHUIDiffInlineCommentDetailView phutil_tag_div('phabricator-remarkup', $content)), )); - $snippet = id(new PhutilUTF8StringTruncator()) - ->setMaximumGlyphs(96) - ->truncateString($inline->getContent()); - $summary = phutil_tag( 'div', array( diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index e7c18ef6ad..1f0d503b9f 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -22,6 +22,7 @@ JX.install('DiffInline', { _undoRow: null, _replyToCommentPHID: null, _originalText: null, + _snippet: null, _isDeleted: false, _isInvisible: false, @@ -75,6 +76,7 @@ JX.install('DiffInline', { this._changesetID = data.changesetID; this._isNew = false; + this._snippet = data.snippet; this.setInvisible(false); @@ -219,7 +221,7 @@ JX.install('DiffInline', { var icon = 'fa-comment'; var color = 'bluegrey'; - var tooltip = null; + var tooltip = this._snippet; var anchor = this._row; if (this._isEditing) { From e15009b76e1b085fabb0efe58a03869999ca202a Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 05:48:38 -0700 Subject: [PATCH 11/61] Show "reply" inlines as replies in the objective list Summary: Ref T12733. Show a "reply" icon for replies, and make them stack directly under their parent. Test Plan: {F4968500} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17981 --- resources/celerity/map.php | 52 +++++++++---------- .../rsrc/js/application/diff/DiffInline.js | 5 ++ .../js/application/diff/ScrollObjective.js | 18 +++++++ .../application/diff/ScrollObjectiveList.js | 9 +++- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 46443e7ecc..1d430926a6 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', - 'differential.pkg.js' => '06cddcc0', + 'differential.pkg.js' => '886eadff', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -392,9 +392,9 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => '4478f8ac', - 'rsrc/js/application/diff/ScrollObjective.js' => '9df4e4e2', - 'rsrc/js/application/diff/ScrollObjectiveList.js' => '085dd101', + 'rsrc/js/application/diff/DiffInline.js' => '1478c3b2', + 'rsrc/js/application/diff/ScrollObjective.js' => '7e8877e7', + 'rsrc/js/application/diff/ScrollObjectiveList.js' => '6120e99a', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', @@ -779,7 +779,7 @@ return array( 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => '4478f8ac', + 'phabricator-diff-inline' => '1478c3b2', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -799,8 +799,8 @@ return array( 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'c5af80a2', 'phabricator-remarkup-css' => 'd1a5e11e', - 'phabricator-scroll-objective' => '9df4e4e2', - 'phabricator-scroll-objective-list' => '085dd101', + 'phabricator-scroll-objective' => '7e8877e7', + 'phabricator-scroll-objective-list' => '6120e99a', 'phabricator-search-results-css' => 'f87d23ad', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', @@ -956,15 +956,6 @@ return array( 'javelin-stratcom', 'javelin-util', ), - '085dd101' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-scrollbar', - 'phabricator-scroll-objective', - ), '08f4ccc3' => array( 'phui-oi-list-view-css', ), @@ -990,6 +981,9 @@ return array( 'javelin-dom', 'javelin-typeahead-normalizer', ), + '1478c3b2' => array( + 'javelin-dom', + ), '1499a8cb' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1203,9 +1197,6 @@ return array( 'javelin-workflow', 'javelin-workboard-controller', ), - '4478f8ac' => array( - 'javelin-dom', - ), '44959b73' => array( 'javelin-util', 'javelin-uri', @@ -1393,6 +1384,15 @@ return array( 'javelin-stratcom', 'javelin-dom', ), + '6120e99a' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-scrollbar', + 'phabricator-scroll-objective', + ), '61cbc29a' => array( 'javelin-magical-init', 'javelin-util', @@ -1501,6 +1501,13 @@ return array( '7e41274a' => array( 'javelin-install', ), + '7e8877e7' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + ), '7ebaeed3' => array( 'herald-rule-editor', 'javelin-behavior', @@ -1671,13 +1678,6 @@ return array( '9d9685d6' => array( 'phui-oi-list-view-css', ), - '9df4e4e2' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index 1f0d503b9f..b0a8202e54 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -223,6 +223,7 @@ JX.install('DiffInline', { var color = 'bluegrey'; var tooltip = this._snippet; var anchor = this._row; + var should_stack = false; if (this._isEditing) { icon = 'fa-star'; @@ -244,6 +245,9 @@ JX.install('DiffInline', { } else if (this._isGhost) { icon = 'fa-comment-o'; color = 'grey'; + } else if (this._replyToCommentPHID) { + icon = 'fa-reply'; + should_stack = true; } objective @@ -251,6 +255,7 @@ JX.install('DiffInline', { .setIcon(icon) .setColor(color) .setTooltip(tooltip) + .setShouldStack(should_stack) .show(); }, diff --git a/webroot/rsrc/js/application/diff/ScrollObjective.js b/webroot/rsrc/js/application/diff/ScrollObjective.js index b8fb169914..1e596bd816 100644 --- a/webroot/rsrc/js/application/diff/ScrollObjective.js +++ b/webroot/rsrc/js/application/diff/ScrollObjective.js @@ -26,6 +26,7 @@ JX.install('ScrollObjective', { _visible: false, _callback: false, + _stack: false, getNode: function() { if (!this._node) { @@ -104,6 +105,23 @@ JX.install('ScrollObjective', { return this; }, + + /** + * Should this objective always stack immediately under the previous + * objective? + * + * This allows related objectives (like "comment, reply, reply") to be + * rendered in a tight sequence. + */ + setShouldStack: function(stack) { + this._stack = stack; + return this; + }, + + shouldStack: function() { + return this._stack; + }, + show: function() { this._visible = true; return this; diff --git a/webroot/rsrc/js/application/diff/ScrollObjectiveList.js b/webroot/rsrc/js/application/diff/ScrollObjectiveList.js index 7aae1fb1b4..ce47877d1a 100644 --- a/webroot/rsrc/js/application/diff/ScrollObjectiveList.js +++ b/webroot/rsrc/js/application/diff/ScrollObjectiveList.js @@ -112,7 +112,8 @@ JX.install('ScrollObjectiveList', { items.push({ offset: offset, - node: objective_node + node: objective_node, + objective: objective }); } @@ -130,7 +131,11 @@ JX.install('ScrollObjectiveList', { offset = item.offset; if (min !== null) { - offset = Math.max(offset, min); + if (item.objective.shouldStack()) { + offset = min; + } else { + offset = Math.max(offset, min); + } } min = offset + 15; From 7d44e7cb4d2f7f0fe5b58ce84c5fedf42dce512f Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 20 May 2017 05:59:47 -0700 Subject: [PATCH 12/61] Show the curent selected inline in the objective list Summary: Ref T12733. When an inline is selected, make it stand out so you can see where you are in the document more clearly. Test Plan: {F4968509} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17982 --- resources/celerity/map.php | 24 +++++++++---------- .../js/application/diff/DiffChangesetList.js | 16 ++++++++++++- .../rsrc/js/application/diff/DiffInline.js | 7 ++++++ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 1d430926a6..26ebc596f3 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', - 'differential.pkg.js' => '886eadff', + 'differential.pkg.js' => '1d120743', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -391,8 +391,8 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => 'cf4e2140', - 'rsrc/js/application/diff/DiffChangesetList.js' => 'a716ca27', - 'rsrc/js/application/diff/DiffInline.js' => '1478c3b2', + 'rsrc/js/application/diff/DiffChangesetList.js' => '7a184082', + 'rsrc/js/application/diff/DiffInline.js' => '19582231', 'rsrc/js/application/diff/ScrollObjective.js' => '7e8877e7', 'rsrc/js/application/diff/ScrollObjectiveList.js' => '6120e99a', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', @@ -778,8 +778,8 @@ return array( 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => 'cf4e2140', - 'phabricator-diff-changeset-list' => 'a716ca27', - 'phabricator-diff-inline' => '1478c3b2', + 'phabricator-diff-changeset-list' => '7a184082', + 'phabricator-diff-inline' => '19582231', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -981,9 +981,6 @@ return array( 'javelin-dom', 'javelin-typeahead-normalizer', ), - '1478c3b2' => array( - 'javelin-dom', - ), '1499a8cb' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1003,6 +1000,9 @@ return array( '185bbd53' => array( 'javelin-install', ), + 19582231 => array( + 'javelin-dom', + ), '19f9369b' => array( 'phui-oi-list-view-css', ), @@ -1488,6 +1488,10 @@ return array( 'javelin-behavior', 'javelin-quicksand', ), + '7a184082' => array( + 'javelin-install', + 'phabricator-scroll-objective-list', + ), '7a68dda3' => array( 'owners-path-editor', 'javelin-behavior', @@ -1724,10 +1728,6 @@ return array( 'javelin-stratcom', 'javelin-dom', ), - 'a716ca27' => array( - 'javelin-install', - 'phabricator-scroll-objective-list', - ), 'a80d0378' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index 8e35a92f80..c344c96de8 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -538,10 +538,24 @@ JX.install('DiffChangesetList', { }, _setSelectionState: function(item, manager) { - this._cursorItem = item; + // If we had an inline selected before, we need to update it after + // changing our selection to clear the selected state. Then, update the + // new one to add the selected state. + var old_inline = this.getSelectedInline(); + this._cursorItem = item; this._redrawSelection(manager, true); + var new_inline = this.getSelectedInline(); + + if (old_inline) { + old_inline.updateObjective(); + } + + if (new_inline) { + new_inline.updateObjective(); + } + return this; }, diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index b0a8202e54..bfc2a3e258 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -250,6 +250,13 @@ JX.install('DiffInline', { should_stack = true; } + if (changeset.getChangesetList().getSelectedInline() === this) { + // TODO: Maybe add some other kind of effect here, since we're only + // using color to show this? + color = 'yellow'; + } + + objective .setAnchor(anchor) .setIcon(icon) From bc4ef0d22f3a71f1f6fb10ab4bc85ac954e13c9e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 20 May 2017 09:06:26 -0700 Subject: [PATCH 13/61] Reorder workboard menu items Summary: Adds a divider and better grouping Test Plan: Click on dropdown menu on a workboard Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17984 --- .../PhabricatorProjectBoardViewController.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index da1f0ccb95..51b907cac0 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -713,14 +713,6 @@ final class PhabricatorProjectBoardViewController ->setDisabled(!$can_edit) ->setWorkflow(true); - $background_uri = $this->getApplicationURI("board/{$id}/background/"); - $manage_items[] = id(new PhabricatorActionView()) - ->setIcon('fa-paint-brush') - ->setName(pht('Change Background Color')) - ->setHref($background_uri) - ->setDisabled(!$can_edit) - ->setWorkflow(false); - if ($show_hidden) { $hidden_uri = $this->getURIWithState() ->setQueryParam('hidden', null); @@ -738,6 +730,17 @@ final class PhabricatorProjectBoardViewController ->setName($hidden_text) ->setHref($hidden_uri); + $manage_items[] = id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER); + + $background_uri = $this->getApplicationURI("board/{$id}/background/"); + $manage_items[] = id(new PhabricatorActionView()) + ->setIcon('fa-paint-brush') + ->setName(pht('Change Background Color')) + ->setHref($background_uri) + ->setDisabled(!$can_edit) + ->setWorkflow(false); + $manage_uri = $this->getApplicationURI("board/{$id}/manage/"); $manage_items[] = id(new PhabricatorActionView()) ->setIcon('fa-gear') From 11578bfc90090ec5ed96c3ed878695fe12a531a0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 21 May 2017 09:24:26 -0700 Subject: [PATCH 14/61] Add Revisions to User Profiles Summary: Ref T12423. Adds back revisions as a user profile page. I don't want to think about custom profiles for a while. Test Plan: Make some diffs, visit my profile, see diffs. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12423 Differential Revision: https://secure.phabricator.com/D17987 --- src/__phutil_library_map__.php | 4 + .../PhabricatorPeopleApplication.php | 2 + ...bricatorPeopleProfileCommitsController.php | 8 -- ...icatorPeopleProfileRevisionsController.php | 82 +++++++++++++++++++ ...habricatorPeopleProfileTasksController.php | 4 - .../PhabricatorPeopleProfileMenuEngine.php | 11 +++ ...bricatorPeopleRevisionsProfileMenuItem.php | 59 +++++++++++++ 7 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 src/applications/people/controller/PhabricatorPeopleProfileRevisionsController.php create mode 100644 src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index cbf324c847..f6b66d9ab8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3457,10 +3457,12 @@ phutil_register_library_map(array( 'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php', 'PhabricatorPeopleProfileMenuEngine' => 'applications/people/engine/PhabricatorPeopleProfileMenuEngine.php', 'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php', + 'PhabricatorPeopleProfileRevisionsController' => 'applications/people/controller/PhabricatorPeopleProfileRevisionsController.php', 'PhabricatorPeopleProfileTasksController' => 'applications/people/controller/PhabricatorPeopleProfileTasksController.php', 'PhabricatorPeopleProfileViewController' => 'applications/people/controller/PhabricatorPeopleProfileViewController.php', 'PhabricatorPeopleQuery' => 'applications/people/query/PhabricatorPeopleQuery.php', 'PhabricatorPeopleRenameController' => 'applications/people/controller/PhabricatorPeopleRenameController.php', + 'PhabricatorPeopleRevisionsProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php', 'PhabricatorPeopleSearchEngine' => 'applications/people/query/PhabricatorPeopleSearchEngine.php', 'PhabricatorPeopleTasksProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php', 'PhabricatorPeopleTestDataGenerator' => 'applications/people/lipsum/PhabricatorPeopleTestDataGenerator.php', @@ -8825,10 +8827,12 @@ phutil_register_library_map(array( 'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfileMenuEngine' => 'PhabricatorProfileMenuEngine', 'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleProfileController', + 'PhabricatorPeopleProfileRevisionsController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfileTasksController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfileViewController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleRenameController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleRevisionsProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorPeopleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleTasksProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorPeopleTestDataGenerator' => 'PhabricatorTestDataGenerator', diff --git a/src/applications/people/application/PhabricatorPeopleApplication.php b/src/applications/people/application/PhabricatorPeopleApplication.php index f2bb70e423..dde82f1d3a 100644 --- a/src/applications/people/application/PhabricatorPeopleApplication.php +++ b/src/applications/people/application/PhabricatorPeopleApplication.php @@ -70,6 +70,8 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication { 'PhabricatorPeopleProfileTasksController', 'commits/(?P[1-9]\d*)/' => 'PhabricatorPeopleProfileCommitsController', + 'revisions/(?P[1-9]\d*)/' => + 'PhabricatorPeopleProfileRevisionsController', 'picture/(?P[1-9]\d*)/' => 'PhabricatorPeopleProfilePictureController', 'manage/(?P[1-9]\d*)/' => diff --git a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php index f2adf4b23d..3e1e6de1ee 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php @@ -13,10 +13,6 @@ final class PhabricatorPeopleProfileCommitsController ->needProfile(true) ->needProfileImage(true) ->needAvailability(true) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - )) ->executeOne(); if (!$user) { return new Aphront404Response(); @@ -63,10 +59,6 @@ final class PhabricatorPeopleProfileCommitsController ->needAuditRequests(true) ->needCommitData(true) ->needDrafts(true) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - )) ->setLimit(100) ->execute(); diff --git a/src/applications/people/controller/PhabricatorPeopleProfileRevisionsController.php b/src/applications/people/controller/PhabricatorPeopleProfileRevisionsController.php new file mode 100644 index 0000000000..adb2a60e5d --- /dev/null +++ b/src/applications/people/controller/PhabricatorPeopleProfileRevisionsController.php @@ -0,0 +1,82 @@ +getViewer(); + $id = $request->getURIData('id'); + + $user = id(new PhabricatorPeopleQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needProfile(true) + ->needProfileImage(true) + ->needAvailability(true) + ->executeOne(); + if (!$user) { + return new Aphront404Response(); + } + + $class = 'PhabricatorDifferentialApplication'; + if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { + return new Aphront404Response(); + } + + $this->setUser($user); + $title = array(pht('Recent Revisions'), $user->getUsername()); + $header = $this->buildProfileHeader(); + $commits = $this->buildRevisionsView($user); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Recent Revisions')); + $crumbs->setBorder(true); + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_REVISIONS); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->addClass('project-view-home') + ->addClass('project-view-people-home') + ->setFooter(array( + $commits, + )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setNavigation($nav) + ->appendChild($view); + } + + private function buildRevisionsView(PhabricatorUser $user) { + $viewer = $this->getViewer(); + + $revisions = id(new DifferentialRevisionQuery()) + ->setViewer($viewer) + ->withAuthors(array($user->getPHID())) + ->needFlags(true) + ->needDrafts(true) + ->needReviewers(true) + ->setLimit(100) + ->execute(); + + $list = id(new DifferentialRevisionListView()) + ->setUser($viewer) + ->setNoBox(true) + ->setRevisions($revisions) + ->setNoDataString(pht('No recent revisions.')); + + $object_phids = $list->getRequiredHandlePHIDs(); + $handles = $this->loadViewerHandles($object_phids); + $list->setHandles($handles); + + $view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Recent Revisions')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($list); + + return $view; + } +} diff --git a/src/applications/people/controller/PhabricatorPeopleProfileTasksController.php b/src/applications/people/controller/PhabricatorPeopleProfileTasksController.php index 52c88d89fa..47cc605bb8 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileTasksController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileTasksController.php @@ -13,10 +13,6 @@ final class PhabricatorPeopleProfileTasksController ->needProfile(true) ->needProfileImage(true) ->needAvailability(true) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - )) ->executeOne(); if (!$user) { return new Aphront404Response(); diff --git a/src/applications/people/engine/PhabricatorPeopleProfileMenuEngine.php b/src/applications/people/engine/PhabricatorPeopleProfileMenuEngine.php index e5f25eb4a0..6d6d239f5b 100644 --- a/src/applications/people/engine/PhabricatorPeopleProfileMenuEngine.php +++ b/src/applications/people/engine/PhabricatorPeopleProfileMenuEngine.php @@ -9,6 +9,7 @@ final class PhabricatorPeopleProfileMenuEngine const ITEM_BADGES = 'people.badges'; const ITEM_TASKS = 'people.tasks'; const ITEM_COMMITS = 'people.commits'; + const ITEM_REVISIONS = 'people.revisions'; protected function isMenuEngineConfigurable() { return false; @@ -52,6 +53,16 @@ final class PhabricatorPeopleProfileMenuEngine ->setMenuItemKey(PhabricatorPeopleTasksProfileMenuItem::MENUITEMKEY); } + $have_differential = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorDifferentialApplication', + $viewer); + if ($have_differential) { + $items[] = $this->newItem() + ->setBuiltinKey(self::ITEM_REVISIONS) + ->setMenuItemKey( + PhabricatorPeopleRevisionsProfileMenuItem::MENUITEMKEY); + } + $have_diffusion = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorDiffusionApplication', $viewer); diff --git a/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php b/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php new file mode 100644 index 0000000000..499fc1d7f4 --- /dev/null +++ b/src/applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php @@ -0,0 +1,59 @@ +getMenuItemProperty('name'); + + if (strlen($name)) { + return $name; + } + + return $this->getDefaultName(); + } + + public function buildEditEngineFields( + PhabricatorProfileMenuItemConfiguration $config) { + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setPlaceholder($this->getDefaultName()) + ->setValue($config->getMenuItemProperty('name')), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfileMenuItemConfiguration $config) { + + $user = $config->getProfileObject(); + $id = $user->getID(); + + $item = $this->newItem() + ->setHref("/people/revisions/{$id}/") + ->setName($this->getDisplayName($config)) + ->setIcon('fa-gear'); + + return array( + $item, + ); + } + +} From 179d80dd57f89424bc26097b7deb913f32717960 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Sat, 20 May 2017 15:34:07 -0700 Subject: [PATCH 15/61] Migrate Project lock to modular transactions Summary: See T12673 Test Plan: Unit tests pass. Locked and unlocked a project and saw timeline changes. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D17986 --- src/__phutil_library_map__.php | 2 + .../PhabricatorProjectLockController.php | 3 +- .../PhabricatorProjectTransactionEditor.php | 10 +--- .../storage/PhabricatorProjectTransaction.php | 51 +---------------- .../PhabricatorProjectLockTransaction.php | 56 +++++++++++++++++++ 5 files changed, 62 insertions(+), 60 deletions(-) create mode 100644 src/applications/project/xaction/PhabricatorProjectLockTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f6b66d9ab8..9b1841639c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3630,6 +3630,7 @@ phutil_register_library_map(array( 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php', 'PhabricatorProjectLockController' => 'applications/project/controller/PhabricatorProjectLockController.php', + 'PhabricatorProjectLockTransaction' => 'applications/project/xaction/PhabricatorProjectLockTransaction.php', 'PhabricatorProjectLogicalAncestorDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAncestorDatasource.php', 'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php', 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php', @@ -9048,6 +9049,7 @@ phutil_register_library_map(array( 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectListView' => 'AphrontView', 'PhabricatorProjectLockController' => 'PhabricatorProjectController', + 'PhabricatorProjectLockTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectLogicalAncestorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource', diff --git a/src/applications/project/controller/PhabricatorProjectLockController.php b/src/applications/project/controller/PhabricatorProjectLockController.php index b9b56bde10..a746911d45 100644 --- a/src/applications/project/controller/PhabricatorProjectLockController.php +++ b/src/applications/project/controller/PhabricatorProjectLockController.php @@ -49,7 +49,8 @@ final class PhabricatorProjectLockController } $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_LOCKED) + ->setTransactionType( + PhabricatorProjectLockTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); $editor = id(new PhabricatorProjectTransactionEditor()) diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 2f86afc1ac..47f451b037 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -30,7 +30,6 @@ final class PhabricatorProjectTransactionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; - $types[] = PhabricatorProjectTransaction::TYPE_LOCKED; $types[] = PhabricatorProjectTransaction::TYPE_PARENT; $types[] = PhabricatorProjectTransaction::TYPE_MILESTONE; $types[] = PhabricatorProjectTransaction::TYPE_HASWORKBOARD; @@ -46,8 +45,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_LOCKED: - return (int)$object->getIsMembershipLocked(); case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: return (int)$object->getHasWorkboard(); case PhabricatorProjectTransaction::TYPE_PARENT: @@ -69,7 +66,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_LOCKED: case PhabricatorProjectTransaction::TYPE_PARENT: case PhabricatorProjectTransaction::TYPE_MILESTONE: case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: @@ -93,9 +89,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_LOCKED: - $object->setIsMembershipLocked($xaction->getNewValue()); - return; case PhabricatorProjectTransaction::TYPE_PARENT: $object->setParentProjectPHID($xaction->getNewValue()); return; @@ -129,7 +122,6 @@ final class PhabricatorProjectTransactionEditor $new = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_LOCKED: case PhabricatorProjectTransaction::TYPE_PARENT: case PhabricatorProjectTransaction::TYPE_MILESTONE: case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: @@ -320,7 +312,7 @@ final class PhabricatorProjectTransactionEditor $object, PhabricatorPolicyCapability::CAN_EDIT); return; - case PhabricatorProjectTransaction::TYPE_LOCKED: + case PhabricatorProjectLockTransaction::TRANSACTIONTYPE: PhabricatorPolicyFilter::requireCapability( $this->requireActor(), newv($this->getEditorApplicationClass(), array()), diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index b0d442ae57..f0a9966646 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -3,7 +3,6 @@ final class PhabricatorProjectTransaction extends PhabricatorModularTransaction { - const TYPE_LOCKED = 'project:locked'; const TYPE_PARENT = 'project:parent'; const TYPE_MILESTONE = 'project:milestone'; const TYPE_HASWORKBOARD = 'project:hasworkboard'; @@ -87,16 +86,7 @@ final class PhabricatorProjectTransaction } public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - switch ($this->getTransactionType()) { - case self::TYPE_LOCKED: - if ($new) { - return 'fa-lock'; - } else { - return 'fa-unlock'; - } case self::TYPE_MEMBERS: return 'fa-user'; } @@ -115,18 +105,6 @@ final class PhabricatorProjectTransaction '%s created this project.', $this->renderHandleLink($author_phid)); - case self::TYPE_LOCKED: - if ($new) { - return pht( - "%s locked this project's membership.", - $author_handle); - } else { - return pht( - "%s unlocked this project's membership.", - $author_handle); - } - break; - case self::TYPE_MEMBERS: $add = array_diff($new, $old); $rem = array_diff($old, $new); @@ -196,33 +174,6 @@ final class PhabricatorProjectTransaction return parent::getTitle(); } - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - $author_handle = $this->renderHandleLink($author_phid); - $object_handle = $this->renderHandleLink($object_phid); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_LOCKED: - if ($new) { - return pht( - '%s locked membership for %s.', - $author_handle, - $object_handle); - } else { - return pht( - '%s unlocked membership for %s.', - $author_handle, - $object_handle); - } - } - - return parent::getTitleForFeed(); - } - public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { @@ -247,7 +198,7 @@ final class PhabricatorProjectTransaction } break; case PhabricatorProjectStatusTransaction::TRANSACTIONTYPE: - case self::TYPE_LOCKED: + case PhabricatorProjectLockTransaction::TRANSACTIONTYPE: default: $tags[] = self::MAILTAG_OTHER; break; diff --git a/src/applications/project/xaction/PhabricatorProjectLockTransaction.php b/src/applications/project/xaction/PhabricatorProjectLockTransaction.php new file mode 100644 index 0000000000..42551dfb2c --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectLockTransaction.php @@ -0,0 +1,56 @@ +getIsMembershipLocked(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsMembershipLocked($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + "%s locked this project's membership.", + $this->renderAuthor()); + } else { + return pht( + "%s unlocked this project's membership.", + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s locked %s membership.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s unlocked %s membership.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + + if ($new) { + return 'fa-lock'; + } else { + return 'fa-unlock'; + } + } + +} From 5d966897f14ae9593bf6d85174da565a84150c8b Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 10:03:30 -0700 Subject: [PATCH 16/61] Add Outline tag type to PHUITagView Summary: Adds a new tag type, starts to try to clean up the mess that are PHUITags Test Plan: Review UIExamples. {F4972323} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17991 --- resources/celerity/map.php | 6 +- .../phid/PhabricatorObjectHandle.php | 4 +- .../phid/view/PHUIHandleTagListView.php | 4 +- .../uiexample/examples/PHUITagExample.php | 34 +++- src/view/phui/PHUITagView.php | 53 +++++- webroot/rsrc/css/phui/phui-tag-view.css | 173 ++++++++++++++---- 6 files changed, 216 insertions(+), 58 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 26ebc596f3..0649f9dbc0 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '5ffe8b79', + 'core.pkg.css' => '6e9cf0af', 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -172,7 +172,7 @@ return array( 'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892', 'rsrc/css/phui/phui-spacing.css' => '042804d6', 'rsrc/css/phui/phui-status.css' => 'd5263e49', - 'rsrc/css/phui/phui-tag-view.css' => 'cc4fd402', + 'rsrc/css/phui/phui-tag-view.css' => '3fa7765e', 'rsrc/css/phui/phui-timeline-view.css' => '313c7f22', 'rsrc/css/phui/phui-two-column-view.css' => 'ce9fa0b7', 'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5', @@ -882,7 +882,7 @@ return array( 'phui-segment-bar-view-css' => 'b1d1b892', 'phui-spacing-css' => '042804d6', 'phui-status-list-view-css' => 'd5263e49', - 'phui-tag-view-css' => 'cc4fd402', + 'phui-tag-view-css' => '3fa7765e', 'phui-theme-css' => '9f261c6b', 'phui-timeline-view-css' => '313c7f22', 'phui-two-column-view-css' => 'ce9fa0b7', diff --git a/src/applications/phid/PhabricatorObjectHandle.php b/src/applications/phid/PhabricatorObjectHandle.php index 49255fd9e8..1e6812b53b 100644 --- a/src/applications/phid/PhabricatorObjectHandle.php +++ b/src/applications/phid/PhabricatorObjectHandle.php @@ -407,8 +407,8 @@ final class PhabricatorObjectHandle public function renderTag() { return id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setShade($this->getTagColor()) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor($this->getTagColor()) ->setIcon($this->getIcon()) ->setHref($this->getURI()) ->setName($this->getLinkName()); diff --git a/src/applications/phid/view/PHUIHandleTagListView.php b/src/applications/phid/view/PHUIHandleTagListView.php index c4ef3762c3..abae359a16 100644 --- a/src/applications/phid/view/PHUIHandleTagListView.php +++ b/src/applications/phid/view/PHUIHandleTagListView.php @@ -121,8 +121,8 @@ final class PHUIHandleTagListView extends AphrontTagView { private function newPlaceholderTag() { return id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setShade(PHUITagView::COLOR_DISABLED) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor(PHUITagView::COLOR_DISABLED) ->setSlimShady($this->slim); } diff --git a/src/applications/uiexample/examples/PHUITagExample.php b/src/applications/uiexample/examples/PHUITagExample.php index 155fe4e9da..764caaf717 100644 --- a/src/applications/uiexample/examples/PHUITagExample.php +++ b/src/applications/uiexample/examples/PHUITagExample.php @@ -162,15 +162,15 @@ final class PHUITagExample extends PhabricatorUIExample { $tags = array(); foreach ($shades as $shade) { $tags[] = id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setShade($shade) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor($shade) ->setIcon('fa-tags') ->setName(ucwords($shade)) ->setHref('#'); $tags[] = hsprintf(' '); $tags[] = id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setShade($shade) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor($shade) ->setSlimShady(true) ->setIcon('fa-tags') ->setName(ucwords($shade)) @@ -182,6 +182,26 @@ final class PHUITagExample extends PhabricatorUIExample { ->appendChild($tags) ->addPadding(PHUI::PADDING_LARGE); + $outlines = PHUITagView::getOutlines(); + $tags = array(); + foreach ($outlines as $outline) { + $tags[] = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_OUTLINE) + ->setShade($outline) + ->setName($outline); + $tags[] = hsprintf(' '); + $tags[] = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_OUTLINE) + ->setShade($outline) + ->setSlimShady(true) + ->setName($outline); + $tags[] = hsprintf('

'); + } + + $content5 = id(new PHUIBoxView()) + ->appendChild($tags) + ->addPadding(PHUI::PADDING_LARGE); + $box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Inline')) ->appendChild($intro); @@ -202,6 +222,10 @@ final class PHUITagExample extends PhabricatorUIExample { ->setHeaderText(pht('Shades')) ->appendChild($content4); - return array($box, $box1, $box2, $box3, $box4); + $box5 = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Outlines')) + ->appendChild($content5); + + return array($box, $box1, $box2, $box3, $box4, $box5); } } diff --git a/src/view/phui/PHUITagView.php b/src/view/phui/PHUITagView.php index ae80fc1731..e8d30e935e 100644 --- a/src/view/phui/PHUITagView.php +++ b/src/view/phui/PHUITagView.php @@ -6,6 +6,7 @@ final class PHUITagView extends AphrontTagView { const TYPE_OBJECT = 'object'; const TYPE_STATE = 'state'; const TYPE_SHADE = 'shade'; + const TYPE_OUTLINE = 'outline'; const COLOR_RED = 'red'; const COLOR_ORANGE = 'orange'; @@ -15,6 +16,8 @@ final class PHUITagView extends AphrontTagView { const COLOR_VIOLET = 'violet'; const COLOR_GREEN = 'green'; const COLOR_BLACK = 'black'; + const COLOR_SKY = 'sky'; + const COLOR_FIRE = 'fire'; const COLOR_GREY = 'grey'; const COLOR_WHITE = 'white'; const COLOR_PINK = 'pink'; @@ -29,6 +32,7 @@ final class PHUITagView extends AphrontTagView { private $href; private $name; private $phid; + private $color; private $backgroundColor; private $dotColor; private $closed; @@ -41,6 +45,7 @@ final class PHUITagView extends AphrontTagView { $this->type = $type; switch ($type) { case self::TYPE_SHADE: + case self::TYPE_OUTLINE: break; case self::TYPE_OBJECT: $this->setBackgroundColor(self::COLOR_OBJECT); @@ -52,8 +57,14 @@ final class PHUITagView extends AphrontTagView { return $this; } + /* Deprecated, use setColor */ public function setShade($shade) { - $this->shade = $shade; + $this->color = $shade; + return $this; + } + + public function setColor($color) { + $this->color = $color; return $this; } @@ -109,12 +120,16 @@ final class PHUITagView extends AphrontTagView { 'phui-tag-type-'.$this->type, ); - if ($this->shade) { + if ($this->color) { + $classes[] = 'phui-tag-'.$this->color; + } + + if ($this->slimShady) { + $classes[] = 'phui-tag-slim'; + } + + if ($this->type == self::TYPE_SHADE) { $classes[] = 'phui-tag-shade'; - $classes[] = 'phui-tag-shade-'.$this->shade; - if ($this->slimShady) { - $classes[] = 'phui-tag-shade-slim'; - } } if ($this->icon) { @@ -240,6 +255,32 @@ final class PHUITagView extends AphrontTagView { return idx(self::getShadeMap(), $shade, $shade); } + public static function getOutlines() { + return array_keys(self::getOutlineMap()); + } + + public static function getOutlineMap() { + return array( + self::COLOR_RED => pht('Red'), + self::COLOR_ORANGE => pht('Orange'), + self::COLOR_YELLOW => pht('Yellow'), + self::COLOR_BLUE => pht('Blue'), + self::COLOR_INDIGO => pht('Indigo'), + self::COLOR_VIOLET => pht('Violet'), + self::COLOR_GREEN => pht('Green'), + self::COLOR_GREY => pht('Grey'), + self::COLOR_PINK => pht('Pink'), + self::COLOR_SKY => pht('Sky'), + self::COLOR_FIRE => pht('Fire'), + self::COLOR_BLACK => pht('Black'), + self::COLOR_DISABLED => pht('Disabled'), + ); + } + + public static function getOutlineName($outline) { + return idx(self::getOutlineMap(), $outline, $outline); + } + public function setExternal($external) { $this->external = $external; diff --git a/webroot/rsrc/css/phui/phui-tag-view.css b/webroot/rsrc/css/phui/phui-tag-view.css index d5b2710d7b..56b5badf8d 100644 --- a/webroot/rsrc/css/phui/phui-tag-view.css +++ b/webroot/rsrc/css/phui/phui-tag-view.css @@ -161,225 +161,233 @@ a.phui-tag-view:hover */ -.phui-tag-shade { +.phui-tag-view.phui-tag-type-shade { font-weight: normal; } -.phui-tag-shade .phui-icon-view { +.phui-tag-view.phui-tag-type-shade .phui-icon-view { font-size: 12px; } -.phui-tag-shade-slim .phui-icon-view { + +/* - Slim Tags ----------------------------------------------------------------- + + A thinner tag for object list, workboards. + +*/ + +.phui-tag-slim .phui-icon-view { font-size: 11px; } -.phui-tag-shade-slim .phui-tag-core { +.phui-tag-slim .phui-tag-core { font-size: {$smallerfontsize}; } + /* - Red -------------------------------------------------------------------- */ -.phui-tag-shade-red .phui-tag-core, +.phui-tag-red .phui-tag-core, .jx-tokenizer-token.red { background: {$sh-redbackground}; border-color: {$sh-lightredborder}; color: {$sh-redtext}; } -.phui-tag-shade-red .phui-icon-view, +.phui-tag-red .phui-icon-view, .jx-tokenizer-token.red .phui-icon-view, .jx-tokenizer-token.red .jx-tokenizer-x { color: {$sh-redicon}; } -a.phui-tag-view:hover.phui-tag-shade-red .phui-tag-core, +a.phui-tag-view:hover.phui-tag-red .phui-tag-core, .jx-tokenizer-token.red:hover { border-color: {$sh-redborder}; } /* - Orange ----------------------------------------------------------------- */ -.phui-tag-shade-orange .phui-tag-core, +.phui-tag-orange .phui-tag-core, .jx-tokenizer-token.orange { background: {$sh-orangebackground}; border-color: {$sh-lightorangeborder}; color: {$sh-orangetext}; } -.phui-tag-shade-orange .phui-icon-view, +.phui-tag-orange .phui-icon-view, .jx-tokenizer-token.orange .phui-icon-view, .jx-tokenizer-token.orange .jx-tokenizer-x { color: {$sh-orangeicon}; } -a.phui-tag-view:hover.phui-tag-shade-orange .phui-tag-core, +a.phui-tag-view:hover.phui-tag-orange .phui-tag-core, .jx-tokenizer-token.orange:hover { border-color: {$sh-orangeborder}; } /* - Yellow ----------------------------------------------------------------- */ -.phui-tag-shade-yellow .phui-tag-core, +.phui-tag-yellow .phui-tag-core, .jx-tokenizer-token.yellow { background: {$sh-yellowbackground}; border-color: {$sh-lightyellowborder}; color: {$sh-yellowtext}; } -.phui-tag-shade-yellow .phui-icon-view, +.phui-tag-yellow .phui-icon-view, .jx-tokenizer-token.yellow .phui-icon-view, .jx-tokenizer-token.yellow .jx-tokenizer-x { color: {$sh-yellowicon}; } -a.phui-tag-view:hover.phui-tag-shade-yellow .phui-tag-core, +a.phui-tag-view:hover.phui-tag-yellow .phui-tag-core, .jx-tokenizer-token.yellow:hover { border-color: {$sh-yellowborder}; } /* - Blue ------------------------------------------------------------------- */ -.phui-tag-shade-blue .phui-tag-core, +.phui-tag-blue .phui-tag-core, .jx-tokenizer-token.blue { background: {$sh-bluebackground}; border-color: {$sh-lightblueborder}; color: {$sh-bluetext}; } -.phui-tag-shade-blue .phui-icon-view, +.phui-tag-blue .phui-icon-view, .jx-tokenizer-token.blue .phui-icon-view, .jx-tokenizer-token.blue .jx-tokenizer-x { color: {$sh-blueicon}; } -a.phui-tag-view:hover.phui-tag-shade-blue .phui-tag-core, +a.phui-tag-view:hover.phui-tag-blue .phui-tag-core, .jx-tokenizer-token.blue:hover { border-color: {$sh-blueborder}; } /* - Sky ------------------------------------------------------------------- */ -.phui-tag-shade-sky .phui-tag-core, +.phui-tag-sky .phui-tag-core, .jx-tokenizer-token.sky { background: #E0F0FA; border-color: {$sh-lightblueborder}; color: {$sh-bluetext}; } -.phui-tag-shade-sky .phui-icon-view, +.phui-tag-sky .phui-icon-view, .jx-tokenizer-token.sky .phui-icon-view, .jx-tokenizer-token.sky .jx-tokenizer-x { color: {$sh-blueicon}; } -a.phui-tag-view:hover.phui-tag-shade-sky .phui-tag-core, +a.phui-tag-view:hover.phui-tag-sky .phui-tag-core, .jx-tokenizer-token.sky:hover { border-color: {$sh-blueborder}; } /* - Indigo ----------------------------------------------------------------- */ -.phui-tag-shade-indigo .phui-tag-core, +.phui-tag-indigo .phui-tag-core, .jx-tokenizer-token.indigo { background: {$sh-indigobackground}; border-color: {$sh-lightindigoborder}; color: {$sh-indigotext}; } -.phui-tag-shade-indigo .phui-icon-view, +.phui-tag-indigo .phui-icon-view, .jx-tokenizer-token.indigo .phui-icon-view, .jx-tokenizer-token.indigo .jx-tokenizer-x { color: {$sh-indigoicon}; } -a.phui-tag-view:hover.phui-tag-shade-indigo .phui-tag-core, +a.phui-tag-view:hover.phui-tag-indigo .phui-tag-core, .jx-tokenizer-token.indigo:hover { border-color: {$sh-indigoborder}; } /* - Green ------------------------------------------------------------------ */ -.phui-tag-shade-green .phui-tag-core, +.phui-tag-green .phui-tag-core, .jx-tokenizer-token.green { background: {$sh-greenbackground}; border-color: {$sh-lightgreenborder}; color: {$sh-greentext}; } -.phui-tag-shade-green .phui-icon-view, +.phui-tag-green .phui-icon-view, .jx-tokenizer-token.green .phui-icon-view, .jx-tokenizer-token.green .jx-tokenizer-x { color: {$sh-greenicon}; } -a.phui-tag-view:hover.phui-tag-shade-green .phui-tag-core, +a.phui-tag-view:hover.phui-tag-green .phui-tag-core, .jx-tokenizer-token.green:hover { border-color: {$sh-greenborder}; } /* - Violet ----------------------------------------------------------------- */ -.phui-tag-shade-violet .phui-tag-core, +.phui-tag-violet .phui-tag-core, .jx-tokenizer-token.violet { background: {$sh-violetbackground}; border-color: {$sh-lightvioletborder}; color: {$sh-violettext}; } -.phui-tag-shade-violet .phui-icon-view, +.phui-tag-violet .phui-icon-view, .jx-tokenizer-token.violet .phui-icon-view, .jx-tokenizer-token.violet .jx-tokenizer-x { color: {$sh-violeticon}; } -a.phui-tag-view:hover.phui-tag-shade-violet .phui-tag-core, +a.phui-tag-view:hover.phui-tag-violet .phui-tag-core, .jx-tokenizer-token.violet:hover { border-color: {$sh-violetborder}; } /* - Pink ------------------------------------------------------------------- */ -.phui-tag-shade-pink .phui-tag-core, +.phui-tag-pink .phui-tag-core, .jx-tokenizer-token.pink { background: {$sh-pinkbackground}; border-color: {$sh-lightpinkborder}; color: {$sh-pinktext}; } -.phui-tag-shade-pink .phui-icon-view, +.phui-tag-pink .phui-icon-view, .jx-tokenizer-token.pink .phui-icon-view, .jx-tokenizer-token.pink .jx-tokenizer-x { color: {$sh-pinkicon}; } -a.phui-tag-view:hover.phui-tag-shade-pink .phui-tag-core, +a.phui-tag-view:hover.phui-tag-pink .phui-tag-core, .jx-tokenizer-token.pink:hover { border-color: {$sh-pinkborder}; } /* - Grey ------------------------------------------------------------------- */ -.phui-tag-shade-grey .phui-tag-core, +.phui-tag-grey .phui-tag-core, .jx-tokenizer-token.grey { background: {$sh-greybackground}; border-color: {$sh-lightgreyborder}; color: {$sh-greytext}; } -.phui-tag-shade-grey .phui-icon-view, +.phui-tag-grey .phui-icon-view, .jx-tokenizer-token.grey .phui-icon-view, .jx-tokenizer-token.grey .jx-tokenizer-x { color: {$sh-greyicon}; } -a.phui-tag-view:hover.phui-tag-shade-grey .phui-tag-core, +a.phui-tag-view:hover.phui-tag-grey .phui-tag-core, .jx-tokenizer-token.grey:hover { border-color: {$sh-greyborder}; } /* - Checkered -------------------------------------------------------------- */ -.phui-tag-shade-checkered .phui-tag-core, +.phui-tag-checkered .phui-tag-core, .jx-tokenizer-token.checkered { background: url(/rsrc/image/checker_lighter.png); border-style: dashed; @@ -388,13 +396,13 @@ a.phui-tag-view:hover.phui-tag-shade-grey .phui-tag-core, text-shadow: 1px 1px #fff; } -.phui-tag-shade-checkered .phui-icon-view, +.phui-tag-checkered .phui-icon-view, .jx-tokenizer-token.checkered .phui-icon-view, .jx-tokenizer-token.checkered .jx-tokenizer-x { color: {$sh-greyicon}; } -a.phui-tag-view:hover.phui-tag-shade-checkered .phui-tag-core, +a.phui-tag-view:hover.phui-tag-checkered .phui-tag-core, .jx-tokenizer-token.checkered:hover { border-style: solid; border-color: {$sh-greyborder}; @@ -402,16 +410,101 @@ a.phui-tag-view:hover.phui-tag-shade-checkered .phui-tag-core, /* - Disabled --------------------------------------------------------------- */ -.phui-tag-shade-disabled .phui-tag-core { +.phui-tag-disabled .phui-tag-core { background-color: {$sh-disabledbackground}; border-color: {$sh-lightdisabledborder}; color: {$sh-disabledtext}; } -.phui-tag-shade-disabled .phui-icon-view { +.phui-tag-disabled .phui-icon-view { color: {$sh-disabledicon}; } -a.phui-tag-view:hover.phui-tag-shade-disabled .phui-tag-core { +a.phui-tag-view:hover.phui-tag-disabled .phui-tag-core { border-color: {$sh-disabledborder}; } + +/* - Outline Tags -------------------------------------------------------------- + + Basic Tag with a bold border and white background + +*/ + +.phui-tag-type-outline { + text-transform: uppercase; + font-weight: normal; +} + +.phui-tag-view.phui-tag-type-outline .phui-tag-core { + background: #fff; + padding: 0 6px 1px 6px; +} + +.phui-tag-slim.phui-tag-type-outline .phui-tag-core { + font-size: {$smallestfontsize}; +} + +.phui-tag-type-outline.phui-tag-red .phui-tag-core { + color: {$red}; + border-color: {$red}; +} + +.phui-tag-type-outline.phui-tag-orange .phui-tag-core { + color: {$orange}; + border-color: {$orange}; +} + +.phui-tag-type-outline.phui-tag-yellow .phui-tag-core { + color: {$yellow}; + border-color: {$yellow}; +} + +.phui-tag-type-outline.phui-tag-green .phui-tag-core { + color: {$green}; + border-color: {$green}; +} + +.phui-tag-type-outline.phui-tag-blue .phui-tag-core { + color: {$blue}; + border-color: {$blue}; +} + +.phui-tag-type-outline.phui-tag-indigo .phui-tag-core { + color: {$indigo}; + border-color: {$indigo}; +} + +.phui-tag-type-outline.phui-tag-violet .phui-tag-core { + color: {$violet}; + border-color: {$violet}; +} + +.phui-tag-type-outline.phui-tag-grey .phui-tag-core { + color: {$bluetext}; + border-color: {$bluetext}; +} + +.phui-tag-type-outline.phui-tag-disabled .phui-tag-core { + color: {$lightgreytext}; + border-color: {$lightgreytext}; +} + +.phui-tag-type-outline.phui-tag-pink .phui-tag-core { + color: {$pink}; + border-color: {$pink}; +} + +.phui-tag-type-outline.phui-tag-sky .phui-tag-core { + color: {$sky}; + border-color: {$sky}; +} + +.phui-tag-type-outline.phui-tag-fire .phui-tag-core { + color: {$fire}; + border-color: {$fire}; +} + +.phui-tag-type-outline.phui-tag-black .phui-tag-core { + color: #000; + border-color: #000; +} From 03d4d674f8033300be2c55feb1bf415f3cd7b25f Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 10:47:19 -0700 Subject: [PATCH 17/61] Clean up some colors missing from PHUITagView type shade Summary: Grep for phui-tag-shade and verify we're no longer calling shade-color directly. Test Plan: Search, workboard, story points, etc. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17993 --- resources/celerity/map.php | 22 +++++++++---------- ...PhabricatorCalendarEventViewController.php | 2 +- .../controller/DiffusionController.php | 2 +- .../ManiphestTaskDetailController.php | 2 +- .../css/application/search/search-results.css | 2 +- webroot/rsrc/css/phui/phui-header-view.css | 2 +- .../application/projects/WorkboardColumn.js | 6 ++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 0649f9dbc0..2415f90ff1 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '6e9cf0af', + 'core.pkg.css' => '5387f8b6', 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -109,7 +109,7 @@ return array( 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', 'rsrc/css/application/search/application-search-view.css' => '66ee5d46', - 'rsrc/css/application/search/search-results.css' => 'f87d23ad', + 'rsrc/css/application/search/search-results.css' => '8f8e08ed', 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', @@ -154,7 +154,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => '6175808d', 'rsrc/css/phui/phui-form.css' => 'a5570f70', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => 'e082678d', + 'rsrc/css/phui/phui-header-view.css' => 'a3d1aecd', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '12b387a1', @@ -433,7 +433,7 @@ return array( 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c', 'rsrc/js/application/projects/WorkboardBoard.js' => '8935deef', 'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f', - 'rsrc/js/application/projects/WorkboardColumn.js' => '21df4ff5', + 'rsrc/js/application/projects/WorkboardColumn.js' => '758b4758', 'rsrc/js/application/projects/WorkboardController.js' => '26167537', 'rsrc/js/application/projects/behavior-project-boards.js' => '4250a34e', 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', @@ -754,7 +754,7 @@ return array( 'javelin-websocket' => '3ffe32d6', 'javelin-workboard-board' => '8935deef', 'javelin-workboard-card' => 'c587b80f', - 'javelin-workboard-column' => '21df4ff5', + 'javelin-workboard-column' => '758b4758', 'javelin-workboard-controller' => '26167537', 'javelin-workflow' => '1e911d0f', 'maniphest-batch-editor' => 'b0f0b6d5', @@ -801,7 +801,7 @@ return array( 'phabricator-remarkup-css' => 'd1a5e11e', 'phabricator-scroll-objective' => '7e8877e7', 'phabricator-scroll-objective-list' => '6120e99a', - 'phabricator-search-results-css' => 'f87d23ad', + 'phabricator-search-results-css' => '8f8e08ed', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', 'phabricator-source-code-view-css' => '4383192f', @@ -856,7 +856,7 @@ return array( 'phui-form-css' => 'a5570f70', 'phui-form-view-css' => '6175808d', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => 'e082678d', + 'phui-header-view-css' => 'a3d1aecd', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', @@ -1060,10 +1060,6 @@ return array( 'javelin-install', 'javelin-dom', ), - '21df4ff5' => array( - 'javelin-install', - 'javelin-workboard-card', - ), '2290aeef' => array( 'javelin-install', 'javelin-dom', @@ -1464,6 +1460,10 @@ return array( 'javelin-vector', 'javelin-dom', ), + '758b4758' => array( + 'javelin-install', + 'javelin-workboard-card', + ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php index 91d3a9e336..3ba3aa1e70 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php @@ -125,7 +125,7 @@ final class PhabricatorCalendarEventViewController ->setName(pht('Imported')) ->setIcon('fa-download') ->setHref($event->getImportSource()->getURI()) - ->setShade('orange')); + ->setColor(PHUITagView::COLOR_ORANGE)); } foreach ($this->buildRSVPActions($event) as $action) { diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index a018eb3dbb..a296761bdf 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -332,7 +332,7 @@ abstract class DiffusionController extends PhabricatorController { $tag = id(new PHUITagView()) ->setName($commit) - ->setShade('indigo') + ->setColor(PHUITagView::COLOR_INDIGO) ->setType(PHUITagView::TYPE_SHADE); return $tag; diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 5384825de8..7859599a2f 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -233,7 +233,7 @@ final class ManiphestTaskDetailController extends ManiphestController { ManiphestTaskPoints::getPointsLabel()); $tag = id(new PHUITagView()) ->setName($points_name) - ->setShade('blue') + ->setColor(PHUITagView::COLOR_BLUE) ->setType(PHUITagView::TYPE_SHADE); $view->addTag($tag); diff --git a/webroot/rsrc/css/application/search/search-results.css b/webroot/rsrc/css/application/search/search-results.css index a1837fa391..0f0a31a1b9 100644 --- a/webroot/rsrc/css/application/search/search-results.css +++ b/webroot/rsrc/css/application/search/search-results.css @@ -26,6 +26,6 @@ margin: 0 2px; } -.phui-fulltext-tokens .phui-tag-view.phui-tag-shade-grey { +.phui-fulltext-tokens .phui-tag-view.phui-tag-grey { opacity: 0.5; } diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index 5c24d5575e..470e821544 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -353,7 +353,7 @@ body .phui-header-shell.phui-bleed-header vertical-align: top; } -.phui-header-view .phui-tag-shade-indigo a { +.phui-header-view .phui-tag-indigo a { color: {$sh-indigotext}; } diff --git a/webroot/rsrc/js/application/projects/WorkboardColumn.js b/webroot/rsrc/js/application/projects/WorkboardColumn.js index 81fba84077..9973648593 100644 --- a/webroot/rsrc/js/application/projects/WorkboardColumn.js +++ b/webroot/rsrc/js/application/projects/WorkboardColumn.js @@ -285,9 +285,9 @@ JX.install('WorkboardColumn', { JX.DOM.alterClass(panel, 'project-panel-over-limit', over_limit); var color_map = { - 'phui-tag-shade-disabled': (total_points === 0), - 'phui-tag-shade-blue': (total_points > 0 && !over_limit), - 'phui-tag-shade-red': (over_limit) + 'phui-tag-disabled': (total_points === 0), + 'phui-tag-blue': (total_points > 0 && !over_limit), + 'phui-tag-red': (over_limit) }; for (var c in color_map) { From 1069c2bff9d3686465fd2802b6165bcbc2b2d8c0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 22 May 2017 08:45:52 -0700 Subject: [PATCH 18/61] Convert Nuance Items to Modular Transactions Summary: Ref T12738. Moves existing non-modular transactions to modular transactions. Some of these are pretty flimsy, but a lot of them don't actually work or do anything in Nuance yet anyway. Test Plan: Gently poked Nuance, nothing fell over. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D17990 --- src/__phutil_library_map__.php | 20 +++- .../nuance/editor/NuanceItemEditor.php | 94 ------------------- .../nuance/item/NuanceItemType.php | 2 +- .../nuance/source/NuanceSourceDefinition.php | 7 +- .../nuance/storage/NuanceItemTransaction.php | 64 +------------ .../nuance/storage/NuanceQueueTransaction.php | 4 + .../storage/NuanceSourceTransaction.php | 4 + .../nuance/storage/NuanceTransaction.php | 2 +- .../xaction/NuanceItemCommandTransaction.php | 22 +++++ .../xaction/NuanceItemOwnerTransaction.php | 27 ++++++ .../xaction/NuanceItemPropertyTransaction.php | 27 ++++++ .../xaction/NuanceItemQueueTransaction.php | 25 +++++ .../NuanceItemRequestorTransaction.php | 16 ++++ .../xaction/NuanceItemSourceTransaction.php | 16 ++++ .../xaction/NuanceItemTransactionType.php | 4 + .../xaction/NuanceQueueTransactionType.php | 4 + .../xaction/NuanceSourceTransactionType.php | 4 + 17 files changed, 180 insertions(+), 162 deletions(-) create mode 100644 src/applications/nuance/xaction/NuanceItemCommandTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemOwnerTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemPropertyTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemQueueTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemRequestorTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemSourceTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceItemTransactionType.php create mode 100644 src/applications/nuance/xaction/NuanceQueueTransactionType.php create mode 100644 src/applications/nuance/xaction/NuanceSourceTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9b1841639c..9831b24686 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1620,16 +1620,23 @@ phutil_register_library_map(array( 'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php', 'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php', 'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php', + 'NuanceItemCommandTransaction' => 'applications/nuance/xaction/NuanceItemCommandTransaction.php', 'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php', 'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php', 'NuanceItemListController' => 'applications/nuance/controller/NuanceItemListController.php', 'NuanceItemManageController' => 'applications/nuance/controller/NuanceItemManageController.php', + 'NuanceItemOwnerTransaction' => 'applications/nuance/xaction/NuanceItemOwnerTransaction.php', 'NuanceItemPHIDType' => 'applications/nuance/phid/NuanceItemPHIDType.php', + 'NuanceItemPropertyTransaction' => 'applications/nuance/xaction/NuanceItemPropertyTransaction.php', 'NuanceItemQuery' => 'applications/nuance/query/NuanceItemQuery.php', + 'NuanceItemQueueTransaction' => 'applications/nuance/xaction/NuanceItemQueueTransaction.php', + 'NuanceItemRequestorTransaction' => 'applications/nuance/xaction/NuanceItemRequestorTransaction.php', 'NuanceItemSearchEngine' => 'applications/nuance/query/NuanceItemSearchEngine.php', + 'NuanceItemSourceTransaction' => 'applications/nuance/xaction/NuanceItemSourceTransaction.php', 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', + 'NuanceItemTransactionType' => 'applications/nuance/xaction/NuanceItemTransactionType.php', 'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php', 'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php', 'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php', @@ -1651,6 +1658,7 @@ phutil_register_library_map(array( 'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php', 'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php', 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', + 'NuanceQueueTransactionType' => 'applications/nuance/xaction/NuanceQueueTransactionType.php', 'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php', 'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php', 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', @@ -1672,6 +1680,7 @@ phutil_register_library_map(array( 'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php', 'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php', 'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php', + 'NuanceSourceTransactionType' => 'applications/nuance/xaction/NuanceSourceTransactionType.php', 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', 'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php', @@ -6720,16 +6729,23 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', ), 'NuanceItemCommandQuery' => 'NuanceQuery', + 'NuanceItemCommandTransaction' => 'NuanceItemTransactionType', 'NuanceItemController' => 'NuanceController', 'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceItemListController' => 'NuanceItemController', 'NuanceItemManageController' => 'NuanceController', + 'NuanceItemOwnerTransaction' => 'NuanceItemTransactionType', 'NuanceItemPHIDType' => 'PhabricatorPHIDType', + 'NuanceItemPropertyTransaction' => 'NuanceItemTransactionType', 'NuanceItemQuery' => 'NuanceQuery', + 'NuanceItemQueueTransaction' => 'NuanceItemTransactionType', + 'NuanceItemRequestorTransaction' => 'NuanceItemTransactionType', 'NuanceItemSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'NuanceItemSourceTransaction' => 'NuanceItemTransactionType', 'NuanceItemTransaction' => 'NuanceTransaction', 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'NuanceItemTransactionType' => 'PhabricatorModularTransactionType', 'NuanceItemType' => 'Phobject', 'NuanceItemUpdateWorker' => 'NuanceWorker', 'NuanceItemViewController' => 'NuanceController', @@ -6755,6 +6771,7 @@ phutil_register_library_map(array( 'NuanceQueueTransaction' => 'NuanceTransaction', 'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'NuanceQueueTransactionType' => 'PhabricatorModularTransactionType', 'NuanceQueueViewController' => 'NuanceQueueController', 'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'NuanceSource' => array( @@ -6781,8 +6798,9 @@ phutil_register_library_map(array( 'NuanceSourceTransaction' => 'NuanceTransaction', 'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'NuanceSourceTransactionType' => 'PhabricatorModularTransactionType', 'NuanceSourceViewController' => 'NuanceSourceController', - 'NuanceTransaction' => 'PhabricatorApplicationTransaction', + 'NuanceTransaction' => 'PhabricatorModularTransaction', 'NuanceWorker' => 'PhabricatorWorker', 'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', diff --git a/src/applications/nuance/editor/NuanceItemEditor.php b/src/applications/nuance/editor/NuanceItemEditor.php index 45288052c2..b41ca77563 100644 --- a/src/applications/nuance/editor/NuanceItemEditor.php +++ b/src/applications/nuance/editor/NuanceItemEditor.php @@ -14,104 +14,10 @@ final class NuanceItemEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = NuanceItemTransaction::TYPE_OWNER; - $types[] = NuanceItemTransaction::TYPE_SOURCE; - $types[] = NuanceItemTransaction::TYPE_REQUESTOR; - $types[] = NuanceItemTransaction::TYPE_PROPERTY; - $types[] = NuanceItemTransaction::TYPE_QUEUE; - $types[] = NuanceItemTransaction::TYPE_COMMAND; - - $types[] = PhabricatorTransactions::TYPE_EDGE; - $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceItemTransaction::TYPE_REQUESTOR: - return $object->getRequestorPHID(); - case NuanceItemTransaction::TYPE_SOURCE: - return $object->getSourcePHID(); - case NuanceItemTransaction::TYPE_OWNER: - return $object->getOwnerPHID(); - case NuanceItemTransaction::TYPE_QUEUE: - return $object->getQueuePHID(); - case NuanceItemTransaction::TYPE_PROPERTY: - $key = $xaction->getMetadataValue( - NuanceItemTransaction::PROPERTY_KEY); - return $object->getNuanceProperty($key); - case NuanceItemTransaction::TYPE_COMMAND: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceItemTransaction::TYPE_REQUESTOR: - case NuanceItemTransaction::TYPE_SOURCE: - case NuanceItemTransaction::TYPE_OWNER: - case NuanceItemTransaction::TYPE_PROPERTY: - case NuanceItemTransaction::TYPE_QUEUE: - case NuanceItemTransaction::TYPE_COMMAND: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceItemTransaction::TYPE_REQUESTOR: - $object->setRequestorPHID($xaction->getNewValue()); - break; - case NuanceItemTransaction::TYPE_SOURCE: - $object->setSourcePHID($xaction->getNewValue()); - break; - case NuanceItemTransaction::TYPE_OWNER: - $object->setOwnerPHID($xaction->getNewValue()); - break; - case NuanceItemTransaction::TYPE_QUEUE: - $object->setQueuePHID($xaction->getNewValue()); - break; - case NuanceItemTransaction::TYPE_PROPERTY: - $key = $xaction->getMetadataValue( - NuanceItemTransaction::PROPERTY_KEY); - $object->setNuanceProperty($key, $xaction->getNewValue()); - break; - case NuanceItemTransaction::TYPE_COMMAND: - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceItemTransaction::TYPE_REQUESTOR: - case NuanceItemTransaction::TYPE_SOURCE: - case NuanceItemTransaction::TYPE_OWNER: - case NuanceItemTransaction::TYPE_PROPERTY: - case NuanceItemTransaction::TYPE_QUEUE: - case NuanceItemTransaction::TYPE_COMMAND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - } diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php index 74555494d0..ff89108f4a 100644 --- a/src/applications/nuance/item/NuanceItemType.php +++ b/src/applications/nuance/item/NuanceItemType.php @@ -115,7 +115,7 @@ abstract class NuanceItemType } $xaction = id(new NuanceItemTransaction()) - ->setTransactionType(NuanceItemTransaction::TYPE_COMMAND) + ->setTransactionType(NuanceItemCommandTransaction::TRANSACTIONTYPE) ->setNewValue( array( 'command' => $command->getCommand(), diff --git a/src/applications/nuance/source/NuanceSourceDefinition.php b/src/applications/nuance/source/NuanceSourceDefinition.php index 99d79f8f31..0330aa5c7e 100644 --- a/src/applications/nuance/source/NuanceSourceDefinition.php +++ b/src/applications/nuance/source/NuanceSourceDefinition.php @@ -162,18 +162,19 @@ abstract class NuanceSourceDefinition extends Phobject { $xactions = array(); $xactions[] = id(new NuanceItemTransaction()) - ->setTransactionType(NuanceItemTransaction::TYPE_SOURCE) + ->setTransactionType(NuanceItemSourceTransaction::TRANSACTIONTYPE) ->setNewValue($source->getPHID()); // TODO: Eventually, apply real routing rules. For now, just put everything // in the default queue for the source. $xactions[] = id(new NuanceItemTransaction()) - ->setTransactionType(NuanceItemTransaction::TYPE_QUEUE) + ->setTransactionType(NuanceItemQueueTransaction::TRANSACTIONTYPE) ->setNewValue($source->getDefaultQueuePHID()); + // TODO: Maybe this should all be modular transactions now? foreach ($properties as $key => $property) { $xactions[] = id(new NuanceItemTransaction()) - ->setTransactionType(NuanceItemTransaction::TYPE_PROPERTY) + ->setTransactionType(NuanceItemPropertyTransaction::TRANSACTIONTYPE) ->setMetadataValue(NuanceItemTransaction::PROPERTY_KEY, $key) ->setNewValue($property); } diff --git a/src/applications/nuance/storage/NuanceItemTransaction.php b/src/applications/nuance/storage/NuanceItemTransaction.php index 77471fcdb9..5579183a66 100644 --- a/src/applications/nuance/storage/NuanceItemTransaction.php +++ b/src/applications/nuance/storage/NuanceItemTransaction.php @@ -5,13 +5,6 @@ final class NuanceItemTransaction const PROPERTY_KEY = 'property.key'; - const TYPE_OWNER = 'nuance.item.owner'; - const TYPE_REQUESTOR = 'nuance.item.requestor'; - const TYPE_SOURCE = 'nuance.item.source'; - const TYPE_PROPERTY = 'nuance.item.property'; - const TYPE_QUEUE = 'nuance.item.queue'; - const TYPE_COMMAND = 'nuance.item.command'; - public function getApplicationTransactionType() { return NuanceItemPHIDType::TYPECONST; } @@ -20,61 +13,8 @@ final class NuanceItemTransaction return new NuanceItemTransactionComment(); } - public function shouldHide() { - $old = $this->getOldValue(); - $type = $this->getTransactionType(); - - switch ($type) { - case self::TYPE_REQUESTOR: - case self::TYPE_SOURCE: - return ($old === null); - } - - return parent::shouldHide(); - } - - public function getRequiredHandlePHIDs() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - - $phids = parent::getRequiredHandlePHIDs(); - switch ($type) { - case self::TYPE_QUEUE: - if ($old) { - $phids[] = $old; - } - if ($new) { - $phids[] = $new; - } - break; - } - - return $phids; - } - - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - - $author_phid = $this->getAuthorPHID(); - - switch ($type) { - case self::TYPE_QUEUE: - return pht( - '%s routed this item to the %s queue.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - case self::TYPE_COMMAND: - // TODO: Give item types a chance to render this properly. - return pht( - '%s applied command "%s" to this item.', - $this->renderHandleLink($author_phid), - idx($new, 'command')); - } - - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'NuanceItemTransactionType'; } } diff --git a/src/applications/nuance/storage/NuanceQueueTransaction.php b/src/applications/nuance/storage/NuanceQueueTransaction.php index 44309c2ae6..801ce62d20 100644 --- a/src/applications/nuance/storage/NuanceQueueTransaction.php +++ b/src/applications/nuance/storage/NuanceQueueTransaction.php @@ -12,6 +12,10 @@ final class NuanceQueueTransaction extends NuanceTransaction { return new NuanceQueueTransactionComment(); } + public function getBaseTransactionClass() { + return 'NuanceSourceTransactionType'; + } + public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); diff --git a/src/applications/nuance/storage/NuanceSourceTransaction.php b/src/applications/nuance/storage/NuanceSourceTransaction.php index 0b18c81184..5d70376ce3 100644 --- a/src/applications/nuance/storage/NuanceSourceTransaction.php +++ b/src/applications/nuance/storage/NuanceSourceTransaction.php @@ -14,6 +14,10 @@ final class NuanceSourceTransaction return new NuanceSourceTransactionComment(); } + public function getBaseTransactionClass() { + return 'NuanceSourceTransactionType'; + } + public function shouldHide() { $old = $this->getOldValue(); $new = $this->getNewValue(); diff --git a/src/applications/nuance/storage/NuanceTransaction.php b/src/applications/nuance/storage/NuanceTransaction.php index 5e9ae656ef..0cdb98ff27 100644 --- a/src/applications/nuance/storage/NuanceTransaction.php +++ b/src/applications/nuance/storage/NuanceTransaction.php @@ -1,7 +1,7 @@ renderAuthor()); + } + +} diff --git a/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php b/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php new file mode 100644 index 0000000000..381371c8f3 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemOwnerTransaction.php @@ -0,0 +1,27 @@ +getOwnerPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setOwnerPHID($value); + } + + public function getTitle() { + + // TODO: Assign, unassign strings probably need variants. + + return pht( + '%s reassigned this item from %s to %s.', + $this->renderAuthor(), + $this->renderHandle($this->getOldValue()), + $this->renderHandle($this->getNewValue())); + } + +} diff --git a/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php new file mode 100644 index 0000000000..76724843de --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php @@ -0,0 +1,27 @@ +getMetadataValue($property_key); + return $object->getNuanceProperty($key); + } + + public function applyInternalEffects($object, $value) { + $property_key = NuanceItemTransaction::PROPERTY_KEY; + $key = $this->getMetadataValue($property_key); + + $object->setNuanceProperty($key, $value); + } + + public function getTitle() { + return pht( + '%s set a property on this item.', + $this->renderAuthor()); + } + +} diff --git a/src/applications/nuance/xaction/NuanceItemQueueTransaction.php b/src/applications/nuance/xaction/NuanceItemQueueTransaction.php new file mode 100644 index 0000000000..8ccbdb7797 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemQueueTransaction.php @@ -0,0 +1,25 @@ +getQueuePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setQueuePHID($value); + } + + public function getTitle() { + return pht( + '%s rerouted this item from %s to %s.', + $this->renderAuthor(), + $this->renderHandle($this->getOldValue()), + $this->renderHandle($this->getNewValue())); + } + + +} diff --git a/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php b/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php new file mode 100644 index 0000000000..a19ef45197 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemRequestorTransaction.php @@ -0,0 +1,16 @@ +getRequestorPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setRequestorPHID($value); + } + +} diff --git a/src/applications/nuance/xaction/NuanceItemSourceTransaction.php b/src/applications/nuance/xaction/NuanceItemSourceTransaction.php new file mode 100644 index 0000000000..e637485990 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemSourceTransaction.php @@ -0,0 +1,16 @@ +getSourcePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setSourcePHID($value); + } + +} diff --git a/src/applications/nuance/xaction/NuanceItemTransactionType.php b/src/applications/nuance/xaction/NuanceItemTransactionType.php new file mode 100644 index 0000000000..cc03b31ac4 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemTransactionType.php @@ -0,0 +1,4 @@ + Date: Mon, 22 May 2017 10:29:14 -0700 Subject: [PATCH 19/61] Convert Nuance queues to modular transactions Summary: Ref T12738. Swaps queues over. Also fixes a typo from D17990. Test Plan: Renamed a queue. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D17992 --- src/__phutil_library_map__.php | 2 + .../nuance/editor/NuanceQueueEditEngine.php | 2 +- .../nuance/editor/NuanceQueueEditor.php | 79 ------------------- .../nuance/storage/NuanceQueueTransaction.php | 26 +----- .../xaction/NuanceQueueNameTransaction.php | 47 +++++++++++ 5 files changed, 51 insertions(+), 105 deletions(-) create mode 100644 src/applications/nuance/xaction/NuanceQueueNameTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9831b24686..7cbf6f7216 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1652,6 +1652,7 @@ phutil_register_library_map(array( 'NuanceQueueEditEngine' => 'applications/nuance/editor/NuanceQueueEditEngine.php', 'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php', 'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php', + 'NuanceQueueNameTransaction' => 'applications/nuance/xaction/NuanceQueueNameTransaction.php', 'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php', 'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php', 'NuanceQueueSearchEngine' => 'applications/nuance/query/NuanceQueueSearchEngine.php', @@ -6765,6 +6766,7 @@ phutil_register_library_map(array( 'NuanceQueueEditEngine' => 'PhabricatorEditEngine', 'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceQueueListController' => 'NuanceQueueController', + 'NuanceQueueNameTransaction' => 'NuanceQueueTransactionType', 'NuanceQueuePHIDType' => 'PhabricatorPHIDType', 'NuanceQueueQuery' => 'NuanceQuery', 'NuanceQueueSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/nuance/editor/NuanceQueueEditEngine.php b/src/applications/nuance/editor/NuanceQueueEditEngine.php index 049916adbe..12f5c7b517 100644 --- a/src/applications/nuance/editor/NuanceQueueEditEngine.php +++ b/src/applications/nuance/editor/NuanceQueueEditEngine.php @@ -75,7 +75,7 @@ final class NuanceQueueEditEngine ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the queue.')) - ->setTransactionType(NuanceQueueTransaction::TYPE_NAME) + ->setTransactionType(NuanceQueueNameTransaction::TRANSACTIONTYPE) ->setIsRequired(true) ->setValue($object->getName()), ); diff --git a/src/applications/nuance/editor/NuanceQueueEditor.php b/src/applications/nuance/editor/NuanceQueueEditor.php index cb3ead2417..2a18188f98 100644 --- a/src/applications/nuance/editor/NuanceQueueEditor.php +++ b/src/applications/nuance/editor/NuanceQueueEditor.php @@ -14,89 +14,10 @@ final class NuanceQueueEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = NuanceQueueTransaction::TYPE_NAME; - $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceQueueTransaction::TYPE_NAME: - return $object->getName(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceQueueTransaction::TYPE_NAME: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceQueueTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceQueueTransaction::TYPE_NAME: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case NuanceQueueTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('A queue must have a name.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - } - - return $errors; - } - - } diff --git a/src/applications/nuance/storage/NuanceQueueTransaction.php b/src/applications/nuance/storage/NuanceQueueTransaction.php index 801ce62d20..1561db80e5 100644 --- a/src/applications/nuance/storage/NuanceQueueTransaction.php +++ b/src/applications/nuance/storage/NuanceQueueTransaction.php @@ -2,8 +2,6 @@ final class NuanceQueueTransaction extends NuanceTransaction { - const TYPE_NAME = 'nuance.queue.name'; - public function getApplicationTransactionType() { return NuanceQueuePHIDType::TYPECONST; } @@ -13,29 +11,7 @@ final class NuanceQueueTransaction extends NuanceTransaction { } public function getBaseTransactionClass() { - return 'NuanceSourceTransactionType'; + return 'NuanceQueueTransactionType'; } - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - - $author_phid = $this->getAuthorPHID(); - - switch ($type) { - case PhabricatorTransactions::TYPE_CREATE: - return pht( - '%s created this queue.', - $this->renderHandleLink($author_phid)); - case self::TYPE_NAME: - return pht( - '%s renamed this queue from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - - return parent::getTitle(); - } } diff --git a/src/applications/nuance/xaction/NuanceQueueNameTransaction.php b/src/applications/nuance/xaction/NuanceQueueNameTransaction.php new file mode 100644 index 0000000000..e9a9efcd93 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceQueueNameTransaction.php @@ -0,0 +1,47 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this queue from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Queues must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht( + 'Queue names must not be longer than %s character(s).', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} From 3a0a086a094c75be0bd3347be2c51e5f9a456533 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 22 May 2017 10:52:44 -0700 Subject: [PATCH 20/61] Convert Nuance sources to modular transactions Summary: Ref T12738. Update sources to modular transactions. Test Plan: Created and edited a source. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D17994 --- src/__phutil_library_map__.php | 4 + .../nuance/editor/NuanceSourceEditEngine.php | 5 +- .../nuance/editor/NuanceSourceEditor.php | 101 ------------------ .../storage/NuanceSourceTransaction.php | 62 ----------- .../NuanceSourceDefaultQueueTransaction.php | 42 ++++++++ .../xaction/NuanceSourceNameTransaction.php | 47 ++++++++ 6 files changed, 96 insertions(+), 165 deletions(-) create mode 100644 src/applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php create mode 100644 src/applications/nuance/xaction/NuanceSourceNameTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7cbf6f7216..7088012879 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1666,6 +1666,7 @@ phutil_register_library_map(array( 'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php', 'NuanceSourceController' => 'applications/nuance/controller/NuanceSourceController.php', 'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php', + 'NuanceSourceDefaultQueueTransaction' => 'applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php', 'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php', 'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php', 'NuanceSourceDefinitionTestCase' => 'applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php', @@ -1675,6 +1676,7 @@ phutil_register_library_map(array( 'NuanceSourceListController' => 'applications/nuance/controller/NuanceSourceListController.php', 'NuanceSourceManageCapability' => 'applications/nuance/capability/NuanceSourceManageCapability.php', 'NuanceSourceNameNgrams' => 'applications/nuance/storage/NuanceSourceNameNgrams.php', + 'NuanceSourceNameTransaction' => 'applications/nuance/xaction/NuanceSourceNameTransaction.php', 'NuanceSourcePHIDType' => 'applications/nuance/phid/NuanceSourcePHIDType.php', 'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php', 'NuanceSourceSearchEngine' => 'applications/nuance/query/NuanceSourceSearchEngine.php', @@ -6785,6 +6787,7 @@ phutil_register_library_map(array( 'NuanceSourceActionController' => 'NuanceController', 'NuanceSourceController' => 'NuanceController', 'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability', + 'NuanceSourceDefaultQueueTransaction' => 'NuanceSourceTransactionType', 'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceDefinition' => 'Phobject', 'NuanceSourceDefinitionTestCase' => 'PhabricatorTestCase', @@ -6794,6 +6797,7 @@ phutil_register_library_map(array( 'NuanceSourceListController' => 'NuanceSourceController', 'NuanceSourceManageCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceNameNgrams' => 'PhabricatorSearchNgrams', + 'NuanceSourceNameTransaction' => 'NuanceSourceTransactionType', 'NuanceSourcePHIDType' => 'PhabricatorPHIDType', 'NuanceSourceQuery' => 'NuanceQuery', 'NuanceSourceSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/nuance/editor/NuanceSourceEditEngine.php b/src/applications/nuance/editor/NuanceSourceEditEngine.php index 18d27863ac..eac751c3a5 100644 --- a/src/applications/nuance/editor/NuanceSourceEditEngine.php +++ b/src/applications/nuance/editor/NuanceSourceEditEngine.php @@ -96,14 +96,15 @@ final class NuanceSourceEditEngine ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the source.')) - ->setTransactionType(NuanceSourceTransaction::TYPE_NAME) + ->setTransactionType(NuanceSourceNameTransaction::TRANSACTIONTYPE) ->setIsRequired(true) ->setValue($object->getName()), id(new PhabricatorDatasourceEditField()) ->setKey('defaultQueue') ->setLabel(pht('Default Queue')) ->setDescription(pht('Default queue.')) - ->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE) + ->setTransactionType( + NuanceSourceDefaultQueueTransaction::TRANSACTIONTYPE) ->setDatasource(new NuanceQueueDatasource()) ->setSingleValue($object->getDefaultQueuePHID()), ); diff --git a/src/applications/nuance/editor/NuanceSourceEditor.php b/src/applications/nuance/editor/NuanceSourceEditor.php index 5fbc02b962..b56b183f9e 100644 --- a/src/applications/nuance/editor/NuanceSourceEditor.php +++ b/src/applications/nuance/editor/NuanceSourceEditor.php @@ -18,111 +18,10 @@ final class NuanceSourceEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = NuanceSourceTransaction::TYPE_NAME; - $types[] = NuanceSourceTransaction::TYPE_DEFAULT_QUEUE; - - $types[] = PhabricatorTransactions::TYPE_EDGE; - $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceSourceTransaction::TYPE_NAME: - return $object->getName(); - case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: - return $object->getDefaultQueuePHID(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceSourceTransaction::TYPE_NAME: - case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceSourceTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - break; - case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: - $object->setDefaultQueuePHID($xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case NuanceSourceTransaction::TYPE_NAME: - case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case NuanceSourceTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Source name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: - foreach ($xactions as $xaction) { - if (!$xaction->getNewValue()) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Sources must have a default queue.'), - $xaction); - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - } - break; - } - - return $errors; - } - } diff --git a/src/applications/nuance/storage/NuanceSourceTransaction.php b/src/applications/nuance/storage/NuanceSourceTransaction.php index 5d70376ce3..0e264876dd 100644 --- a/src/applications/nuance/storage/NuanceSourceTransaction.php +++ b/src/applications/nuance/storage/NuanceSourceTransaction.php @@ -3,9 +3,6 @@ final class NuanceSourceTransaction extends NuanceTransaction { - const TYPE_NAME = 'source.name'; - const TYPE_DEFAULT_QUEUE = 'source.queue.default'; - public function getApplicationTransactionType() { return NuanceSourcePHIDType::TYPECONST; } @@ -18,63 +15,4 @@ final class NuanceSourceTransaction return 'NuanceSourceTransactionType'; } - public function shouldHide() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - - switch ($type) { - case self::TYPE_DEFAULT_QUEUE: - return !$old; - case self::TYPE_NAME: - return ($old === null); - } - - return parent::shouldHide(); - } - - public function getRequiredHandlePHIDs() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - - $phids = parent::getRequiredHandlePHIDs(); - switch ($type) { - case self::TYPE_DEFAULT_QUEUE: - if ($old) { - $phids[] = $old; - } - if ($new) { - $phids[] = $new; - } - break; - } - - return $phids; - } - - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $type = $this->getTransactionType(); - $author_phid = $this->getAuthorPHID(); - - switch ($type) { - case self::TYPE_DEFAULT_QUEUE: - return pht( - '%s changed the default queue from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - case self::TYPE_NAME: - return pht( - '%s renamed this source from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - - return parent::getTitle(); - } - } diff --git a/src/applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php b/src/applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php new file mode 100644 index 0000000000..f5a7cc4302 --- /dev/null +++ b/src/applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php @@ -0,0 +1,42 @@ +getDefaultQueuePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setDefaultQueuePHID($value); + } + + public function getTitle() { + return pht( + '%s changed the default queue for this source from %s to %s.', + $this->renderAuthor(), + $this->renderOldHandle(), + $this->renderNewHandle()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if (!$object->getDefaultQueuePHID() && !$xactions) { + $errors[] = $this->newRequiredError( + pht('Sources must have a default queue.')); + } + + foreach ($xactions as $xaction) { + if (!$xaction->getNewValue()) { + $errors[] = $this->newRequiredError( + pht('Sources must have a default queue.')); + } + } + + return $errors; + } + +} diff --git a/src/applications/nuance/xaction/NuanceSourceNameTransaction.php b/src/applications/nuance/xaction/NuanceSourceNameTransaction.php new file mode 100644 index 0000000000..e33b60551c --- /dev/null +++ b/src/applications/nuance/xaction/NuanceSourceNameTransaction.php @@ -0,0 +1,47 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this source from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Sources must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht( + 'Source names must not be longer than %s character(s).', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} From 00400ae6f96583ef150c39acd53dc35f377d05c5 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 18:59:53 +0000 Subject: [PATCH 21/61] Search and Replace calls to setShade Summary: grep for setShade and update to setColor. Add deprecated warning. Test Plan: Diffusion, Workboards, Maniphest, Project tags, tokenizer, uiexamples Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, O14 ATC Monitoring Differential Revision: https://secure.phabricator.com/D17995 --- .../calendar/view/PHUIUserAvailabilityView.php | 2 +- .../conpherence/controller/ConpherenceController.php | 2 +- .../differential/constants/DifferentialRevisionStatus.php | 2 +- .../files/controller/PhabricatorFileInfoController.php | 4 ++-- .../harbormaster/view/HarbormasterUnitSummaryView.php | 2 +- .../maniphest/constants/ManiphestTaskStatus.php | 2 +- .../PhabricatorOwnersHovercardEngineExtension.php | 2 +- src/applications/people/view/PhabricatorUserCardView.php | 2 +- .../controller/PhabricatorProjectBoardViewController.php | 2 +- .../project/query/PhabricatorProjectSearchEngine.php | 2 +- src/applications/project/view/ProjectBoardTaskCard.php | 2 +- .../search/query/PhabricatorFulltextToken.php | 2 +- src/applications/uiexample/examples/PHUITagExample.php | 4 ++-- .../diff/view/PHUIDiffInlineCommentDetailView.php | 4 ++-- .../markup/rule/PhabricatorNavigationRemarkupRule.php | 2 +- src/view/phui/PHUIHeaderView.php | 2 +- src/view/phui/PHUITagView.php | 8 +++++++- 17 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/applications/calendar/view/PHUIUserAvailabilityView.php b/src/applications/calendar/view/PHUIUserAvailabilityView.php index 7ab0ace77a..f4f9696ba9 100644 --- a/src/applications/calendar/view/PHUIUserAvailabilityView.php +++ b/src/applications/calendar/view/PHUIUserAvailabilityView.php @@ -29,7 +29,7 @@ final class PHUIUserAvailabilityView $away_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($color) + ->setColor($color) ->setName($name) ->setDotColor($color); diff --git a/src/applications/conpherence/controller/ConpherenceController.php b/src/applications/conpherence/controller/ConpherenceController.php index 90328cca04..9d7473e159 100644 --- a/src/applications/conpherence/controller/ConpherenceController.php +++ b/src/applications/conpherence/controller/ConpherenceController.php @@ -71,7 +71,7 @@ abstract class ConpherenceController extends PhabricatorController { if (strlen($data['topic'])) { $topic = id(new PHUITagView()) ->setName($data['topic']) - ->setShade(PHUITagView::COLOR_VIOLET) + ->setColor(PHUITagView::COLOR_VIOLET) ->setType(PHUITagView::TYPE_SHADE) ->addClass('conpherence-header-topic'); $header->addTag($topic); diff --git a/src/applications/differential/constants/DifferentialRevisionStatus.php b/src/applications/differential/constants/DifferentialRevisionStatus.php index 4f332838ac..38e6a2dd49 100644 --- a/src/applications/differential/constants/DifferentialRevisionStatus.php +++ b/src/applications/differential/constants/DifferentialRevisionStatus.php @@ -65,7 +65,7 @@ final class DifferentialRevisionStatus extends Phobject { $tag = id(new PHUITagView()) ->setName($status_name) ->setIcon(self::getRevisionStatusIcon($status)) - ->setShade(self::getRevisionStatusColor($status)) + ->setColor(self::getRevisionStatusColor($status)) ->setType(PHUITagView::TYPE_SHADE); return $tag; diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php index 061790aa31..f30421c132 100644 --- a/src/applications/files/controller/PhabricatorFileInfoController.php +++ b/src/applications/files/controller/PhabricatorFileInfoController.php @@ -44,7 +44,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController { if ($ttl !== null) { $ttl_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade(PHUITagView::COLOR_YELLOW) + ->setColor(PHUITagView::COLOR_YELLOW) ->setName(pht('Temporary')); $header->addTag($ttl_tag); } @@ -53,7 +53,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController { if ($partial) { $partial_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade(PHUITagView::COLOR_ORANGE) + ->setColor(PHUITagView::COLOR_ORANGE) ->setName(pht('Partial Upload')); $header->addTag($partial_tag); } diff --git a/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php b/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php index 28f79ee181..e5a66a3eb8 100644 --- a/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php +++ b/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php @@ -56,7 +56,7 @@ final class HarbormasterUnitSummaryView extends AphrontView { $tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($tag_color) + ->setColor($tag_color) ->setIcon($tag_icon) ->setName($tag_text); diff --git a/src/applications/maniphest/constants/ManiphestTaskStatus.php b/src/applications/maniphest/constants/ManiphestTaskStatus.php index 5734892f0a..6781fb7724 100644 --- a/src/applications/maniphest/constants/ManiphestTaskStatus.php +++ b/src/applications/maniphest/constants/ManiphestTaskStatus.php @@ -97,7 +97,7 @@ final class ManiphestTaskStatus extends ManiphestConstants { ->setName($name) ->setIcon($icon) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($color); + ->setColor($color); return $tag; } diff --git a/src/applications/owners/engineextension/PhabricatorOwnersHovercardEngineExtension.php b/src/applications/owners/engineextension/PhabricatorOwnersHovercardEngineExtension.php index 744d3fbea2..39fe30ad28 100644 --- a/src/applications/owners/engineextension/PhabricatorOwnersHovercardEngineExtension.php +++ b/src/applications/owners/engineextension/PhabricatorOwnersHovercardEngineExtension.php @@ -64,7 +64,7 @@ final class PhabricatorOwnersHovercardEngineExtension if ($package->isArchived()) { $tag = id(new PHUITagView()) ->setName(pht('Archived')) - ->setShade(PHUITagView::COLOR_INDIGO) + ->setColor(PHUITagView::COLOR_INDIGO) ->setType(PHUITagView::TYPE_OBJECT); $hovercard->addTag($tag); } diff --git a/src/applications/people/view/PhabricatorUserCardView.php b/src/applications/people/view/PhabricatorUserCardView.php index 4f4f15a33d..f1fc515f88 100644 --- a/src/applications/people/view/PhabricatorUserCardView.php +++ b/src/applications/people/view/PhabricatorUserCardView.php @@ -85,7 +85,7 @@ final class PhabricatorUserCardView extends AphrontTagView { ->setType(PHUITagView::TYPE_SHADE); if ($tag_shade !== null) { - $tag->setShade($tag_shade); + $tag->setColor($tag_shade); } $body = array(); diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index 51b907cac0..ad08df1692 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -331,7 +331,7 @@ final class PhabricatorProjectBoardViewController $count_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade(PHUITagView::COLOR_BLUE) + ->setColor(PHUITagView::COLOR_BLUE) ->addSigil('column-points') ->setName( javelin_tag( diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php index df13278812..452085fa9f 100644 --- a/src/applications/project/query/PhabricatorProjectSearchEngine.php +++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php @@ -211,7 +211,7 @@ final class PhabricatorProjectSearchEngine $options[$color] = array( id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($color) + ->setColor($color) ->setName($name), ); } diff --git a/src/applications/project/view/ProjectBoardTaskCard.php b/src/applications/project/view/ProjectBoardTaskCard.php index ba5213a623..100fee20b3 100644 --- a/src/applications/project/view/ProjectBoardTaskCard.php +++ b/src/applications/project/view/ProjectBoardTaskCard.php @@ -100,7 +100,7 @@ final class ProjectBoardTaskCard extends Phobject { if ($points !== null) { $points_tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade(PHUITagView::COLOR_GREY) + ->setColor(PHUITagView::COLOR_GREY) ->setSlimShady(true) ->setName($points) ->addClass('phui-workcard-points'); diff --git a/src/applications/search/query/PhabricatorFulltextToken.php b/src/applications/search/query/PhabricatorFulltextToken.php index d42c15e9e6..4edeb098a9 100644 --- a/src/applications/search/query/PhabricatorFulltextToken.php +++ b/src/applications/search/query/PhabricatorFulltextToken.php @@ -64,7 +64,7 @@ final class PhabricatorFulltextToken extends Phobject { $tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($shade) + ->setColor($shade) ->setName($token->getValue()); if ($tip !== null) { diff --git a/src/applications/uiexample/examples/PHUITagExample.php b/src/applications/uiexample/examples/PHUITagExample.php index 764caaf717..027be2f9d8 100644 --- a/src/applications/uiexample/examples/PHUITagExample.php +++ b/src/applications/uiexample/examples/PHUITagExample.php @@ -187,12 +187,12 @@ final class PHUITagExample extends PhabricatorUIExample { foreach ($outlines as $outline) { $tags[] = id(new PHUITagView()) ->setType(PHUITagView::TYPE_OUTLINE) - ->setShade($outline) + ->setColor($outline) ->setName($outline); $tags[] = hsprintf(' '); $tags[] = id(new PHUITagView()) ->setType(PHUITagView::TYPE_OUTLINE) - ->setShade($outline) + ->setColor($outline) ->setSlimShady(true) ->setName($outline); $tags[] = hsprintf('

'); diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 821834431a..a42efa932a 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -148,7 +148,7 @@ final class PHUIDiffInlineCommentDetailView ->setType(PHUITagView::TYPE_SHADE) ->setName(pht('Unsubmitted')) ->setSlimShady(true) - ->setShade(PHUITagView::COLOR_RED) + ->setColor(PHUITagView::COLOR_RED) ->addClass('mml inline-draft-text'); } @@ -383,7 +383,7 @@ final class PHUIDiffInlineCommentDetailView ->setType(PHUITagView::TYPE_SHADE) ->setName(pht('Author')) ->setSlimShady(true) - ->setShade(PHUITagView::COLOR_YELLOW) + ->setColor(PHUITagView::COLOR_YELLOW) ->addClass('mml'); } } diff --git a/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php index 458ee5b834..3fc3373001 100644 --- a/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php +++ b/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php @@ -60,7 +60,7 @@ final class PhabricatorNavigationRemarkupRule extends PhutilRemarkupRule { $tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_SHADE) - ->setShade($item_color) + ->setColor($item_color) ->setName($item_name); if ($item['icon']) { diff --git a/src/view/phui/PHUIHeaderView.php b/src/view/phui/PHUIHeaderView.php index 0cd8379b42..ab576c64d5 100644 --- a/src/view/phui/PHUIHeaderView.php +++ b/src/view/phui/PHUIHeaderView.php @@ -131,7 +131,7 @@ final class PHUIHeaderView extends AphrontTagView { $tag = id(new PHUITagView()) ->setName($name) ->setIcon($icon) - ->setShade($color) + ->setColor($color) ->setType(PHUITagView::TYPE_SHADE); return $this->addProperty(self::PROPERTY_STATUS, $tag); diff --git a/src/view/phui/PHUITagView.php b/src/view/phui/PHUITagView.php index e8d30e935e..1811f8f1a9 100644 --- a/src/view/phui/PHUITagView.php +++ b/src/view/phui/PHUITagView.php @@ -57,8 +57,14 @@ final class PHUITagView extends AphrontTagView { return $this; } - /* Deprecated, use setColor */ + /** + * This method has been deprecated, use @{method:setColor} instead. + * + * @deprecated + */ public function setShade($shade) { + phlog( + pht('Deprecated call to setShade(), use setColor() instead.')); $this->color = $shade; return $this; } From a1b10824649fb7c950c91a9bc556c658ad9a67a0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 14:27:22 -0700 Subject: [PATCH 22/61] Update Phriction Delete to modular transactions Summary: Ref T12625. Updates to modular transactions Test Plan: Delete a document, restore a document, see feed story. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12625 Differential Revision: https://secure.phabricator.com/D17996 --- src/__phutil_library_map__.php | 2 + .../controller/PhrictionDeleteController.php | 3 +- .../editor/PhrictionTransactionEditor.php | 47 +--------- .../storage/PhrictionTransaction.php | 20 +---- .../PhrictionDocumentDeleteTransaction.php | 86 +++++++++++++++++++ 5 files changed, 95 insertions(+), 63 deletions(-) create mode 100644 src/applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7088012879..bceb28a334 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4635,6 +4635,7 @@ phutil_register_library_map(array( 'PhrictionDocumentAuthorHeraldField' => 'applications/phriction/herald/PhrictionDocumentAuthorHeraldField.php', 'PhrictionDocumentContentHeraldField' => 'applications/phriction/herald/PhrictionDocumentContentHeraldField.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', + 'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', 'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php', 'PhrictionDocumentHeraldField' => 'applications/phriction/herald/PhrictionDocumentHeraldField.php', @@ -10297,6 +10298,7 @@ phutil_register_library_map(array( 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentController' => 'PhrictionController', + 'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', 'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter', 'PhrictionDocumentHeraldField' => 'HeraldField', diff --git a/src/applications/phriction/controller/PhrictionDeleteController.php b/src/applications/phriction/controller/PhrictionDeleteController.php index 58dc06a65b..b061e89756 100644 --- a/src/applications/phriction/controller/PhrictionDeleteController.php +++ b/src/applications/phriction/controller/PhrictionDeleteController.php @@ -26,7 +26,8 @@ final class PhrictionDeleteController extends PhrictionController { if ($request->isFormPost()) { $xactions = array(); $xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_DELETE) + ->setTransactionType( + PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE) ->setNewValue(true); $editor = id(new PhrictionTransactionEditor()) diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index 9ab91d5db9..e29bd50152 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -86,7 +86,6 @@ final class PhrictionTransactionEditor $types = parent::getTransactionTypes(); $types[] = PhrictionTransaction::TYPE_CONTENT; - $types[] = PhrictionTransaction::TYPE_DELETE; $types[] = PhrictionTransaction::TYPE_MOVE_AWAY; $types[] = PhabricatorTransactions::TYPE_EDGE; @@ -107,7 +106,6 @@ final class PhrictionTransactionEditor return null; } return $this->getOldContent()->getContent(); - case PhrictionTransaction::TYPE_DELETE: case PhrictionTransaction::TYPE_MOVE_AWAY: return null; } @@ -119,7 +117,6 @@ final class PhrictionTransactionEditor switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_CONTENT: - case PhrictionTransaction::TYPE_DELETE: return $xaction->getNewValue(); case PhrictionTransaction::TYPE_MOVE_AWAY: $document = $xaction->getNewValue(); @@ -141,7 +138,7 @@ final class PhrictionTransactionEditor switch ($xaction->getTransactionType()) { case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: case PhrictionTransaction::TYPE_CONTENT: - case PhrictionTransaction::TYPE_DELETE: + case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: case PhrictionTransaction::TYPE_MOVE_AWAY: return true; @@ -169,9 +166,6 @@ final class PhrictionTransactionEditor case PhrictionTransaction::TYPE_MOVE_AWAY: $object->setStatus(PhrictionDocumentStatus::STATUS_MOVED); return; - case PhrictionTransaction::TYPE_DELETE: - $object->setStatus(PhrictionDocumentStatus::STATUS_DELETED); - return; } } @@ -188,7 +182,8 @@ final class PhrictionTransactionEditor $content = $xaction->getNewValue(); if ($content === '') { $xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_DELETE) + ->setTransactionType( + PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE) ->setNewValue(true) ->setMetadataValue('contentDelete', true); } @@ -218,11 +213,6 @@ final class PhrictionTransactionEditor case PhrictionTransaction::TYPE_CONTENT: $this->getNewContent()->setContent($xaction->getNewValue()); break; - case PhrictionTransaction::TYPE_DELETE: - $this->getNewContent()->setContent(''); - $this->getNewContent()->setChangeType( - PhrictionChangeType::CHANGE_DELETE); - break; case PhrictionTransaction::TYPE_MOVE_AWAY: $dict = $xaction->getNewValue(); $this->getNewContent()->setContent(''); @@ -245,7 +235,7 @@ final class PhrictionTransactionEditor case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: case PhrictionTransaction::TYPE_CONTENT: - case PhrictionTransaction::TYPE_DELETE: + case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: case PhrictionTransaction::TYPE_MOVE_AWAY: $save_content = true; break; @@ -536,35 +526,6 @@ final class PhrictionTransactionEditor } break; - case PhrictionTransaction::TYPE_DELETE: - switch ($object->getStatus()) { - case PhrictionDocumentStatus::STATUS_DELETED: - if ($xaction->getMetadataValue('contentDelete')) { - $e_text = pht( - 'This document is already deleted. You must specify '. - 'content to re-create the document and make further edits.'); - } else { - $e_text = pht( - 'An already deleted document can not be deleted.'); - } - break; - case PhrictionDocumentStatus::STATUS_MOVED: - $e_text = pht('A moved document can not be deleted.'); - break; - case PhrictionDocumentStatus::STATUS_STUB: - $e_text = pht('A stub document can not be deleted.'); - break; - default: - break 2; - } - - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Can not delete document.'), - $e_text, - $xaction); - $errors[] = $error; - break; } } diff --git a/src/applications/phriction/storage/PhrictionTransaction.php b/src/applications/phriction/storage/PhrictionTransaction.php index d3d78ff665..e447bf0bb4 100644 --- a/src/applications/phriction/storage/PhrictionTransaction.php +++ b/src/applications/phriction/storage/PhrictionTransaction.php @@ -4,7 +4,6 @@ final class PhrictionTransaction extends PhabricatorModularTransaction { const TYPE_CONTENT = 'content'; - const TYPE_DELETE = 'delete'; const TYPE_MOVE_AWAY = 'move-away'; const MAILTAG_TITLE = 'phriction-title'; @@ -99,8 +98,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return 1.3; - case self::TYPE_DELETE: - return 1.5; case self::TYPE_MOVE_AWAY: return 1.0; } @@ -115,8 +112,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return pht('Edited'); - case self::TYPE_DELETE: - return pht('Deleted'); case self::TYPE_MOVE_AWAY: return pht('Moved Away'); } @@ -131,8 +126,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return 'fa-pencil'; - case self::TYPE_DELETE: - return 'fa-times'; case self::TYPE_MOVE_AWAY: return 'fa-arrows'; } @@ -153,11 +146,6 @@ final class PhrictionTransaction '%s edited the document content.', $this->renderHandleLink($author_phid)); - case self::TYPE_DELETE: - return pht( - '%s deleted this document.', - $this->renderHandleLink($author_phid)); - case self::TYPE_MOVE_AWAY: return pht( '%s moved this document to %s', @@ -184,12 +172,6 @@ final class PhrictionTransaction $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); - case self::TYPE_DELETE: - return pht( - '%s deleted %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } return parent::getTitleForFeed(); } @@ -218,7 +200,7 @@ final class PhrictionTransaction case self::TYPE_CONTENT: $tags[] = self::MAILTAG_CONTENT; break; - case self::TYPE_DELETE: + case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_DELETE; break; case PhabricatorTransactions::TYPE_SUBSCRIBERS: diff --git a/src/applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php b/src/applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php new file mode 100644 index 0000000000..25cc7c2b28 --- /dev/null +++ b/src/applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php @@ -0,0 +1,86 @@ +setStatus(PhrictionDocumentStatus::STATUS_DELETED); + } + + public function applyExternalEffects($object, $value) { + $this->getEditor()->getNewContent()->setContent(''); + $this->getEditor()->getNewContent()->setChangeType( + PhrictionChangeType::CHANGE_DELETE); + } + + public function getActionStrength() { + return 1.5; + } + + public function getActionName() { + return pht('Deleted'); + } + + public function getTitle() { + return pht( + '%s deleted this document.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s deleted %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $e_text = null; + foreach ($xactions as $xaction) { + switch ($object->getStatus()) { + case PhrictionDocumentStatus::STATUS_DELETED: + if ($xaction->getMetadataValue('contentDelete')) { + $e_text = pht( + 'This document is already deleted. You must specify '. + 'content to re-create the document and make further edits.'); + } else { + $e_text = pht( + 'An already deleted document can not be deleted.'); + } + break; + case PhrictionDocumentStatus::STATUS_MOVED: + $e_text = pht('A moved document can not be deleted.'); + break; + case PhrictionDocumentStatus::STATUS_STUB: + $e_text = pht('A stub document can not be deleted.'); + break; + default: + break; + } + + if ($e_text !== null) { + $errors[] = $this->newInvalidError($e_text); + } + + } + + return $errors; + } + + public function getIcon() { + return 'fa-trash-o'; + } + + public function getColor() { + return 'red'; + } + +} From 2325c61ad77536e75322936d5a0505ee2bbb616d Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 22:26:58 +0000 Subject: [PATCH 23/61] Make the Install Dashboard button green Summary: GREEN Test Plan: View a dashboard page, see green button Reviewers: amckinley, epriestley Reviewed By: epriestley Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D17997 --- .../dashboard/controller/PhabricatorDashboardViewController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php index 07faee8f05..41441f09f4 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -47,6 +47,7 @@ final class PhabricatorDashboardViewController ->setTag('a') ->setText('Install Dashboard') ->setIcon('fa-plus') + ->setColor(PHUIButtonView::GREEN) ->setWorkflow(true) ->setHref($this->getApplicationURI("/install/{$id}/")); $header->addActionLink($install_button); From b164d2d04bcb5314ac25930ece089561a75f8dfd Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 22 May 2017 15:40:16 -0700 Subject: [PATCH 24/61] Update Phriction Move Away transaction to modular transactions Summary: Ref T12625 Test Plan: Move a document to a new location, verify the old and new document. Edit both. Grep for MOVE_AWAY Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12625 Differential Revision: https://secure.phabricator.com/D17988 --- src/__phutil_library_map__.php | 2 + .../editor/PhrictionTransactionEditor.php | 31 ++-------- .../storage/PhrictionTransaction.php | 20 +----- .../PhrictionDocumentMoveAwayTransaction.php | 62 +++++++++++++++++++ 4 files changed, 72 insertions(+), 43 deletions(-) create mode 100644 src/applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index bceb28a334..bfc054b88b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4640,6 +4640,7 @@ phutil_register_library_map(array( 'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php', 'PhrictionDocumentHeraldField' => 'applications/phriction/herald/PhrictionDocumentHeraldField.php', 'PhrictionDocumentHeraldFieldGroup' => 'applications/phriction/herald/PhrictionDocumentHeraldFieldGroup.php', + 'PhrictionDocumentMoveAwayTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php', 'PhrictionDocumentMoveToTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveToTransaction.php', 'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php', 'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php', @@ -10303,6 +10304,7 @@ phutil_register_library_map(array( 'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter', 'PhrictionDocumentHeraldField' => 'HeraldField', 'PhrictionDocumentHeraldFieldGroup' => 'HeraldFieldGroup', + 'PhrictionDocumentMoveAwayTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType', 'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField', diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index e29bd50152..eaa6ea93f1 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -86,7 +86,6 @@ final class PhrictionTransactionEditor $types = parent::getTransactionTypes(); $types[] = PhrictionTransaction::TYPE_CONTENT; - $types[] = PhrictionTransaction::TYPE_MOVE_AWAY; $types[] = PhabricatorTransactions::TYPE_EDGE; $types[] = PhabricatorTransactions::TYPE_COMMENT; @@ -106,8 +105,6 @@ final class PhrictionTransactionEditor return null; } return $this->getOldContent()->getContent(); - case PhrictionTransaction::TYPE_MOVE_AWAY: - return null; } } @@ -118,15 +115,6 @@ final class PhrictionTransactionEditor switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_CONTENT: return $xaction->getNewValue(); - case PhrictionTransaction::TYPE_MOVE_AWAY: - $document = $xaction->getNewValue(); - $dict = array( - 'id' => $document->getID(), - 'phid' => $document->getPHID(), - 'content' => $document->getContent()->getContent(), - 'title' => $document->getContent()->getTitle(), - ); - return $dict; } } @@ -140,7 +128,7 @@ final class PhrictionTransactionEditor case PhrictionTransaction::TYPE_CONTENT: case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case PhrictionTransaction::TYPE_MOVE_AWAY: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: return true; } } @@ -163,9 +151,6 @@ final class PhrictionTransactionEditor case PhrictionTransaction::TYPE_CONTENT: $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); return; - case PhrictionTransaction::TYPE_MOVE_AWAY: - $object->setStatus(PhrictionDocumentStatus::STATUS_MOVED); - return; } } @@ -213,13 +198,6 @@ final class PhrictionTransactionEditor case PhrictionTransaction::TYPE_CONTENT: $this->getNewContent()->setContent($xaction->getNewValue()); break; - case PhrictionTransaction::TYPE_MOVE_AWAY: - $dict = $xaction->getNewValue(); - $this->getNewContent()->setContent(''); - $this->getNewContent()->setChangeType( - PhrictionChangeType::CHANGE_MOVE_AWAY); - $this->getNewContent()->setChangeRef($dict['id']); - break; default: break; } @@ -234,9 +212,9 @@ final class PhrictionTransactionEditor switch ($xaction->getTransactionType()) { case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case PhrictionTransaction::TYPE_CONTENT: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: - case PhrictionTransaction::TYPE_MOVE_AWAY: + case PhrictionTransaction::TYPE_CONTENT: $save_content = true; break; default: @@ -303,7 +281,8 @@ final class PhrictionTransactionEditor if ($this->moveAwayDocument !== null) { $move_away_xactions = array(); $move_away_xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_MOVE_AWAY) + ->setTransactionType( + PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE) ->setNewValue($object); $sub_editor = id(new PhrictionTransactionEditor()) ->setActor($this->getActor()) diff --git a/src/applications/phriction/storage/PhrictionTransaction.php b/src/applications/phriction/storage/PhrictionTransaction.php index e447bf0bb4..542e9b3e58 100644 --- a/src/applications/phriction/storage/PhrictionTransaction.php +++ b/src/applications/phriction/storage/PhrictionTransaction.php @@ -4,7 +4,6 @@ final class PhrictionTransaction extends PhabricatorModularTransaction { const TYPE_CONTENT = 'content'; - const TYPE_MOVE_AWAY = 'move-away'; const MAILTAG_TITLE = 'phriction-title'; const MAILTAG_CONTENT = 'phriction-content'; @@ -33,7 +32,7 @@ final class PhrictionTransaction $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case self::TYPE_MOVE_AWAY: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: $phids[] = $new['phid']; break; case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: @@ -75,7 +74,7 @@ final class PhrictionTransaction public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case self::TYPE_MOVE_AWAY: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: return true; case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: return $this->getMetadataValue('stub:create:phid', false); @@ -86,7 +85,7 @@ final class PhrictionTransaction public function shouldHideForFeed() { switch ($this->getTransactionType()) { case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case self::TYPE_MOVE_AWAY: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: return true; case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: return $this->getMetadataValue('stub:create:phid', false); @@ -98,8 +97,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return 1.3; - case self::TYPE_MOVE_AWAY: - return 1.0; } return parent::getActionStrength(); @@ -112,8 +109,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return pht('Edited'); - case self::TYPE_MOVE_AWAY: - return pht('Moved Away'); } return parent::getActionName(); @@ -126,8 +121,6 @@ final class PhrictionTransaction switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return 'fa-pencil'; - case self::TYPE_MOVE_AWAY: - return 'fa-arrows'; } return parent::getIcon(); @@ -145,13 +138,6 @@ final class PhrictionTransaction return pht( '%s edited the document content.', $this->renderHandleLink($author_phid)); - - case self::TYPE_MOVE_AWAY: - return pht( - '%s moved this document to %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new['phid'])); - } return parent::getTitle(); diff --git a/src/applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php b/src/applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php new file mode 100644 index 0000000000..c827f7337d --- /dev/null +++ b/src/applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php @@ -0,0 +1,62 @@ + $document->getID(), + 'phid' => $document->getPHID(), + 'content' => $document->getContent()->getContent(), + 'title' => $document->getContent()->getTitle(), + ); + return $dict; + } + + public function applyInternalEffects($object, $value) { + $object->setStatus(PhrictionDocumentStatus::STATUS_MOVED); + } + + public function applyExternalEffects($object, $value) { + $dict = $value; + $this->getEditor()->getNewContent()->setContent(''); + $this->getEditor()->getNewContent()->setChangeType( + PhrictionChangeType::CHANGE_MOVE_AWAY); + $this->getEditor()->getNewContent()->setChangeRef($dict['id']); + } + + public function getActionName() { + return pht('Moved Away'); + } + + public function getTitle() { + $new = $this->getNewValue(); + + return pht( + '%s moved this document to %s', + $this->renderAuthor(), + $this->renderHandleLink($new['phid'])); + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + + return pht( + '%s moved %s to %s', + $this->renderAuthor(), + $this->renderObject(), + $this->renderHandleLink($new['phid'])); + } + + public function getIcon() { + return 'fa-arrows'; + } + +} From 20e7f7d0e2900fe878a830796a088204e4ba0a6d Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 23 May 2017 16:28:05 +0000 Subject: [PATCH 25/61] Bump markup engine version to clear old "Navigation Sequence" elements Summary: The tag/shade stuff changed, so purge older markup (like Diviner documents). Test Plan: {F4972666} Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17998 --- src/infrastructure/markup/PhabricatorMarkupEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php index ad380414f6..0c56d9ed41 100644 --- a/src/infrastructure/markup/PhabricatorMarkupEngine.php +++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php @@ -42,7 +42,7 @@ final class PhabricatorMarkupEngine extends Phobject { private $objects = array(); private $viewer; private $contextObject; - private $version = 16; + private $version = 17; private $engineCaches = array(); private $auxiliaryConfig = array(); From 93d8b33ccade9b70e600e7f8c7ba7a92e5b5a217 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 23 May 2017 16:59:15 +0000 Subject: [PATCH 26/61] Check for strlen instead of null for Maniphest title Summary: Fixes T12744. Unclear why `null` doesn't work here but does for the title, but `!strlen` seems to work fine in both cases. Test Plan: Create a new task, check mail folder, see [Created] Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12744 Differential Revision: https://secure.phabricator.com/D18002 --- .../maniphest/xaction/ManiphestTaskTitleTransaction.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/applications/maniphest/xaction/ManiphestTaskTitleTransaction.php b/src/applications/maniphest/xaction/ManiphestTaskTitleTransaction.php index 5fade77d07..506817b0fc 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskTitleTransaction.php +++ b/src/applications/maniphest/xaction/ManiphestTaskTitleTransaction.php @@ -19,8 +19,8 @@ final class ManiphestTaskTitleTransaction public function getActionName() { $old = $this->getOldValue(); - $new = $this->getNewValue(); - if ($old === null) { + + if (!strlen($old)) { return pht('Created'); } @@ -29,7 +29,8 @@ final class ManiphestTaskTitleTransaction public function getTitle() { $old = $this->getOldValue(); - if ($old === null) { + + if (!strlen($old)) { return pht( '%s created this task.', $this->renderAuthor()); From cd136a6af86a80fb1df5db777e43f2f08c251148 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Tue, 23 May 2017 11:12:30 -0700 Subject: [PATCH 27/61] Migrate Project parent and milestone to modular transactions Test Plan: Unit tests pass. Went through the UI for creating new subprojects and milestones, but didn't setup some API calls to check that all the validation errors were still caught. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D17999 --- src/__phutil_library_map__.php | 6 + .../PhabricatorProjectCoreTestCase.php | 6 +- .../PhabricatorProjectTransactionEditor.php | 116 +----------------- .../engine/PhabricatorProjectEditEngine.php | 9 +- .../storage/PhabricatorProjectTransaction.php | 2 - ...PhabricatorProjectMilestoneTransaction.php | 31 +++++ .../PhabricatorProjectParentTransaction.php | 29 +++++ .../PhabricatorProjectTypeTransaction.php | 71 +++++++++++ 8 files changed, 152 insertions(+), 118 deletions(-) create mode 100644 src/applications/project/xaction/PhabricatorProjectMilestoneTransaction.php create mode 100644 src/applications/project/xaction/PhabricatorProjectParentTransaction.php create mode 100644 src/applications/project/xaction/PhabricatorProjectTypeTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index bfc054b88b..ada16cc079 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3660,6 +3660,7 @@ phutil_register_library_map(array( 'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php', 'PhabricatorProjectMembersViewController' => 'applications/project/controller/PhabricatorProjectMembersViewController.php', 'PhabricatorProjectMenuItemController' => 'applications/project/controller/PhabricatorProjectMenuItemController.php', + 'PhabricatorProjectMilestoneTransaction' => 'applications/project/xaction/PhabricatorProjectMilestoneTransaction.php', 'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php', 'PhabricatorProjectNameContextFreeGrammar' => 'applications/project/lipsum/PhabricatorProjectNameContextFreeGrammar.php', 'PhabricatorProjectNameTransaction' => 'applications/project/xaction/PhabricatorProjectNameTransaction.php', @@ -3668,6 +3669,7 @@ phutil_register_library_map(array( 'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php', 'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php', 'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php', + 'PhabricatorProjectParentTransaction' => 'applications/project/xaction/PhabricatorProjectParentTransaction.php', 'PhabricatorProjectPictureProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php', 'PhabricatorProjectPointsProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', @@ -3696,6 +3698,7 @@ phutil_register_library_map(array( 'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php', 'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php', 'PhabricatorProjectTransactionType' => 'applications/project/xaction/PhabricatorProjectTransactionType.php', + 'PhabricatorProjectTypeTransaction' => 'applications/project/xaction/PhabricatorProjectTypeTransaction.php', 'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php', 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php', @@ -9093,6 +9096,7 @@ phutil_register_library_map(array( 'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersViewController' => 'PhabricatorProjectController', 'PhabricatorProjectMenuItemController' => 'PhabricatorProjectController', + 'PhabricatorProjectMilestoneTransaction' => 'PhabricatorProjectTypeTransaction', 'PhabricatorProjectMoveController' => 'PhabricatorProjectController', 'PhabricatorProjectNameContextFreeGrammar' => 'PhutilContextFreeGrammar', 'PhabricatorProjectNameTransaction' => 'PhabricatorProjectTransactionType', @@ -9101,6 +9105,7 @@ phutil_register_library_map(array( 'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver', + 'PhabricatorProjectParentTransaction' => 'PhabricatorProjectTypeTransaction', 'PhabricatorProjectPictureProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorProjectPointsProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', @@ -9132,6 +9137,7 @@ phutil_register_library_map(array( 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProjectTransactionType' => 'PhabricatorModularTransactionType', + 'PhabricatorProjectTypeTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener', 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', diff --git a/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php b/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php index 0bec2fe53c..d9356357b3 100644 --- a/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php +++ b/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php @@ -1447,11 +1447,13 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase { if ($parent) { if ($is_milestone) { $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_MILESTONE) + ->setTransactionType( + PhabricatorProjectMilestoneTransaction::TRANSACTIONTYPE) ->setNewValue($parent->getPHID()); } else { $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_PARENT) + ->setTransactionType( + PhabricatorProjectParentTransaction::TRANSACTIONTYPE) ->setNewValue($parent->getPHID()); } } diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 47f451b037..8b77f71505 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -30,8 +30,6 @@ final class PhabricatorProjectTransactionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; - $types[] = PhabricatorProjectTransaction::TYPE_PARENT; - $types[] = PhabricatorProjectTransaction::TYPE_MILESTONE; $types[] = PhabricatorProjectTransaction::TYPE_HASWORKBOARD; $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_SORT; $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER; @@ -47,9 +45,6 @@ final class PhabricatorProjectTransactionEditor switch ($xaction->getTransactionType()) { case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: return (int)$object->getHasWorkboard(); - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: - return null; case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: return $object->getDefaultWorkboardSort(); case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: @@ -66,8 +61,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: return $xaction->getNewValue(); @@ -89,14 +82,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_PARENT: - $object->setParentProjectPHID($xaction->getNewValue()); - return; - case PhabricatorProjectTransaction::TYPE_MILESTONE: - $number = $object->getParentProject()->loadNextMilestoneNumber(); - $object->setMilestoneNumber($number); - $object->setParentProjectPHID($xaction->getNewValue()); - return; case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: $object->setHasWorkboard($xaction->getNewValue()); return; @@ -122,8 +107,6 @@ final class PhabricatorProjectTransactionEditor $new = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: @@ -145,8 +128,8 @@ final class PhabricatorProjectTransactionEditor $parent_xaction = null; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: + case PhabricatorProjectParentTransaction::TRANSACTIONTYPE: + case PhabricatorProjectMilestoneTransaction::TRANSACTIONTYPE: if ($xaction->getNewValue() === null) { continue; } @@ -208,95 +191,6 @@ final class PhabricatorProjectTransactionEditor return $errors; } - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: - if (!$xactions) { - break; - } - - $xaction = last($xactions); - - $parent_phid = $xaction->getNewValue(); - if (!$parent_phid) { - continue; - } - - if (!$this->getIsNewObject()) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'You can only set a parent or milestone project when creating a '. - 'project for the first time.'), - $xaction); - break; - } - - $projects = id(new PhabricatorProjectQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($parent_phid)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->execute(); - if (!$projects) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Parent or milestone project PHID ("%s") must be the PHID of a '. - 'valid, visible project which you have permission to edit.', - $parent_phid), - $xaction); - break; - } - - $project = head($projects); - - if ($project->isMilestone()) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Parent or milestone project PHID ("%s") must not be a '. - 'milestone. Milestones may not have subprojects or milestones.', - $parent_phid), - $xaction); - break; - } - - $limit = PhabricatorProject::getProjectDepthLimit(); - if ($project->getProjectDepth() >= ($limit - 1)) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'You can not create a subproject or mielstone under this parent '. - 'because it would nest projects too deeply. The maximum '. - 'nesting depth of projects is %s.', - new PhutilNumber($limit)), - $xaction); - break; - } - - $object->attachParentProject($project); - break; - } - - return $errors; - } - - protected function requireCapabilities( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { @@ -458,8 +352,8 @@ final class PhabricatorProjectTransactionEditor break; } break; - case PhabricatorProjectTransaction::TYPE_PARENT: - case PhabricatorProjectTransaction::TYPE_MILESTONE: + case PhabricatorProjectParentTransaction::TRANSACTIONTYPE: + case PhabricatorProjectMilestoneTransaction::TRANSACTIONTYPE: $materialize = true; $new_parent = $object->getParentProject(); break; @@ -634,7 +528,7 @@ final class PhabricatorProjectTransactionEditor $is_milestone = $object->isMilestone(); foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_MILESTONE: + case PhabricatorProjectMilestoneTransaction::TRANSACTIONTYPE: if ($xaction->getNewValue() !== null) { $is_milestone = true; } diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php index cc377bed44..a7702c345f 100644 --- a/src/applications/project/engine/PhabricatorProjectEditEngine.php +++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php @@ -202,7 +202,8 @@ final class PhabricatorProjectEditEngine pht('Choose a parent project to create a subproject beneath.')) ->setConduitTypeDescription(pht('PHID of the parent project.')) ->setAliases(array('parentPHID')) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_PARENT) + ->setTransactionType( + PhabricatorProjectParentTransaction::TRANSACTIONTYPE) ->setHandleParameterType(new AphrontPHIDHTTPParameterType()) ->setSingleValue($parent_phid) ->setIsReorderable(false) @@ -217,7 +218,8 @@ final class PhabricatorProjectEditEngine pht('Choose a parent project to create a new milestone for.')) ->setConduitTypeDescription(pht('PHID of the parent project.')) ->setAliases(array('milestonePHID')) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_MILESTONE) + ->setTransactionType( + PhabricatorProjectMilestoneTransaction::TRANSACTIONTYPE) ->setHandleParameterType(new AphrontPHIDHTTPParameterType()) ->setSingleValue($milestone_phid) ->setIsReorderable(false) @@ -244,7 +246,8 @@ final class PhabricatorProjectEditEngine id(new PhabricatorIconSetEditField()) ->setKey('icon') ->setLabel(pht('Icon')) - ->setTransactionType(PhabricatorProjectIconTransaction::TRANSACTIONTYPE) + ->setTransactionType( + PhabricatorProjectIconTransaction::TRANSACTIONTYPE) ->setIconSet(new PhabricatorProjectIconSet()) ->setDescription(pht('Project icon.')) ->setConduitDescription(pht('Change the project icon.')) diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index f0a9966646..b6c77808bc 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -3,8 +3,6 @@ final class PhabricatorProjectTransaction extends PhabricatorModularTransaction { - const TYPE_PARENT = 'project:parent'; - const TYPE_MILESTONE = 'project:milestone'; const TYPE_HASWORKBOARD = 'project:hasworkboard'; const TYPE_DEFAULT_SORT = 'project:sort'; const TYPE_DEFAULT_FILTER = 'project:filter'; diff --git a/src/applications/project/xaction/PhabricatorProjectMilestoneTransaction.php b/src/applications/project/xaction/PhabricatorProjectMilestoneTransaction.php new file mode 100644 index 0000000000..74ac77b55d --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectMilestoneTransaction.php @@ -0,0 +1,31 @@ +setViewer($this->getActor()) + ->withPHIDs(array($parent_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + $object->attachParentProject($project); + + $number = $object->getParentProject()->loadNextMilestoneNumber(); + $object->setMilestoneNumber($number); + $object->setParentProjectPHID($value); + } + +} diff --git a/src/applications/project/xaction/PhabricatorProjectParentTransaction.php b/src/applications/project/xaction/PhabricatorProjectParentTransaction.php new file mode 100644 index 0000000000..6fc850ddde --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectParentTransaction.php @@ -0,0 +1,29 @@ +setViewer($this->getActor()) + ->withPHIDs(array($parent_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + $object->attachParentProject($project); + + $object->setParentProjectPHID($value); + } + +} diff --git a/src/applications/project/xaction/PhabricatorProjectTypeTransaction.php b/src/applications/project/xaction/PhabricatorProjectTypeTransaction.php new file mode 100644 index 0000000000..7bba2c5289 --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectTypeTransaction.php @@ -0,0 +1,71 @@ +getNewValue(); + if (!$parent_phid) { + return $errors; + } + + if (!$this->getEditor()->getIsNewObject()) { + $errors[] = $this->newInvalidError( + pht( + 'You can only set a parent or milestone project when creating a '. + 'project for the first time.')); + return $errors; + } + + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($parent_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->execute(); + if (!$projects) { + $errors[] = $this->newInvalidError( + pht( + 'Parent or milestone project PHID ("%s") must be the PHID of a '. + 'valid, visible project which you have permission to edit.', + $parent_phid)); + return $errors; + } + + $project = head($projects); + + if ($project->isMilestone()) { + $errors[] = $this->newInvalidError( + pht( + 'Parent or milestone project PHID ("%s") must not be a '. + 'milestone. Milestones may not have subprojects or milestones.', + $parent_phid)); + return $errors; + } + + $limit = PhabricatorProject::getProjectDepthLimit(); + if ($project->getProjectDepth() >= ($limit - 1)) { + $errors[] = $this->newInvalidError( + pht( + 'You can not create a subproject or milestone under this parent '. + 'because it would nest projects too deeply. The maximum '. + 'nesting depth of projects is %s.', + new PhutilNumber($limit))); + return $errors; + } + + return $errors; + } + +} From 1a75ae24056b76ce80d320c37bd28360dece3c23 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 23 May 2017 11:27:21 -0700 Subject: [PATCH 28/61] Modernize Diffusion Create with sidenav, curtain Summary: This moves the navigation to a standard sidebar, and moves all actions to the curtain. Also pulled out info view when available for cleaner UI. Test Plan: Create a git, svn, hg test repository and verify each page in the sidebar renders as expected. {F4973792} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18003 --- ...fusionRepositoryManagePanelsController.php | 11 ++- ...fusionRepositoryActionsManagementPanel.php | 13 ++-- ...ionRepositoryAutomationManagementPanel.php | 17 +++-- ...ffusionRepositoryBasicsManagementPanel.php | 34 ++++++---- ...usionRepositoryBranchesManagementPanel.php | 13 ++-- ...RepositoryDocumentationManagementPanel.php | 4 ++ ...fusionRepositoryHistoryManagementPanel.php | 3 + .../DiffusionRepositoryManagementPanel.php | 38 +++-------- ...usionRepositoryPoliciesManagementPanel.php | 13 ++-- ...fusionRepositoryStagingManagementPanel.php | 13 ++-- ...ffusionRepositoryStatusManagementPanel.php | 13 ++-- ...fusionRepositoryStorageManagementPanel.php | 44 ++++++------ ...ionRepositorySubversionManagementPanel.php | 13 ++-- ...fusionRepositorySymbolsManagementPanel.php | 13 ++-- ...DiffusionRepositoryURIsManagementPanel.php | 68 ++++++++++--------- 15 files changed, 162 insertions(+), 148 deletions(-) diff --git a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php index 22c03145e0..12faa6799d 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php @@ -83,11 +83,11 @@ final class DiffusionRepositoryManagePanelsController ->setTag('a') ->setText(pht('View Repository')) ->setHref($repository->getURI()) - ->setIcon('fa-code')); + ->setIcon('fa-code') + ->setColor(PHUIButtonView::GREEN)); $view = id(new PHUITwoColumnView()) ->setHeader($header) - ->setNavigation($nav) ->setMainColumn($content); $curtain = $panel->buildManagementPanelCurtain(); @@ -98,6 +98,7 @@ final class DiffusionRepositoryManagePanelsController return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($view); } @@ -112,6 +113,12 @@ final class DiffusionRepositoryManagePanelsController $nav = id(new AphrontSideNavFilterView()) ->setBaseURI($base_uri); + $item = id(new PHUIListItemView()) + ->setName(pht('manage')) + ->setType(PHUIListItemView::TYPE_LABEL); + + $nav->addMenuItem($item); + foreach ($panels as $panel) { $key = $panel->getManagementPanelKey(); $label = $panel->getManagementPanelLabel(); diff --git a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php index 1f47a68de3..83697e52e3 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php @@ -37,9 +37,10 @@ final class DiffusionRepositoryActionsManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -48,14 +49,15 @@ final class DiffusionRepositoryActionsManagementPanel $actions_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Actions')) ->setHref($actions_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -63,8 +65,7 @@ final class DiffusionRepositoryActionsManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $notify = $repository->getDetail('herald-disabled') ? pht('Off') diff --git a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php index 14182a0444..b37aa05ecf 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php @@ -46,9 +46,10 @@ final class DiffusionRepositoryAutomationManagementPanel return 'fa-truck'; } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -60,20 +61,23 @@ final class DiffusionRepositoryAutomationManagementPanel $automation_uri = $this->getEditPageURI(); $test_uri = $repository->getPathURI('edit/testautomation/'); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Automation')) ->setHref($automation_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), + ->setWorkflow(!$can_edit)); + + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-gamepad') ->setName(pht('Test Configuration')) ->setWorkflow(true) ->setDisabled(!$can_test) - ->setHref($test_uri), - ); + ->setHref($test_uri)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -81,8 +85,7 @@ final class DiffusionRepositoryAutomationManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $blueprint_phids = $repository->getAutomationBlueprintPHIDs(); if (!$blueprint_phids) { diff --git a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php index 45c2ca142a..a5e09e40d3 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php @@ -33,9 +33,10 @@ final class DiffusionRepositoryBasicsManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -67,38 +68,47 @@ final class DiffusionRepositoryBasicsManagementPanel $can_dangerous = ($can_edit && $repository->canAllowDangerousChanges()); } - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Basic Information')) ->setHref($edit_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), + ->setWorkflow(!$can_edit)); + + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-text-width') ->setName(pht('Edit Text Encoding')) ->setHref($encoding_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), + ->setWorkflow(!$can_edit)); + + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon($dangerous_icon) ->setName($dangerous_name) ->setHref($dangerous_uri) ->setDisabled(!$can_dangerous) - ->setWorkflow(true), + ->setWorkflow(true)); + + $action_list->addAction( id(new PhabricatorActionView()) ->setHref($activate_uri) ->setIcon($activate_icon) ->setName($activate_label) ->setDisabled(!$can_edit) - ->setWorkflow(true), + ->setWorkflow(true)); + + $action_list->addAction( id(new PhabricatorActionView()) ->setName(pht('Delete Repository')) ->setIcon('fa-times') ->setHref($delete_uri) ->setDisabled(true) - ->setWorkflow(true), - ); + ->setWorkflow(true)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -108,6 +118,7 @@ final class DiffusionRepositoryBasicsManagementPanel $repository = $this->getRepository(); $is_new = $repository->isNewlyInitialized(); + $info_view = null; if ($is_new) { $messages = array(); @@ -131,8 +142,6 @@ final class DiffusionRepositoryBasicsManagementPanel $info_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setErrors($messages); - - $basics->setInfoView($info_view); } $result[] = $basics; @@ -142,7 +151,7 @@ final class DiffusionRepositoryBasicsManagementPanel $result[] = $this->newBox(pht('Description'), $description); } - return $result; + return array($info_view, $result); } private function buildBasics() { @@ -150,8 +159,7 @@ final class DiffusionRepositoryBasicsManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $name = $repository->getName(); $view->addProperty(pht('Name'), $name); diff --git a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php index b3e7926cfc..aa2bb49ccb 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php @@ -41,9 +41,10 @@ final class DiffusionRepositoryBranchesManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -52,14 +53,15 @@ final class DiffusionRepositoryBranchesManagementPanel $branches_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Branches')) ->setHref($branches_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -67,8 +69,7 @@ final class DiffusionRepositoryBranchesManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $default_branch = nonempty( $repository->getHumanReadableDetail('default-branch'), diff --git a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php index ca2c577b38..9d067cd90b 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php @@ -21,6 +21,10 @@ final class DiffusionRepositoryDocumentationManagementPanel return null; } + public function buildManagementPanelCurtain() { + return null; + } + public function getPanelNavigationURI() { return PhabricatorEnv::getDoclink( 'Diffusion User Guide: Managing Repositories'); diff --git a/src/applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php index c1a812dca0..4ce2367f20 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php @@ -21,5 +21,8 @@ final class DiffusionRepositoryHistoryManagementPanel return $this->newTimeline(); } + public function buildManagementPanelCurtain() { + return null; + } } diff --git a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php index 34047cdb89..0098fe1df9 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php @@ -37,6 +37,7 @@ abstract class DiffusionRepositoryManagementPanel abstract public function getManagementPanelLabel(); abstract public function getManagementPanelOrder(); abstract public function buildManagementPanelContent(); + abstract public function buildManagementPanelCurtain(); public function getManagementPanelIcon() { return 'fa-pencil'; @@ -51,41 +52,20 @@ abstract class DiffusionRepositoryManagementPanel return true; } - final protected function newActions() { - $actions = $this->buildManagementPanelActions(); - if (!$actions) { - return null; - } - + public function getNewActionList() { $viewer = $this->getViewer(); + $action_id = celerity_generate_unique_node_id(); - $action_list = id(new PhabricatorActionListView()) - ->setViewer($viewer); - - foreach ($actions as $action) { - $action_list->addAction($action); - } - - return $action_list; + return id(new PhabricatorActionListView()) + ->setViewer($viewer) + ->setID($action_id); } - public function buildManagementPanelCurtain() { - // TODO: Delete or fix this, curtains always render in the left gutter - // at the moment. - return null; - - $actions = $this->newActions(); - if (!$actions) { - return null; - } - + public function getNewCurtainView(PhabricatorActionListView $action_list) { $viewer = $this->getViewer(); - - $curtain = id(new PHUICurtainView()) + return id(new PHUICurtainView()) ->setViewer($viewer) - ->setActionList($actions); - - return $curtain; + ->setActionList($action_list); } public static function getAllPanels() { diff --git a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php index 081869fbaa..6b2972e30c 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php @@ -54,9 +54,10 @@ final class DiffusionRepositoryPoliciesManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -65,14 +66,15 @@ final class DiffusionRepositoryPoliciesManagementPanel $edit_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Policies')) ->setHref($edit_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -80,8 +82,7 @@ final class DiffusionRepositoryPoliciesManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $viewer, diff --git a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php index 79b716e82a..bab7e72857 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php @@ -37,9 +37,10 @@ final class DiffusionRepositoryStagingManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -48,14 +49,15 @@ final class DiffusionRepositoryStagingManagementPanel $staging_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Staging')) ->setHref($staging_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -63,8 +65,7 @@ final class DiffusionRepositoryStagingManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $staging_uri = $repository->getStagingURI(); if (!$staging_uri) { diff --git a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php index 324338443d..23b2cd1684 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php @@ -28,9 +28,10 @@ final class DiffusionRepositoryStatusManagementPanel return 'fa-check grey'; } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -39,14 +40,15 @@ final class DiffusionRepositoryStatusManagementPanel $update_uri = $repository->getPathURI('edit/update/'); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-refresh') ->setName(pht('Update Now')) ->setWorkflow(true) ->setDisabled(!$can_edit) - ->setHref($update_uri), - ); + ->setHref($update_uri)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -54,8 +56,7 @@ final class DiffusionRepositoryStatusManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $view->addProperty( pht('Update Frequency'), diff --git a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php index 9cf210632d..3d6733d5d3 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php @@ -25,6 +25,22 @@ final class DiffusionRepositoryStorageManagementPanel } } + public function buildManagementPanelCurtain() { + $repository = $this->getRepository(); + $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); + + $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); + + $action_list->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setName(pht('Cluster Documentation'))); + + return $this->getNewCurtainView($action_list); + } + public function buildManagementPanelContent() { return array( $this->buildStorageStatusPanel(), @@ -55,13 +71,9 @@ final class DiffusionRepositoryStorageManagementPanel $view->addProperty(pht('Storage Path'), $storage_path); $view->addProperty(pht('Storage Cluster'), $storage_service); - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Storage')); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->addPropertyList($view); + $box = $this->newBox(pht('Storage'), null); + $box->addPropertyList($view); + return $box; } private function buildClusterStatusPanel() { @@ -231,21 +243,9 @@ final class DiffusionRepositoryStorageManagementPanel 'date', )); - $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Cluster Status')) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + $box = $this->newBox(pht('Cluster Status'), null); + $box->setTable($table); + return $box; } } diff --git a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php index c6b236d5b9..5b9384d195 100644 --- a/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php @@ -36,9 +36,10 @@ final class DiffusionRepositorySubversionManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -47,14 +48,15 @@ final class DiffusionRepositorySubversionManagementPanel $subversion_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Properties')) ->setHref($subversion_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -62,8 +64,7 @@ final class DiffusionRepositorySubversionManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $default_branch = nonempty( $repository->getHumanReadableDetail('svn-subpath'), diff --git a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php index 996473f4f1..22d8780077 100644 --- a/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php @@ -34,9 +34,10 @@ final class DiffusionRepositorySymbolsManagementPanel ); } - protected function buildManagementPanelActions() { + public function buildManagementPanelCurtain() { $repository = $this->getRepository(); $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -45,14 +46,15 @@ final class DiffusionRepositorySymbolsManagementPanel $symbols_uri = $this->getEditPageURI(); - return array( + $action_list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setName(pht('Edit Symbols')) ->setHref($symbols_uri) ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit), - ); + ->setWorkflow(!$can_edit)); + + return $this->getNewCurtainView($action_list); } public function buildManagementPanelContent() { @@ -60,8 +62,7 @@ final class DiffusionRepositorySymbolsManagementPanel $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) - ->setViewer($viewer) - ->setActionList($this->newActions()); + ->setViewer($viewer); $languages = $repository->getSymbolLanguages(); if ($languages) { diff --git a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php index 333c2f03c8..4fe9e00475 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php @@ -17,6 +17,35 @@ final class DiffusionRepositoryURIsManagementPanel return 400; } + public function buildManagementPanelCurtain() { + $repository = $this->getRepository(); + $viewer = $this->getViewer(); + $action_list = $this->getNewActionList(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); + $add_href = $repository->getPathURI('uri/edit/'); + + $action_list->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-plus') + ->setHref($add_href) + ->setDisabled(!$can_edit) + ->setName(pht('Add New URI'))); + + $action_list->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-book') + ->setHref($doc_href) + ->setName(pht('URI Documentation'))); + + return $this->getNewCurtainView($action_list); + } + public function buildManagementPanelContent() { $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -95,24 +124,6 @@ final class DiffusionRepositoryURIsManagementPanel null, )); - $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs'); - $add_href = $repository->getPathURI('uri/edit/'); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Repository URIs')) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-plus') - ->setHref($add_href) - ->setTag('a') - ->setText(pht('Add New URI'))) - ->addActionLink( - id(new PHUIButtonView()) - ->setIcon('fa-book') - ->setHref($doc_href) - ->setTag('a') - ->setText(pht('Documentation'))); - $is_new = $repository->isNewlyInitialized(); $messages = array(); @@ -123,11 +134,7 @@ final class DiffusionRepositoryURIsManagementPanel $host_message = pht('Phabricator is hosting this repository.'); } - $messages[] = array( - id(new PHUIIconView())->setIcon('fa-folder'), - ' ', - $host_message, - ); + $messages[] = $host_message; } else { if ($is_new) { $observe_message = pht( @@ -137,22 +144,17 @@ final class DiffusionRepositoryURIsManagementPanel 'This repository is hosted remotely. Phabricator is observing it.'); } - $messages[] = array( - id(new PHUIIconView())->setIcon('fa-download'), - ' ', - $observe_message, - ); + $messages[] = $observe_message; } $info_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setErrors($messages); - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setInfoView($info_view) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); + $box = $this->newBox(pht('Repository URIs'), null); + $box->setTable($table); + + return array($info_view, $box); } } From 7e822fc94fa373cecaf55e702f03fd91be33ae96 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 23 May 2017 11:31:27 -0700 Subject: [PATCH 29/61] Update PhrictionContent for modular transactions Summary: Fixes T12625. Moves TYPE_CONTENT in Phriction over to modular transactions. Test Plan: Edit some documents. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12625 Differential Revision: https://secure.phabricator.com/D18000 --- src/__phutil_library_map__.php | 2 + .../PhrictionCreateConduitAPIMethod.php | 2 +- .../conduit/PhrictionEditConduitAPIMethod.php | 2 +- .../controller/PhrictionEditController.php | 6 +- .../editor/PhrictionTransactionEditor.php | 92 ++------------ .../storage/PhrictionTransaction.php | 113 +----------------- .../PhrictionDocumentContentTransaction.php | 95 +++++++++++++++ 7 files changed, 117 insertions(+), 195 deletions(-) create mode 100644 src/applications/phriction/xaction/PhrictionDocumentContentTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ada16cc079..1aef433927 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4637,6 +4637,7 @@ phutil_register_library_map(array( 'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php', 'PhrictionDocumentAuthorHeraldField' => 'applications/phriction/herald/PhrictionDocumentAuthorHeraldField.php', 'PhrictionDocumentContentHeraldField' => 'applications/phriction/herald/PhrictionDocumentContentHeraldField.php', + 'PhrictionDocumentContentTransaction' => 'applications/phriction/xaction/PhrictionDocumentContentTransaction.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', @@ -10304,6 +10305,7 @@ phutil_register_library_map(array( ), 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', + 'PhrictionDocumentContentTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', diff --git a/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php index 4b05874410..fc28b53b66 100644 --- a/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php +++ b/src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php @@ -50,7 +50,7 @@ final class PhrictionCreateConduitAPIMethod extends PhrictionConduitAPIMethod { ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE) ->setNewValue($request->getValue('title')); $xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) + ->setTransactionType(PhrictionDocumentContentTransaction::TRANSACTIONTYPE) ->setNewValue($request->getValue('content')); $editor = id(new PhrictionTransactionEditor()) diff --git a/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php index d4c2b63b5a..70c02d376a 100644 --- a/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php +++ b/src/applications/phriction/conduit/PhrictionEditConduitAPIMethod.php @@ -45,7 +45,7 @@ final class PhrictionEditConduitAPIMethod extends PhrictionConduitAPIMethod { ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE) ->setNewValue($request->getValue('title')); $xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) + ->setTransactionType(PhrictionDocumentContentTransaction::TRANSACTIONTYPE) ->setNewValue($request->getValue('content')); $editor = id(new PhrictionTransactionEditor()) diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php index 1917348c24..17d11fdf3c 100644 --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -136,7 +136,8 @@ final class PhrictionEditController ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE) ->setNewValue($title); $xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) + ->setTransactionType( + PhrictionDocumentContentTransaction::TRANSACTIONTYPE) ->setNewValue($content_text); $xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) @@ -178,7 +179,8 @@ final class PhrictionEditController PhrictionDocumentTitleTransaction::TRANSACTIONTYPE), true); $e_content = nonempty( - $ex->getShortMessage(PhrictionTransaction::TYPE_CONTENT), + $ex->getShortMessage( + PhrictionDocumentContentTransaction::TRANSACTIONTYPE), true); // if we're not supposed to process the content version error, then diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index eaa6ea93f1..1920b4c718 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -85,8 +85,6 @@ final class PhrictionTransactionEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhrictionTransaction::TYPE_CONTENT; - $types[] = PhabricatorTransactions::TYPE_EDGE; $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; @@ -95,41 +93,18 @@ final class PhrictionTransactionEditor return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: - if ($this->getIsNewObject()) { - return null; - } - return $this->getOldContent()->getContent(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: - return $xaction->getNewValue(); - } - } - protected function shouldApplyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: - case PhrictionTransaction::TYPE_CONTENT: - case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: - case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: - case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: - return true; + case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: + case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: + case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: + case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: + return true; } } return parent::shouldApplyInitialEffects($object, $xactions); @@ -143,24 +118,13 @@ final class PhrictionTransactionEditor $this->setNewContent($this->buildNewContentTemplate($object)); } - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: - $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); - return; - } - } - protected function expandTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $xactions = parent::expandTransaction($object, $xaction); switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: if ($this->getIsNewObject()) { break; } @@ -190,19 +154,6 @@ final class PhrictionTransactionEditor return $xactions; } - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: - $this->getNewContent()->setContent($xaction->getNewValue()); - break; - default: - break; - } - } - protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { @@ -214,7 +165,7 @@ final class PhrictionTransactionEditor case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: case PhrictionDocumentMoveAwayTransaction::TRANSACTIONTYPE: case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: - case PhrictionTransaction::TYPE_CONTENT: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: $save_content = true; break; default: @@ -257,7 +208,8 @@ final class PhrictionTransactionEditor ->setNewValue(PhabricatorSlug::getDefaultTitle($slug)) ->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction()) - ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) + ->setTransactionType( + PhrictionDocumentContentTransaction::TRANSACTIONTYPE) ->setNewValue('') ->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction()) @@ -295,7 +247,7 @@ final class PhrictionTransactionEditor // Compute the content diff URI for the publishing phase. foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PhrictionTransaction::TYPE_CONTENT: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: $uri = id(new PhutilURI('/phriction/diff/'.$object->getID().'/')) ->alter('l', $this->getOldContent()->getVersion()) ->alter('r', $this->getNewContent()->getVersion()); @@ -419,29 +371,12 @@ final class PhrictionTransactionEditor foreach ($xactions as $xaction) { switch ($type) { - case PhrictionTransaction::TYPE_CONTENT: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: if ($xaction->getMetadataValue('stub:create:phid')) { continue; } - $missing = false; - if ($this->getIsNewObject()) { - $content = $object->getContent()->getContent(); - $missing = $this->validateIsEmptyTextField( - $content, - $xactions); - } - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Document content is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } else if ($this->getProcessContentVersionError()) { + if ($this->getProcessContentVersionError()) { $error = $this->validateContentVersion($object, $type, $xaction); if ($error) { $this->setProcessContentVersionError(false); @@ -459,7 +394,6 @@ final class PhrictionTransactionEditor $errors = array_merge($errors, $ancestry_errors); } } - break; case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: diff --git a/src/applications/phriction/storage/PhrictionTransaction.php b/src/applications/phriction/storage/PhrictionTransaction.php index 542e9b3e58..2ce9d38a08 100644 --- a/src/applications/phriction/storage/PhrictionTransaction.php +++ b/src/applications/phriction/storage/PhrictionTransaction.php @@ -3,8 +3,6 @@ final class PhrictionTransaction extends PhabricatorModularTransaction { - const TYPE_CONTENT = 'content'; - const MAILTAG_TITLE = 'phriction-title'; const MAILTAG_CONTENT = 'phriction-content'; const MAILTAG_DELETE = 'phriction-delete'; @@ -45,32 +43,6 @@ final class PhrictionTransaction return $phids; } - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - $blocks[] = $this->getNewValue(); - break; - } - - return $blocks; - } - - public function shouldHide() { - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - if ($this->getOldValue() === null) { - return true; - } else { - return false; - } - break; - } - - return parent::shouldHide(); - } - public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case PhrictionDocumentMoveToTransaction::TRANSACTIONTYPE: @@ -93,89 +65,6 @@ final class PhrictionTransaction return parent::shouldHideForFeed(); } - public function getActionStrength() { - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return 1.3; - } - - return parent::getActionStrength(); - } - - public function getActionName() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return pht('Edited'); - } - - return parent::getActionName(); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return 'fa-pencil'; - } - - return parent::getIcon(); - } - - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return pht( - '%s edited the document content.', - $this->renderHandleLink($author_phid)); - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - - case self::TYPE_CONTENT: - return pht( - '%s edited the content of %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } - return parent::getTitleForFeed(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return true; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); - } public function getMailTags() { $tags = array(); @@ -183,7 +72,7 @@ final class PhrictionTransaction case PhrictionDocumentTitleTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_TITLE; break; - case self::TYPE_CONTENT: + case PhrictionDocumentContentTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_CONTENT; break; case PhrictionDocumentDeleteTransaction::TRANSACTIONTYPE: diff --git a/src/applications/phriction/xaction/PhrictionDocumentContentTransaction.php b/src/applications/phriction/xaction/PhrictionDocumentContentTransaction.php new file mode 100644 index 0000000000..a051546824 --- /dev/null +++ b/src/applications/phriction/xaction/PhrictionDocumentContentTransaction.php @@ -0,0 +1,95 @@ +getEditor()->getIsNewObject()) { + return null; + } + return $object->getContent()->getContent(); + } + + public function generateNewValue($object, $value) { + return $value; + } + + public function applyInternalEffects($object, $value) { + $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); + } + + public function applyExternalEffects($object, $value) { + $this->getEditor()->getNewContent()->setContent($value); + } + + public function shouldHide() { + if ($this->getOldValue() === null) { + return true; + } else { + return false; + } + } + + public function getActionStrength() { + return 1.3; + } + + public function getActionName() { + return pht('Edited'); + } + + public function getTitle() { + return pht( + '%s edited the content of this document.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s edited the content of %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO DOCUMENT CONTENT'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $content = $object->getContent()->getContent(); + if ($this->isEmptyTextTransaction($content, $xactions)) { + $errors[] = $this->newRequiredError( + pht('Documents must have content.')); + } + + return $errors; + } + +} From 774fba3ce925af1500bcece04368932483e9cdf8 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Tue, 23 May 2017 11:54:37 -0700 Subject: [PATCH 30/61] Migrate Project workboard to modular transactions Summary: This was interesting, because there were a mix of callsites using transactions and others that just set the property on the `Project` object. I made everything consistent in using transactions to change this property. I also found an implementation of `getTitle()` that I don't think is ever being invoked since `shouldHide()` is returning `true`, but I migrated it anyway. Test Plan: Unit tests pass + enabling/disabling workboards (and importing). Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D18004 --- src/__phutil_library_map__.php | 2 + ...abricatorProjectBoardDisableController.php | 3 +- ...habricatorProjectBoardImportController.php | 12 +++++- .../PhabricatorProjectBoardViewController.php | 16 +++++++- .../PhabricatorProjectTransactionEditor.php | 9 ----- .../storage/PhabricatorProjectTransaction.php | 15 +------- ...PhabricatorProjectWorkboardTransaction.php | 38 +++++++++++++++++++ 7 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 src/applications/project/xaction/PhabricatorProjectWorkboardTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1aef433927..21daf85177 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3708,6 +3708,7 @@ phutil_register_library_map(array( 'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php', 'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php', 'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php', + 'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php', 'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php', 'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php', 'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php', @@ -9148,6 +9149,7 @@ phutil_register_library_map(array( 'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject', 'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem', + 'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension', 'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension', diff --git a/src/applications/project/controller/PhabricatorProjectBoardDisableController.php b/src/applications/project/controller/PhabricatorProjectBoardDisableController.php index 0440ff9eff..fc850640f1 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardDisableController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardDisableController.php @@ -33,7 +33,8 @@ final class PhabricatorProjectBoardDisableController $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_HASWORKBOARD) + ->setTransactionType( + PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE) ->setNewValue(0); id(new PhabricatorProjectTransactionEditor()) diff --git a/src/applications/project/controller/PhabricatorProjectBoardImportController.php b/src/applications/project/controller/PhabricatorProjectBoardImportController.php index 988084d3ee..c344bc0af0 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardImportController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardImportController.php @@ -61,8 +61,18 @@ final class PhabricatorProjectBoardImportController ->setProperties($import_column->getProperties()) ->save(); } + $xactions = array(); + $xactions[] = id(new PhabricatorProjectTransaction()) + ->setTransactionType( + PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE) + ->setNewValue(1); - $project->setHasWorkboard(1)->save(); + id(new PhabricatorProjectTransactionEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($project, $xactions); $table->saveTransaction(); diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index ad08df1692..8405ec677f 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -966,7 +966,18 @@ final class PhabricatorProjectBoardViewController ->setProjectPHID($project->getPHID()) ->save(); - $project->setHasWorkboard(1)->save(); + $xactions = array(); + $xactions[] = id(new PhabricatorProjectTransaction()) + ->setTransactionType( + PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE) + ->setNewValue(1); + + id(new PhabricatorProjectTransactionEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($project, $xactions); return id(new AphrontRedirectResponse()) ->setURI($board_uri); @@ -1050,7 +1061,8 @@ final class PhabricatorProjectBoardViewController $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_HASWORKBOARD) + ->setTransactionType( + PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE) ->setNewValue(1); id(new PhabricatorProjectTransactionEditor()) diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 8b77f71505..69d16c3786 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -30,7 +30,6 @@ final class PhabricatorProjectTransactionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; - $types[] = PhabricatorProjectTransaction::TYPE_HASWORKBOARD; $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_SORT; $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER; $types[] = PhabricatorProjectTransaction::TYPE_BACKGROUND; @@ -43,8 +42,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: - return (int)$object->getHasWorkboard(); case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: return $object->getDefaultWorkboardSort(); case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: @@ -64,8 +61,6 @@ final class PhabricatorProjectTransactionEditor case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: return $xaction->getNewValue(); - case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: - return (int)$xaction->getNewValue(); case PhabricatorProjectTransaction::TYPE_BACKGROUND: $value = $xaction->getNewValue(); if (!strlen($value)) { @@ -82,9 +77,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: - $object->setHasWorkboard($xaction->getNewValue()); - return; case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: $object->setDefaultWorkboardSort($xaction->getNewValue()); return; @@ -107,7 +99,6 @@ final class PhabricatorProjectTransactionEditor $new = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_HASWORKBOARD: case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: case PhabricatorProjectTransaction::TYPE_BACKGROUND: diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index b6c77808bc..cfb99d7469 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -3,7 +3,6 @@ final class PhabricatorProjectTransaction extends PhabricatorModularTransaction { - const TYPE_HASWORKBOARD = 'project:hasworkboard'; const TYPE_DEFAULT_SORT = 'project:sort'; const TYPE_DEFAULT_FILTER = 'project:filter'; const TYPE_BACKGROUND = 'project:background'; @@ -61,7 +60,6 @@ final class PhabricatorProjectTransaction public function shouldHideForFeed() { switch ($this->getTransactionType()) { - case self::TYPE_HASWORKBOARD: case self::TYPE_DEFAULT_SORT: case self::TYPE_DEFAULT_FILTER: case self::TYPE_BACKGROUND: @@ -73,7 +71,7 @@ final class PhabricatorProjectTransaction public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { - case self::TYPE_HASWORKBOARD: + case PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE: case self::TYPE_DEFAULT_SORT: case self::TYPE_DEFAULT_FILTER: case self::TYPE_BACKGROUND: @@ -142,17 +140,6 @@ final class PhabricatorProjectTransaction } break; - case self::TYPE_HASWORKBOARD: - if ($new) { - return pht( - '%s enabled the workboard for this project.', - $author_handle); - } else { - return pht( - '%s disabled the workboard for this project.', - $author_handle); - } - case self::TYPE_DEFAULT_SORT: return pht( '%s changed the default sort order for the project workboard.', diff --git a/src/applications/project/xaction/PhabricatorProjectWorkboardTransaction.php b/src/applications/project/xaction/PhabricatorProjectWorkboardTransaction.php new file mode 100644 index 0000000000..b16a1921e0 --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectWorkboardTransaction.php @@ -0,0 +1,38 @@ +getHasWorkboard(); + } + + public function generateNewValue($object, $value) { + return (int)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setHasWorkboard($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s enabled the workboard for this project.', + $this->renderAuthor()); + } else { + return pht( + '%s disabled the workboard for this project.', + $this->renderAuthor()); + } + } + + public function shouldHide() { + return true; + } + +} From 1b36252ef39bfa2f58dbc7b1d54a00d34d489fd7 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 23 May 2017 14:01:32 -0700 Subject: [PATCH 31/61] Add a dedicated HistoryListView for Diffusion Summary: Going to play a bit with this layout (diffusion sans audit) and see how it feels on profile. Uses a user image, moves the commit hash (easily selectible) and separates commits by date. Test Plan: Review profiles with and without commits. {F4973987} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18005 --- resources/celerity/map.php | 2 + src/__phutil_library_map__.php | 2 + .../view/DiffusionHistoryListView.php | 148 ++++++++++++++++++ ...bricatorPeopleProfileCommitsController.php | 11 +- .../diffusion/diffusion-history.css | 12 ++ 5 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 src/applications/diffusion/view/DiffusionHistoryListView.php create mode 100644 webroot/rsrc/css/application/diffusion/diffusion-history.css diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 2415f90ff1..8329159685 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -71,6 +71,7 @@ return array( 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', + 'rsrc/css/application/diffusion/diffusion-history.css' => 'b4ac65b3', 'rsrc/css/application/diffusion/diffusion-icons.css' => 'a6a1e2ba', 'rsrc/css/application/diffusion/diffusion-readme.css' => '18bd3910', 'rsrc/css/application/diffusion/diffusion-source.css' => '750add59', @@ -574,6 +575,7 @@ return array( 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', + 'diffusion-history-css' => 'b4ac65b3', 'diffusion-icons-css' => 'a6a1e2ba', 'diffusion-readme-css' => '18bd3910', 'diffusion-source-css' => '750add59', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 21daf85177..ff287cbb01 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -728,6 +728,7 @@ phutil_register_library_map(array( 'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php', 'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', + 'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php', 'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php', @@ -5694,6 +5695,7 @@ phutil_register_library_map(array( ), 'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionHistoryController' => 'DiffusionController', + 'DiffusionHistoryListView' => 'AphrontView', 'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', diff --git a/src/applications/diffusion/view/DiffusionHistoryListView.php b/src/applications/diffusion/view/DiffusionHistoryListView.php new file mode 100644 index 0000000000..d3223f70db --- /dev/null +++ b/src/applications/diffusion/view/DiffusionHistoryListView.php @@ -0,0 +1,148 @@ +noDataString = $no_data_string; + return $this; + } + + public function setHeader($header) { + $this->header = $header; + return $this; + } + + public function setCommits(array $commits) { + assert_instances_of($commits, 'PhabricatorRepositoryCommit'); + $this->commits = mpull($commits, null, 'getPHID'); + return $this; + } + + public function getCommits() { + return $this->commits; + } + + private function getCommitDescription($phid) { + if ($this->commits === null) { + return pht('(Unknown Commit)'); + } + + $commit = idx($this->commits, $phid); + if (!$commit) { + return pht('(Unknown Commit)'); + } + + $summary = $commit->getCommitData()->getSummary(); + if (strlen($summary)) { + return $summary; + } + + // No summary, so either this is still importing or just has an empty + // commit message. + + if (!$commit->isImported()) { + return pht('(Importing Commit...)'); + } else { + return pht('(Untitled Commit)'); + } + } + + public function render() { + require_celerity_resource('diffusion-history-css'); + return $this->buildList(); + } + + public function buildList() { + $viewer = $this->getViewer(); + $rowc = array(); + + $phids = array(); + foreach ($this->getCommits() as $commit) { + $phids[] = $commit->getPHID(); + + $author_phid = $commit->getAuthorPHID(); + if ($author_phid) { + $phids[] = $author_phid; + } + } + + $handles = $viewer->loadHandles($phids); + + $cur_date = 0; + $list = null; + $header = null; + $view = array(); + foreach ($this->commits as $commit) { + $new_date = date('Ymd', $commit->getEpoch()); + if ($cur_date != $new_date) { + if ($list) { + $view[] = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + $date = ucfirst( + phabricator_relative_date($commit->getEpoch(), $viewer)); + $header = id(new PHUIHeaderView()) + ->setHeader($date); + $list = id(new PHUIObjectItemListView()) + ->setFlush(true) + ->addClass('diffusion-history-list'); + } + + $commit_phid = $commit->getPHID(); + $commit_handle = $handles[$commit_phid]; + $committed = null; + + $commit_name = $commit_handle->getName(); + $commit_link = $commit_handle->getURI(); + $commit_desc = $this->getCommitDescription($commit_phid); + $committed = phabricator_datetime($commit->getEpoch(), $viewer); + + $author_phid = $commit->getAuthorPHID(); + if ($author_phid) { + $author_name = $handles[$author_phid]->renderLink(); + $author_image_uri = $handles[$author_phid]->getImageURI(); + } else { + $author_name = $commit->getCommitData()->getAuthorName(); + $author_image_uri = + celerity_get_resource_uri('/rsrc/image/people/user0.png'); + } + + $commit_tag = id(new PHUITagView()) + ->setName($commit_name) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor(PHUITagView::COLOR_INDIGO) + ->setSlimShady(true); + + $item = id(new PHUIObjectItemView()) + ->setHeader($commit_desc) + ->setHref($commit_link) + ->setDisabled($commit->isUnreachable()) + ->setImageURI($author_image_uri) + ->addByline(pht('Author: %s', $author_name)) + ->addIcon('none', $committed) + ->addAttribute($commit_tag); + + $list->addItem($item); + $cur_date = $new_date; + } + + if (!$view) { + $list = id(new PHUIObjectItemListView()) + ->setFlush(true) + ->setNoDataString($this->noDataString); + + $view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Recent Commits')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + + return $view; + } + +} diff --git a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php index 3e1e6de1ee..81e4fa304e 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php @@ -56,22 +56,15 @@ final class PhabricatorPeopleProfileCommitsController $commits = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withAuthorPHIDs(array($user->getPHID())) - ->needAuditRequests(true) ->needCommitData(true) - ->needDrafts(true) ->setLimit(100) ->execute(); - $list = id(new PhabricatorAuditListView()) + $list = id(new DiffusionHistoryListView()) ->setViewer($viewer) ->setCommits($commits) ->setNoDataString(pht('No recent commits.')); - $view = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Recent Commits')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($list); - - return $view; + return $list; } } diff --git a/webroot/rsrc/css/application/diffusion/diffusion-history.css b/webroot/rsrc/css/application/diffusion/diffusion-history.css new file mode 100644 index 0000000000..796b4b6059 --- /dev/null +++ b/webroot/rsrc/css/application/diffusion/diffusion-history.css @@ -0,0 +1,12 @@ +/** + * @provides diffusion-history-css + */ + +.diffusion-history-list .phui-oi-link { + color: {$darkbluetext}; + font-size: {$biggerfontsize}; +} + +.diffusion-history-list .phui-oi-attribute .phui-tag-core { + border-color: transparent; +} From 684ce701fb03746c6669c02ad3285f637c252cc2 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 23 May 2017 19:21:05 -0700 Subject: [PATCH 32/61] Add a description/toggle to PHUIObjectItemView Summary: Gives the ability to hide a big long block of text in an ObjectListItem without cluttering the UI. Test Plan: Added a test case to UIExamples. Click on icon, see content. Click again, content go away. {F4974153} {F4974311} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18006 --- resources/celerity/map.php | 10 +++--- .../view/DiffusionHistoryListView.php | 9 +++++ .../examples/PHUIObjectItemListExample.php | 2 +- src/view/phui/PHUIObjectItemView.php | 34 +++++++++++++++++++ .../diffusion/diffusion-history.css | 8 +++++ .../phui/object-item/phui-oi-list-view.css | 25 ++++++++++++++ 6 files changed, 82 insertions(+), 6 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 8329159685..a71d9f524e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '5387f8b6', + 'core.pkg.css' => '71865bdf', 'core.pkg.js' => '599698a7', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -71,7 +71,7 @@ return array( 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', - 'rsrc/css/application/diffusion/diffusion-history.css' => 'b4ac65b3', + 'rsrc/css/application/diffusion/diffusion-history.css' => '0c596546', 'rsrc/css/application/diffusion/diffusion-icons.css' => 'a6a1e2ba', 'rsrc/css/application/diffusion/diffusion-readme.css' => '18bd3910', 'rsrc/css/application/diffusion/diffusion-source.css' => '750add59', @@ -132,7 +132,7 @@ 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' => '412bef1a', + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => '78fdc98e', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', 'rsrc/css/phui/phui-action-list.css' => 'c01858f4', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', @@ -575,7 +575,7 @@ return array( 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', - 'diffusion-history-css' => 'b4ac65b3', + 'diffusion-history-css' => '0c596546', 'diffusion-icons-css' => 'a6a1e2ba', 'diffusion-readme-css' => '18bd3910', 'diffusion-source-css' => '750add59', @@ -875,7 +875,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' => '412bef1a', + 'phui-oi-list-view-css' => '78fdc98e', 'phui-oi-simple-ui-css' => 'a8beebea', 'phui-pager-css' => '77d8a794', 'phui-pinboard-view-css' => '2495140e', diff --git a/src/applications/diffusion/view/DiffusionHistoryListView.php b/src/applications/diffusion/view/DiffusionHistoryListView.php index d3223f70db..00a6eb0741 100644 --- a/src/applications/diffusion/view/DiffusionHistoryListView.php +++ b/src/applications/diffusion/view/DiffusionHistoryListView.php @@ -102,6 +102,14 @@ final class DiffusionHistoryListView extends AphrontView { $commit_desc = $this->getCommitDescription($commit_phid); $committed = phabricator_datetime($commit->getEpoch(), $viewer); + $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); + $engine->setConfig('viewer', $viewer); + $commit_data = $commit->getCommitData(); + $message = $commit_data->getCommitMessage(); + $message = $engine->markupText($message); + $message = phutil_tag_div( + 'diffusion-history-message phabricator-remarkup', $message); + $author_phid = $commit->getAuthorPHID(); if ($author_phid) { $author_name = $handles[$author_phid]->renderLink(); @@ -122,6 +130,7 @@ final class DiffusionHistoryListView extends AphrontView { ->setHeader($commit_desc) ->setHref($commit_link) ->setDisabled($commit->isUnreachable()) + ->setDescription($message) ->setImageURI($author_image_uri) ->addByline(pht('Author: %s', $author_name)) ->addIcon('none', $committed) diff --git a/src/applications/uiexample/examples/PHUIObjectItemListExample.php b/src/applications/uiexample/examples/PHUIObjectItemListExample.php index 4a75ceede1..691c84554c 100644 --- a/src/applications/uiexample/examples/PHUIObjectItemListExample.php +++ b/src/applications/uiexample/examples/PHUIObjectItemListExample.php @@ -202,7 +202,7 @@ final class PHUIObjectItemListExample extends PhabricatorUIExample { $list->addItem( id(new PHUIObjectItemView()) ->setHeader(pht('Ace of Hearts')) - ->setSubHead( + ->setDescription( pht('This is a powerful card in the game "Hearts".')) ->setHref('#') ->addAttribute(pht('Suit: Hearts')) diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php index 6d193081d2..59547c4442 100644 --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -26,6 +26,7 @@ final class PHUIObjectItemView extends AphrontTagView { private $countdownNoun; private $launchButton; private $coverImage; + private $description; public function setDisabled($disabled) { $this->disabled = $disabled; @@ -148,6 +149,11 @@ final class PHUIObjectItemView extends AphrontTagView { return $this; } + public function setDescription($description) { + $this->description = $description; + return $this; + } + public function setEpoch($epoch) { $date = phabricator_datetime($epoch, $this->getUser()); $this->addIcon('none', $date); @@ -334,6 +340,23 @@ final class PHUIObjectItemView extends AphrontTagView { ), $this->header); + $description_tag = null; + if ($this->description) { + $decription_id = celerity_generate_unique_node_id(); + $description_tag = id(new PHUITagView()) + ->setIcon('fa-ellipsis-h') + ->addClass('phui-oi-description-tag') + ->setType(PHUITagView::TYPE_SHADE) + ->setColor(PHUITagView::COLOR_GREY) + ->addSigil('jx-toggle-class') + ->setSlimShady(true) + ->setMetaData(array( + 'map' => array( + $decription_id => 'phui-oi-description-reveal', + ), + )); + } + // Wrap the header content in a with the "slippery" sigil. This // prevents us from beginning a drag if you click the text (like "T123"), // but not if you click the white space after the header. @@ -351,6 +374,7 @@ final class PHUIObjectItemView extends AphrontTagView { $this->headIcons, $header_name, $header_link, + $description_tag, ))); $icons = array(); @@ -453,6 +477,16 @@ final class PHUIObjectItemView extends AphrontTagView { $this->subhead); } + if ($this->description) { + $subhead = phutil_tag( + 'div', + array( + 'class' => 'phui-oi-subhead phui-oi-description', + 'id' => $decription_id, + ), + $this->description); + } + if ($icons) { $icons = phutil_tag( 'div', diff --git a/webroot/rsrc/css/application/diffusion/diffusion-history.css b/webroot/rsrc/css/application/diffusion/diffusion-history.css index 796b4b6059..b340cd913d 100644 --- a/webroot/rsrc/css/application/diffusion/diffusion-history.css +++ b/webroot/rsrc/css/application/diffusion/diffusion-history.css @@ -10,3 +10,11 @@ .diffusion-history-list .phui-oi-attribute .phui-tag-core { border-color: transparent; } + +.diffusion-history-message { + background-color: {$bluebackground}; + padding: 16px; + margin: 4px 0; + border-radius: 5px; + color: {$darkbluetext}; +} diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css index 26b0781e8d..cbc2d43238 100644 --- a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css @@ -285,6 +285,31 @@ ul.phui-oi-list-view { padding: 0 8px 6px; } +.phui-oi-description { + display: none; +} + +.phui-oi-description.phui-oi-description-reveal { + display: block; +} + +.phui-oi-description-tag { + margin-left: 4px; +} + +.phui-oi-description-tag:hover .phui-tag-core { + cursor: pointer; + background: {$darkgreybackground}; +} + +.phui-oi-description-tag .phui-tag-core { + border: none; +} + +.phui-oi-description-tag.phui-tag-view .phui-icon-view { + margin: 2px; +} + /* - Attribute List ------------------------------------------------------------ From c4392ba067575c5c5a6523df25dd5b341bcc1be4 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 24 May 2017 10:18:21 -0700 Subject: [PATCH 33/61] Add slugs to project manage page Summary: Minor, just shows the slugs on the manage project page, also normalized language to "details" Test Plan: review a project with slugs, description. Reviewers: amckinley Reviewed By: amckinley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D17985 --- .../project/controller/PhabricatorProjectController.php | 8 ++++++++ .../controller/PhabricatorProjectManageController.php | 7 ++++++- .../controller/PhabricatorProjectProfileController.php | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php index 45e2f193af..7c344b0b8e 100644 --- a/src/applications/project/controller/PhabricatorProjectController.php +++ b/src/applications/project/controller/PhabricatorProjectController.php @@ -166,4 +166,12 @@ abstract class PhabricatorProjectController extends PhabricatorController { ->buildResponse(); } + public function renderHashtags(array $tags) { + $result = array(); + foreach ($tags as $key => $tag) { + $result[] = '#'.$tag; + } + return implode(', ', $result); + } + } diff --git a/src/applications/project/controller/PhabricatorProjectManageController.php b/src/applications/project/controller/PhabricatorProjectManageController.php index 17b9030658..2c76c63606 100644 --- a/src/applications/project/controller/PhabricatorProjectManageController.php +++ b/src/applications/project/controller/PhabricatorProjectManageController.php @@ -138,6 +138,12 @@ final class PhabricatorProjectManageController pht('Looks Like'), $viewer->renderHandle($project->getPHID())->setAsTag(true)); + $slugs = $project->getSlugs(); + $tags = mpull($slugs, 'getSlug'); + + $view->addProperty( + pht('Hashtags'), + $this->renderHashtags($tags)); $field_list = PhabricatorCustomField::getObjectFields( $project, @@ -147,5 +153,4 @@ final class PhabricatorProjectManageController return $view; } - } diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index 32dbec3c0f..e47cc678bc 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -135,7 +135,7 @@ final class PhabricatorProjectProfileController } $header = id(new PHUIHeaderView()) - ->setHeader(pht('Properties')); + ->setHeader(pht('Details')); $view = id(new PHUIObjectBoxView()) ->setHeader($header) From 272a5d668f9e67b1ad61f6b13877974007ccf9ec Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 22 May 2017 12:24:58 -0700 Subject: [PATCH 34/61] Fix a handful of Nuance fatals Summary: Ref T12738. Some of the Nuance "form" workflows currently fatal after work on the GitHub stuff. Try to make everything stop fataling, at least. Test Plan: Using "Complaints Form" no longer fatals, and now lodges a complaint instead. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18007 --- .../autopatches/20170522.nuance.01.itemkey.sql | 2 ++ src/__phutil_library_map__.php | 2 ++ .../cursor/NuanceGitHubIssuesImportCursor.php | 3 +-- .../NuanceGitHubRepositoryImportCursor.php | 3 +-- .../nuance/item/NuanceFormItemType.php | 16 ++++++++++++++++ .../nuance/phid/NuanceItemPHIDType.php | 2 +- .../NuancePhabricatorFormSourceDefinition.php | 4 +++- .../nuance/source/NuanceSourceDefinition.php | 5 ++++- src/applications/nuance/storage/NuanceItem.php | 8 ++++++-- .../xaction/NuanceItemPropertyTransaction.php | 4 ++-- 10 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 resources/sql/autopatches/20170522.nuance.01.itemkey.sql create mode 100644 src/applications/nuance/item/NuanceFormItemType.php diff --git a/resources/sql/autopatches/20170522.nuance.01.itemkey.sql b/resources/sql/autopatches/20170522.nuance.01.itemkey.sql new file mode 100644 index 0000000000..75118205ce --- /dev/null +++ b/resources/sql/autopatches/20170522.nuance.01.itemkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_nuance.nuance_item + MODIFY itemKey VARCHAR(64) COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ff287cbb01..ac24aa3cb6 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1606,6 +1606,7 @@ phutil_register_library_map(array( 'NuanceContentSource' => 'applications/nuance/contentsource/NuanceContentSource.php', 'NuanceController' => 'applications/nuance/controller/NuanceController.php', 'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php', + 'NuanceFormItemType' => 'applications/nuance/item/NuanceFormItemType.php', 'NuanceGitHubEventItemType' => 'applications/nuance/item/NuanceGitHubEventItemType.php', 'NuanceGitHubImportCursor' => 'applications/nuance/cursor/NuanceGitHubImportCursor.php', 'NuanceGitHubIssuesImportCursor' => 'applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php', @@ -6716,6 +6717,7 @@ phutil_register_library_map(array( 'NuanceContentSource' => 'PhabricatorContentSource', 'NuanceController' => 'PhabricatorController', 'NuanceDAO' => 'PhabricatorLiskDAO', + 'NuanceFormItemType' => 'NuanceItemType', 'NuanceGitHubEventItemType' => 'NuanceItemType', 'NuanceGitHubImportCursor' => 'NuanceImportCursor', 'NuanceGitHubIssuesImportCursor' => 'NuanceGitHubImportCursor', diff --git a/src/applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php b/src/applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php index d250b1d02d..151a5876ba 100644 --- a/src/applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php +++ b/src/applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php @@ -17,10 +17,9 @@ final class NuanceGitHubIssuesImportCursor $container_key = null; - return NuanceItem::initializeNewItem() + return NuanceItem::initializeNewItem(NuanceGitHubEventItemType::ITEMTYPE) ->setStatus(NuanceItem::STATUS_IMPORTING) ->setSourcePHID($source->getPHID()) - ->setItemType(NuanceGitHubEventItemType::ITEMTYPE) ->setItemKey($item_key) ->setItemContainerKey($container_key) ->setItemProperty('api.type', 'issue') diff --git a/src/applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php b/src/applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php index 72aca276d2..018b3aa8c1 100644 --- a/src/applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php +++ b/src/applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php @@ -36,10 +36,9 @@ final class NuanceGitHubRepositoryImportCursor $container_key = "github.issue.{$issue_id}"; } - return NuanceItem::initializeNewItem() + return NuanceItem::initializeNewItem(NuanceGitHubEventItemType::ITEMTYPE) ->setStatus(NuanceItem::STATUS_IMPORTING) ->setSourcePHID($source->getPHID()) - ->setItemType(NuanceGitHubEventItemType::ITEMTYPE) ->setItemKey($item_key) ->setItemContainerKey($container_key) ->setItemProperty('api.type', 'repository') diff --git a/src/applications/nuance/item/NuanceFormItemType.php b/src/applications/nuance/item/NuanceFormItemType.php new file mode 100644 index 0000000000..ee2f923d08 --- /dev/null +++ b/src/applications/nuance/item/NuanceFormItemType.php @@ -0,0 +1,16 @@ + $handle) { $item = $objects[$phid]; - $handle->setName($item->getItemDisplayName()); + $handle->setName($item->getDisplayName()); $handle->setURI($item->getURI()); } } diff --git a/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php b/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php index e7c7212590..2eaf5781dc 100644 --- a/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php +++ b/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php @@ -39,6 +39,8 @@ final class NuancePhabricatorFormSourceDefinition $content_source = PhabricatorContentSource::newFromRequest($request); $item = $this->newItemFromProperties( + NuanceFormItemType::ITEMTYPE, + $viewer->getPHID(), $properties, $content_source); @@ -79,7 +81,7 @@ final class NuancePhabricatorFormSourceDefinition NuanceItem $item, PHUIPropertyListView $view) { - $complaint = $item->getNuanceProperty('complaint'); + $complaint = $item->getItemProperty('complaint'); $complaint = new PHUIRemarkupView($viewer, $complaint); $view->addSectionHeader( pht('Complaint'), 'fa-exclamation-circle'); diff --git a/src/applications/nuance/source/NuanceSourceDefinition.php b/src/applications/nuance/source/NuanceSourceDefinition.php index 0330aa5c7e..2c4ebc65e5 100644 --- a/src/applications/nuance/source/NuanceSourceDefinition.php +++ b/src/applications/nuance/source/NuanceSourceDefinition.php @@ -149,6 +149,8 @@ abstract class NuanceSourceDefinition extends Phobject { } protected function newItemFromProperties( + $item_type, + $author_phid, array $properties, PhabricatorContentSource $content_source) { @@ -157,7 +159,7 @@ abstract class NuanceSourceDefinition extends Phobject { $actor = PhabricatorUser::getOmnipotentUser(); $source = $this->getSource(); - $item = NuanceItem::initializeNewItem(); + $item = NuanceItem::initializeNewItem($item_type); $xactions = array(); @@ -181,6 +183,7 @@ abstract class NuanceSourceDefinition extends Phobject { $editor = id(new NuanceItemEditor()) ->setActor($actor) + ->setActingAsPHID($author_phid) ->setContentSource($content_source); $editor->applyTransactions($item, $xactions); diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php index 2eadcdb2d9..9fbfea8dae 100644 --- a/src/applications/nuance/storage/NuanceItem.php +++ b/src/applications/nuance/storage/NuanceItem.php @@ -26,8 +26,12 @@ final class NuanceItem private $source = self::ATTACHABLE; private $implementation = self::ATTACHABLE; - public static function initializeNewItem() { + public static function initializeNewItem($item_type) { + + // TODO: Validate that the type is valid, and construct and attach it. + return id(new NuanceItem()) + ->setItemType($item_type) ->setStatus(self::STATUS_OPEN); } @@ -42,7 +46,7 @@ final class NuanceItem 'requestorPHID' => 'phid?', 'queuePHID' => 'phid?', 'itemType' => 'text64', - 'itemKey' => 'text64', + 'itemKey' => 'text64?', 'itemContainerKey' => 'text64?', 'status' => 'text32', 'mailKey' => 'bytes20', diff --git a/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php index 76724843de..3367a6a0cf 100644 --- a/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php +++ b/src/applications/nuance/xaction/NuanceItemPropertyTransaction.php @@ -8,14 +8,14 @@ final class NuanceItemPropertyTransaction public function generateOldValue($object) { $property_key = NuanceItemTransaction::PROPERTY_KEY; $key = $this->getMetadataValue($property_key); - return $object->getNuanceProperty($key); + return $object->getItemProperty($key); } public function applyInternalEffects($object, $value) { $property_key = NuanceItemTransaction::PROPERTY_KEY; $key = $this->getMetadataValue($property_key); - $object->setNuanceProperty($key, $value); + $object->setItemProperty($key, $value); } public function getTitle() { From cbf9008d158fedb42a2957f9d541877467bbafe9 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 06:51:59 -0700 Subject: [PATCH 35/61] Rough in a Nuance "work" controller Summary: Ref T12738. This is mostly just laying in groundwork and prerequisites, like the ability to query items by queue. Eventually, this will become the main UI which staff use to process a queue of items. For now, it does nothing and renders nonsense. This and probably the next big chunk of changes are all going to be made-up, nonfinal things that just make basic operations work until we have fundamental flows -- like "assign", "comment", "close" -- working at a basic level and can think more about UI/workflow. Test Plan: Visited the page, it loaded a mostly-reasonable item and then rendered nonsense: {F4975050} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18008 --- src/__phutil_library_map__.php | 2 + .../PhabricatorNuanceApplication.php | 1 + .../controller/NuanceQueueViewController.php | 8 ++ .../controller/NuanceQueueWorkController.php | 98 +++++++++++++++++++ .../nuance/query/NuanceItemQuery.php | 69 ++++++++++++- .../nuance/query/NuanceItemSearchEngine.php | 13 +++ .../nuance/storage/NuanceItem.php | 10 ++ 7 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 src/applications/nuance/controller/NuanceQueueWorkController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ac24aa3cb6..cc16cb4e88 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1663,6 +1663,7 @@ phutil_register_library_map(array( 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', 'NuanceQueueTransactionType' => 'applications/nuance/xaction/NuanceQueueTransactionType.php', 'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php', + 'NuanceQueueWorkController' => 'applications/nuance/controller/NuanceQueueWorkController.php', 'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php', 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', 'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php', @@ -6788,6 +6789,7 @@ phutil_register_library_map(array( 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceQueueTransactionType' => 'PhabricatorModularTransactionType', 'NuanceQueueViewController' => 'NuanceQueueController', + 'NuanceQueueWorkController' => 'NuanceQueueController', 'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'NuanceSource' => array( 'NuanceDAO', diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php index cf18bc389d..9f99c9e5bd 100644 --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -51,6 +51,7 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication { $this->getQueryRoutePattern() => 'NuanceQueueListController', $this->getEditRoutePattern('edit/') => 'NuanceQueueEditController', 'view/(?P[1-9]\d*)/' => 'NuanceQueueViewController', + 'work/(?P[1-9]\d*)/' => 'NuanceQueueWorkController', ), ), '/action/' => array( diff --git a/src/applications/nuance/controller/NuanceQueueViewController.php b/src/applications/nuance/controller/NuanceQueueViewController.php index 8f4e85565a..f5284f6bfa 100644 --- a/src/applications/nuance/controller/NuanceQueueViewController.php +++ b/src/applications/nuance/controller/NuanceQueueViewController.php @@ -70,6 +70,14 @@ final class NuanceQueueViewController ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Begin Work')) + ->setIcon('fa-play-circle-o') + ->setHref($this->getApplicationURI("queue/work/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + return $curtain; } diff --git a/src/applications/nuance/controller/NuanceQueueWorkController.php b/src/applications/nuance/controller/NuanceQueueWorkController.php new file mode 100644 index 0000000000..3d6308664d --- /dev/null +++ b/src/applications/nuance/controller/NuanceQueueWorkController.php @@ -0,0 +1,98 @@ +getViewer(); + + $queue = id(new NuanceQueueQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->executeOne(); + if (!$queue) { + return new Aphront404Response(); + } + + $title = $queue->getName(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Queues'), $this->getApplicationURI('queue/')); + $crumbs->addTextCrumb($queue->getName(), $queue->getURI()); + $crumbs->addTextCrumb(pht('Work')); + $crumbs->setBorder(true); + + // For now, just pick the first open item. + + $items = id(new NuanceItemQuery()) + ->setViewer($viewer) + ->withQueuePHIDs( + array( + $queue->getPHID(), + )) + ->withStatuses( + array( + NuanceItem::STATUS_OPEN, + )) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->setLimit(5) + ->execute(); + + if (!$items) { + return $this->newDialog() + ->setTitle(pht('Queue Empty')) + ->appendParagraph( + pht( + 'This queue has no open items which you have permission to '. + 'work on.')) + ->addCancelButton($queue->getURI()); + } + + $item = head($items); + + $curtain = $this->buildCurtain($queue); + + $timeline = $this->buildTransactionTimeline( + $item, + new NuanceItemTransactionQuery()); + $timeline->setShouldTerminate(true); + + $view = id(new PHUITwoColumnView()) + ->setCurtain($curtain) + ->setMainColumn($timeline); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } + + private function buildCurtain(NuanceQueue $queue) { + $viewer = $this->getViewer(); + $id = $queue->getID(); + + $curtain = $this->newCurtainView(); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_LABEL) + ->setName(pht('Queue Actions'))); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Manage Queue')) + ->setIcon('fa-cog') + ->setHref($this->getApplicationURI("queue/view/{$id}/"))); + + return $curtain; + } + +} diff --git a/src/applications/nuance/query/NuanceItemQuery.php b/src/applications/nuance/query/NuanceItemQuery.php index 5bb0ec70ec..834e81ca72 100644 --- a/src/applications/nuance/query/NuanceItemQuery.php +++ b/src/applications/nuance/query/NuanceItemQuery.php @@ -6,9 +6,11 @@ final class NuanceItemQuery private $ids; private $phids; private $sourcePHIDs; + private $queuePHIDs; private $itemTypes; private $itemKeys; private $containerKeys; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -25,6 +27,11 @@ final class NuanceItemQuery return $this; } + public function withQueuePHIDs(array $queue_phids) { + $this->queuePHIDs = $queue_phids; + return $this; + } + public function withItemTypes(array $item_types) { $this->itemTypes = $item_types; return $this; @@ -35,6 +42,11 @@ final class NuanceItemQuery return $this; } + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function withItemContainerKeys(array $container_keys) { $this->containerKeys = $container_keys; return $this; @@ -49,13 +61,11 @@ final class NuanceItemQuery } protected function willFilterPage(array $items) { + $viewer = $this->getViewer(); $source_phids = mpull($items, 'getSourcePHID'); - // NOTE: We always load sources, even if the viewer can't formally see - // them. If they can see the item, they're allowed to be aware of the - // source in some sense. $sources = id(new NuanceSourceQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->setViewer($viewer) ->withPHIDs($source_phids) ->execute(); $sources = mpull($sources, null, 'getPHID'); @@ -81,6 +91,43 @@ final class NuanceItemQuery $item->attachImplementation($type); } + $queue_phids = array(); + foreach ($items as $item) { + $queue_phid = $item->getQueuePHID(); + if ($queue_phid) { + $queue_phids[$queue_phid] = $queue_phid; + } + } + + if ($queue_phids) { + $queues = id(new NuanceQueueQuery()) + ->setViewer($viewer) + ->withPHIDs($queue_phids) + ->execute(); + $queues = mpull($queues, null, 'getPHID'); + } else { + $queues = array(); + } + + foreach ($items as $key => $item) { + $queue_phid = $item->getQueuePHID(); + + if (!$queue_phid) { + $item->attachQueue(null); + continue; + } + + $queue = idx($queues, $queue_phid); + + if (!$queue) { + unset($items[$key]); + $this->didRejectResult($item); + continue; + } + + $item->attachQueue($queue); + } + return $items; } @@ -94,6 +141,13 @@ final class NuanceItemQuery $this->sourcePHIDs); } + if ($this->queuePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'queuePHID IN (%Ls)', + $this->queuePHIDs); + } + if ($this->ids !== null) { $where[] = qsprintf( $conn, @@ -108,6 +162,13 @@ final class NuanceItemQuery $this->phids); } + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'status IN (%Ls)', + $this->statuses); + } + if ($this->itemTypes !== null) { $where[] = qsprintf( $conn, diff --git a/src/applications/nuance/query/NuanceItemSearchEngine.php b/src/applications/nuance/query/NuanceItemSearchEngine.php index 2f0951b4e0..0868d7551a 100644 --- a/src/applications/nuance/query/NuanceItemSearchEngine.php +++ b/src/applications/nuance/query/NuanceItemSearchEngine.php @@ -72,6 +72,19 @@ final class NuanceItemSearchEngine $impl->getItemTypeDisplayIcon(), $impl->getItemTypeDisplayName()); + $queue = $item->getQueue(); + if ($queue) { + $view->addAttribute( + phutil_tag( + 'a', + array( + 'href' => $queue->getURI(), + ), + $queue->getName())); + } else { + $view->addAttribute(phutil_tag('em', array(), pht('Not in Queue'))); + } + $list->addItem($view); } diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php index 9fbfea8dae..b1deab3af2 100644 --- a/src/applications/nuance/storage/NuanceItem.php +++ b/src/applications/nuance/storage/NuanceItem.php @@ -23,6 +23,7 @@ final class NuanceItem protected $data = array(); protected $mailKey; + private $queue = self::ATTACHABLE; private $source = self::ATTACHABLE; private $implementation = self::ATTACHABLE; @@ -176,6 +177,15 @@ final class NuanceItem return $this; } + public function getQueue() { + return $this->assertAttached($this->queue); + } + + public function attachQueue(NuanceQueue $queue = null) { + $this->queue = $queue; + return $this; + } + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ From e1b8532e2478395bd1f36baecb998adeef5bea3d Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 07:36:46 -0700 Subject: [PATCH 36/61] Allow Nuance items to put commands actions into the work UI Summary: Ref T12738. This doesn't actually do anything yet, but allows items to define commands that show up in the UI. Adds a "Throw in Trash" item for complaints. This construction will allow future changes to add an `EngineExtension` which can provide generic/default commands across item types. Test Plan: {F4975086} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18009 --- src/__phutil_library_map__.php | 2 + .../nuance/command/NuanceItemCommandSpec.php | 37 +++++++++++++++++++ .../controller/NuanceQueueWorkController.php | 31 ++++++++++++++-- .../nuance/item/NuanceFormItemType.php | 34 +++++++++++++++++ .../nuance/item/NuanceItemType.php | 12 ++++++ 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 src/applications/nuance/command/NuanceItemCommandSpec.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index cc16cb4e88..45a9aa2b96 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1622,6 +1622,7 @@ phutil_register_library_map(array( 'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php', 'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php', 'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php', + 'NuanceItemCommandSpec' => 'applications/nuance/command/NuanceItemCommandSpec.php', 'NuanceItemCommandTransaction' => 'applications/nuance/xaction/NuanceItemCommandTransaction.php', 'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php', 'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php', @@ -6744,6 +6745,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', ), 'NuanceItemCommandQuery' => 'NuanceQuery', + 'NuanceItemCommandSpec' => 'Phobject', 'NuanceItemCommandTransaction' => 'NuanceItemTransactionType', 'NuanceItemController' => 'NuanceController', 'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor', diff --git a/src/applications/nuance/command/NuanceItemCommandSpec.php b/src/applications/nuance/command/NuanceItemCommandSpec.php new file mode 100644 index 0000000000..d449e54833 --- /dev/null +++ b/src/applications/nuance/command/NuanceItemCommandSpec.php @@ -0,0 +1,37 @@ +commandKey = $command_key; + return $this; + } + + public function getCommandKey() { + return $this->commandKey; + } + + public function setName($name) { + $this->name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setIcon($icon) { + $this->icon = $icon; + return $this; + } + + public function getIcon() { + return $this->icon; + } + +} diff --git a/src/applications/nuance/controller/NuanceQueueWorkController.php b/src/applications/nuance/controller/NuanceQueueWorkController.php index 3d6308664d..fb979c4e02 100644 --- a/src/applications/nuance/controller/NuanceQueueWorkController.php +++ b/src/applications/nuance/controller/NuanceQueueWorkController.php @@ -54,16 +54,25 @@ final class NuanceQueueWorkController $item = head($items); - $curtain = $this->buildCurtain($queue); + $curtain = $this->buildCurtain($queue, $item); $timeline = $this->buildTransactionTimeline( $item, new NuanceItemTransactionQuery()); $timeline->setShouldTerminate(true); + $impl = $item->getImplementation() + ->setViewer($viewer); + + $work_content = $impl->buildItemWorkView($item); + $view = id(new PHUITwoColumnView()) ->setCurtain($curtain) - ->setMainColumn($timeline); + ->setMainColumn( + array( + $work_content, + $timeline, + )); return $this->newPage() ->setTitle($title) @@ -71,12 +80,28 @@ final class NuanceQueueWorkController ->appendChild($view); } - private function buildCurtain(NuanceQueue $queue) { + private function buildCurtain(NuanceQueue $queue, NuanceItem $item) { $viewer = $this->getViewer(); $id = $queue->getID(); $curtain = $this->newCurtainView(); + $impl = $item->getImplementation(); + $commands = $impl->buildWorkCommands($item); + + foreach ($commands as $command) { + $command_key = $command->getCommandKey(); + + $item_id = $item->getID(); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName($command->getName()) + ->setIcon($command->getIcon()) + ->setHref("queue/command/{$id}/{$command_key}/{$item_id}/")) + ->setWorkflow(true); + } + $curtain->addAction( id(new PhabricatorActionView()) ->setType(PhabricatorActionView::TYPE_DIVIDER)); diff --git a/src/applications/nuance/item/NuanceFormItemType.php b/src/applications/nuance/item/NuanceFormItemType.php index ee2f923d08..401d20fd87 100644 --- a/src/applications/nuance/item/NuanceFormItemType.php +++ b/src/applications/nuance/item/NuanceFormItemType.php @@ -13,4 +13,38 @@ final class NuanceFormItemType return pht('Complaint'); } + protected function newWorkCommands(NuanceItem $item) { + return array( + $this->newCommand('trash') + ->setIcon('fa-trash') + ->setName(pht('Throw In Trash')), + ); + } + + protected function newItemView(NuanceItem $item) { + $viewer = $this->getViewer(); + + $content = $item->getItemProperty('complaint'); + $content_view = id(new PHUIRemarkupView($viewer, $content)) + ->setContextObject($item); + + $content_section = id(new PHUIPropertyListView()) + ->addTextContent( + phutil_tag( + 'div', + array( + 'class' => 'phabricator-remarkup', + ), + $content_view)); + + $content_box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Complaint')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($content_section); + + return array( + $content_box, + ); + } + } diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php index ff89108f4a..c0c78c9efa 100644 --- a/src/applications/nuance/item/NuanceItemType.php +++ b/src/applications/nuance/item/NuanceItemType.php @@ -32,6 +32,10 @@ abstract class NuanceItemType return $this->newItemView($item); } + final public function buildItemWorkView(NuanceItem $item) { + return $this->newItemView($item); + } + protected function newItemView(NuanceItem $item) { return null; } @@ -104,6 +108,10 @@ abstract class NuanceItemType return null; } + final public function buildWorkCommands(NuanceItem $item) { + return $this->newWorkCommands($item); + } + final public function applyCommand( NuanceItem $item, NuanceItemCommand $command) { @@ -159,4 +167,8 @@ abstract class NuanceItemType return id(new PhabricatorNuanceApplication())->getPHID(); } + protected function newCommand($command_key) { + return id(new NuanceItemCommandSpec()) + ->setCommandKey($command_key); + } } From 7e91f42b02b0a8e91d77f038fd0c9ac4ac47ff19 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 09:28:36 -0700 Subject: [PATCH 37/61] Issue commands to Nuance items, at least roughly Summary: Ref T12738. This makes clicking "Throw In Trash" technically do something, sort of. In Nuance, the default mode of operation for actions is asynchronous -- so you don't have to wait for a response from Twitter or GitHub after you mash the "send default reply tweet" / "close this pull request with a nice response" button and can move directly to the next item instead. In the future, some operations will attempt to apply synchronously (e.g., local actions like "ignore this item forever"). This fakes our way through that for now. There's also no connection to the action actually doing anything yet, but I'll probably rig that up next. Test Plan: {F4975227} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18010 --- .../20170524.nuance.01.command.sql | 8 +++ .../20170524.nuance.02.commandstatus.sql | 5 ++ .../PhabricatorNuanceApplication.php | 2 + .../controller/NuanceItemActionController.php | 66 +++++++++++++++++- .../controller/NuanceItemViewController.php | 34 ---------- .../controller/NuanceQueueWorkController.php | 67 ++++++++++++++++++- .../nuance/item/NuanceFormItemType.php | 4 ++ .../nuance/item/NuanceItemType.php | 8 +-- .../nuance/query/NuanceItemCommandQuery.php | 13 ++++ .../nuance/storage/NuanceItemCommand.php | 64 ++++++++++++++++-- .../nuance/storage/NuanceQueue.php | 4 ++ .../nuance/worker/NuanceItemUpdateWorker.php | 23 ++++++- 12 files changed, 247 insertions(+), 51 deletions(-) create mode 100644 resources/sql/autopatches/20170524.nuance.01.command.sql create mode 100644 resources/sql/autopatches/20170524.nuance.02.commandstatus.sql diff --git a/resources/sql/autopatches/20170524.nuance.01.command.sql b/resources/sql/autopatches/20170524.nuance.01.command.sql new file mode 100644 index 0000000000..529756e748 --- /dev/null +++ b/resources/sql/autopatches/20170524.nuance.01.command.sql @@ -0,0 +1,8 @@ +ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand + ADD dateCreated INT UNSIGNED NOT NULL; + +ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand + ADD dateModified INT UNSIGNED NOT NULL; + +ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand + ADD queuePHID VARBINARY(64); diff --git a/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql b/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql new file mode 100644 index 0000000000..14f57af053 --- /dev/null +++ b/resources/sql/autopatches/20170524.nuance.02.commandstatus.sql @@ -0,0 +1,5 @@ +ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand + ADD status VARCHAR(64) NOT NULL; + +UPDATE {$NAMESPACE}_nuance.nuance_itemcommand + SET status = 'done' WHERE status = ''; diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php index 9f99c9e5bd..cd268dd95e 100644 --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -52,6 +52,8 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication { $this->getEditRoutePattern('edit/') => 'NuanceQueueEditController', 'view/(?P[1-9]\d*)/' => 'NuanceQueueViewController', 'work/(?P[1-9]\d*)/' => 'NuanceQueueWorkController', + 'action/(?P[1-9]\d*)/(?P[^/]+)/(?P[1-9]\d*)/' + => 'NuanceItemActionController', ), ), '/action/' => array( diff --git a/src/applications/nuance/controller/NuanceItemActionController.php b/src/applications/nuance/controller/NuanceItemActionController.php index c64ac5f6ac..c6dc139b11 100644 --- a/src/applications/nuance/controller/NuanceItemActionController.php +++ b/src/applications/nuance/controller/NuanceItemActionController.php @@ -6,6 +6,14 @@ final class NuanceItemActionController extends NuanceController { $viewer = $this->getViewer(); $id = $request->getURIData('id'); + if (!$request->validateCSRF()) { + return new Aphront400Response(); + } + + // NOTE: This controller can be reached from an individual item (usually + // by a user) or while working through a queue (usually by staff). When + // a command originates from a queue, the URI will have a queue ID. + $item = id(new NuanceItemQuery()) ->setViewer($viewer) ->withIDs(array($id)) @@ -14,13 +22,69 @@ final class NuanceItemActionController extends NuanceController { return new Aphront404Response(); } + $cancel_uri = $item->getURI(); + + $queue_id = $request->getURIData('queueID'); + $queue = null; + if ($queue_id) { + $queue = id(new NuanceQueueQuery()) + ->setViewer($viewer) + ->withIDs(array($queue_id)) + ->executeOne(); + if (!$queue) { + return new Aphront404Response(); + } + + $item_queue = $item->getQueue(); + if (!$item_queue || ($item_queue->getPHID() != $queue->getPHID())) { + return $this->newDialog() + ->setTitle(pht('Wrong Queue')) + ->appendParagraph( + pht( + 'You are trying to act on this item from the wrong queue: it '. + 'is currently in a different queue.')) + ->addCancelButton($cancel_uri); + } + } + $action = $request->getURIData('action'); $impl = $item->getImplementation(); $impl->setViewer($viewer); $impl->setController($this); - return $impl->buildActionResponse($item, $action); + $command = NuanceItemCommand::initializeNewCommand() + ->setItemPHID($item->getPHID()) + ->setAuthorPHID($viewer->getPHID()) + ->setCommand($action); + + if ($queue) { + $command->setQueuePHID($queue->getPHID()); + } + + $command->save(); + + // TODO: Here, we should check if the command should be tried immediately, + // and just defer it to the daemons if not. If we're going to try to apply + // the command directly, we should first acquire the worker lock. If we + // can not, we should defer the command even if it's an immediate command. + // For the moment, skip all this stuff by deferring unconditionally. + + $should_defer = true; + if ($should_defer) { + $item->scheduleUpdate(); + } else { + // ... + } + + if ($queue) { + $done_uri = $queue->getWorkURI(); + } else { + $done_uri = $item->getURI(); + } + + return id(new AphrontRedirectResponse()) + ->setURI($done_uri); } } diff --git a/src/applications/nuance/controller/NuanceItemViewController.php b/src/applications/nuance/controller/NuanceItemViewController.php index 7ef5d06682..a902dc3b06 100644 --- a/src/applications/nuance/controller/NuanceItemViewController.php +++ b/src/applications/nuance/controller/NuanceItemViewController.php @@ -26,14 +26,12 @@ final class NuanceItemViewController extends NuanceController { $curtain = $this->buildCurtain($item); $content = $this->buildContent($item); - $commands = $this->buildCommands($item); $timeline = $this->buildTransactionTimeline( $item, new NuanceItemTransactionQuery()); $main = array( - $commands, $content, $timeline, ); @@ -91,36 +89,4 @@ final class NuanceItemViewController extends NuanceController { return $impl->buildItemView($item); } - private function buildCommands(NuanceItem $item) { - $viewer = $this->getViewer(); - - $commands = id(new NuanceItemCommandQuery()) - ->setViewer($viewer) - ->withItemPHIDs(array($item->getPHID())) - ->execute(); - $commands = msort($commands, 'getID'); - - if (!$commands) { - return null; - } - - $rows = array(); - foreach ($commands as $command) { - $rows[] = array( - $command->getCommand(), - ); - } - - $table = id(new AphrontTableView($rows)) - ->setHeaders( - array( - pht('Command'), - )); - - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Pending Commands')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); - } - } diff --git a/src/applications/nuance/controller/NuanceQueueWorkController.php b/src/applications/nuance/controller/NuanceQueueWorkController.php index fb979c4e02..8703a69334 100644 --- a/src/applications/nuance/controller/NuanceQueueWorkController.php +++ b/src/applications/nuance/controller/NuanceQueueWorkController.php @@ -64,12 +64,14 @@ final class NuanceQueueWorkController $impl = $item->getImplementation() ->setViewer($viewer); + $commands = $this->buildCommands($item); $work_content = $impl->buildItemWorkView($item); $view = id(new PHUITwoColumnView()) ->setCurtain($curtain) ->setMainColumn( array( + $commands, $work_content, $timeline, )); @@ -94,12 +96,15 @@ final class NuanceQueueWorkController $item_id = $item->getID(); + $action_uri = "queue/action/{$id}/{$command_key}/{$item_id}/"; + $action_uri = $this->getApplicationURI($action_uri); + $curtain->addAction( id(new PhabricatorActionView()) ->setName($command->getName()) ->setIcon($command->getIcon()) - ->setHref("queue/command/{$id}/{$command_key}/{$item_id}/")) - ->setWorkflow(true); + ->setHref($action_uri) + ->setWorkflow(true)); } $curtain->addAction( @@ -120,4 +125,62 @@ final class NuanceQueueWorkController return $curtain; } + private function buildCommands(NuanceItem $item) { + $viewer = $this->getViewer(); + + $commands = id(new NuanceItemCommandQuery()) + ->setViewer($viewer) + ->withItemPHIDs(array($item->getPHID())) + ->withStatuses( + array( + NuanceItemCommand::STATUS_ISSUED, + NuanceItemCommand::STATUS_EXECUTING, + NuanceItemCommand::STATUS_FAILED, + )) + ->execute(); + $commands = msort($commands, 'getID'); + + if (!$commands) { + return null; + } + + $rows = array(); + foreach ($commands as $command) { + $icon = $command->getStatusIcon(); + $color = $command->getStatusColor(); + + $rows[] = array( + $command->getID(), + id(new PHUIIconView()) + ->setIcon($icon, $color), + $viewer->renderHandle($command->getAuthorPHID()), + $command->getCommand(), + phabricator_datetime($command->getDateCreated(), $viewer), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('ID'), + null, + pht('Actor'), + pht('Command'), + pht('Date'), + )) + ->setColumnClasses( + array( + null, + 'icon', + null, + 'pri', + 'wide right', + )); + + return id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Pending Commands')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($table); + } + } diff --git a/src/applications/nuance/item/NuanceFormItemType.php b/src/applications/nuance/item/NuanceFormItemType.php index 401d20fd87..cbdde0e89c 100644 --- a/src/applications/nuance/item/NuanceFormItemType.php +++ b/src/applications/nuance/item/NuanceFormItemType.php @@ -47,4 +47,8 @@ final class NuanceFormItemType ); } + protected function handleAction(NuanceItem $item, $action) { + return null; + } + } diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php index c0c78c9efa..de64977cb3 100644 --- a/src/applications/nuance/item/NuanceItemType.php +++ b/src/applications/nuance/item/NuanceItemType.php @@ -95,13 +95,7 @@ abstract class NuanceItemType } final public function buildActionResponse(NuanceItem $item, $action) { - $response = $this->handleAction($item, $action); - - if ($response === null) { - return new Aphront404Response(); - } - - return $response; + return $this->handleAction($item, $action); } protected function handleAction(NuanceItem $item, $action) { diff --git a/src/applications/nuance/query/NuanceItemCommandQuery.php b/src/applications/nuance/query/NuanceItemCommandQuery.php index cb20610187..27137cf8f6 100644 --- a/src/applications/nuance/query/NuanceItemCommandQuery.php +++ b/src/applications/nuance/query/NuanceItemCommandQuery.php @@ -5,6 +5,7 @@ final class NuanceItemCommandQuery private $ids; private $itemPHIDs; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -16,6 +17,11 @@ final class NuanceItemCommandQuery return $this; } + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function newResultObject() { return new NuanceItemCommand(); } @@ -41,6 +47,13 @@ final class NuanceItemCommandQuery $this->itemPHIDs); } + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'status IN (%Ls)', + $this->statuses); + } + return $where; } diff --git a/src/applications/nuance/storage/NuanceItemCommand.php b/src/applications/nuance/storage/NuanceItemCommand.php index bda6860ff5..21d3792ff2 100644 --- a/src/applications/nuance/storage/NuanceItemCommand.php +++ b/src/applications/nuance/storage/NuanceItemCommand.php @@ -4,32 +4,86 @@ final class NuanceItemCommand extends NuanceDAO implements PhabricatorPolicyInterface { + const STATUS_ISSUED = 'issued'; + const STATUS_EXECUTING = 'executing'; + const STATUS_DONE = 'done'; + const STATUS_FAILED = 'failed'; + protected $itemPHID; protected $authorPHID; + protected $queuePHID; protected $command; - protected $parameters; + protected $status; + protected $parameters = array(); public static function initializeNewCommand() { - return new self(); + return id(new self()) + ->setStatus(self::STATUS_ISSUED); } protected function getConfiguration() { return array( - self::CONFIG_TIMESTAMPS => false, self::CONFIG_SERIALIZATION => array( 'parameters' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'command' => 'text64', + 'status' => 'text64', + 'queuePHID' => 'phid?', ), self::CONFIG_KEY_SCHEMA => array( - 'key_item' => array( - 'columns' => array('itemPHID'), + 'key_pending' => array( + 'columns' => array('itemPHID', 'status'), ), ), ) + parent::getConfiguration(); } + public static function getStatusMap() { + return array( + self::STATUS_ISSUED => array( + 'name' => pht('Issued'), + 'icon' => 'fa-clock-o', + 'color' => 'bluegrey', + ), + self::STATUS_EXECUTING => array( + 'name' => pht('Executing'), + 'icon' => 'fa-play', + 'color' => 'green', + ), + self::STATUS_DONE => array( + 'name' => pht('Done'), + 'icon' => 'fa-check', + 'color' => 'blue', + ), + self::STATUS_FAILED => array( + 'name' => pht('Failed'), + 'icon' => 'fa-times', + 'color' => 'red', + ), + ); + } + + private function getStatusSpec() { + $map = self::getStatusMap(); + return idx($map, $this->getStatus(), array()); + } + + public function getStatusIcon() { + $spec = $this->getStatusSpec(); + return idx($spec, 'icon', 'fa-question'); + } + + public function getStatusColor() { + $spec = $this->getStatusSpec(); + return idx($spec, 'color', 'indigo'); + } + + public function getStatusName() { + $spec = $this->getStatusSpec(); + return idx($spec, 'name', $this->getStatus()); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/nuance/storage/NuanceQueue.php b/src/applications/nuance/storage/NuanceQueue.php index 9691a42e2f..f0ba5bb45c 100644 --- a/src/applications/nuance/storage/NuanceQueue.php +++ b/src/applications/nuance/storage/NuanceQueue.php @@ -43,6 +43,10 @@ final class NuanceQueue return '/nuance/queue/view/'.$this->getID().'/'; } + public function getWorkURI() { + return '/nuance/queue/work/'.$this->getID().'/'; + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/nuance/worker/NuanceItemUpdateWorker.php b/src/applications/nuance/worker/NuanceItemUpdateWorker.php index 57be20edae..5f33f885f9 100644 --- a/src/applications/nuance/worker/NuanceItemUpdateWorker.php +++ b/src/applications/nuance/worker/NuanceItemUpdateWorker.php @@ -61,12 +61,31 @@ final class NuanceItemUpdateWorker $commands = id(new NuanceItemCommandQuery()) ->setViewer($viewer) ->withItemPHIDs(array($item->getPHID())) + ->withStatuses( + array( + NuanceItemCommand::STATUS_ISSUED, + )) ->execute(); $commands = msort($commands, 'getID'); foreach ($commands as $command) { - $impl->applyCommand($item, $command); - $command->delete(); + $command + ->setStatus(NuanceItemCommand::STATUS_EXECUTING) + ->save(); + + try { + $impl->applyCommand($item, $command); + + $command + ->setStatus(NuanceItemCommand::STATUS_DONE) + ->save(); + } catch (Exception $ex) { + $command + ->setStatus(NuanceItemCommand::STATUS_FAILED) + ->save(); + + throw $ex; + } } } From 8374ec46fdabf4184734d2748395a90342eb98d6 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 10:16:53 -0700 Subject: [PATCH 38/61] Make throwing things into the trash actually work in Nuance Summary: Ref T12738. Implements some modular behavior for Nuance commands. Test Plan: {F4975322} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18011 --- src/__phutil_library_map__.php | 6 + .../command/NuanceCommandImplementation.php | 107 ++++++++++++++++++ .../nuance/command/NuanceTrashCommand.php | 23 ++++ .../nuance/item/NuanceGitHubEventItemType.php | 3 + .../nuance/item/NuanceItemType.php | 40 ------- .../nuance/storage/NuanceItem.php | 1 - .../nuance/worker/NuanceItemUpdateWorker.php | 18 ++- .../xaction/NuanceItemCommandTransaction.php | 12 +- .../xaction/NuanceItemStatusTransaction.php | 25 ++++ 9 files changed, 187 insertions(+), 48 deletions(-) create mode 100644 src/applications/nuance/command/NuanceCommandImplementation.php create mode 100644 src/applications/nuance/command/NuanceTrashCommand.php create mode 100644 src/applications/nuance/xaction/NuanceItemStatusTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 45a9aa2b96..a01125ec38 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1601,6 +1601,7 @@ phutil_register_library_map(array( 'MultimeterLabel' => 'applications/multimeter/storage/MultimeterLabel.php', 'MultimeterSampleController' => 'applications/multimeter/controller/MultimeterSampleController.php', 'MultimeterViewer' => 'applications/multimeter/storage/MultimeterViewer.php', + 'NuanceCommandImplementation' => 'applications/nuance/command/NuanceCommandImplementation.php', 'NuanceConduitAPIMethod' => 'applications/nuance/conduit/NuanceConduitAPIMethod.php', 'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php', 'NuanceContentSource' => 'applications/nuance/contentsource/NuanceContentSource.php', @@ -1636,6 +1637,7 @@ phutil_register_library_map(array( 'NuanceItemRequestorTransaction' => 'applications/nuance/xaction/NuanceItemRequestorTransaction.php', 'NuanceItemSearchEngine' => 'applications/nuance/query/NuanceItemSearchEngine.php', 'NuanceItemSourceTransaction' => 'applications/nuance/xaction/NuanceItemSourceTransaction.php', + 'NuanceItemStatusTransaction' => 'applications/nuance/xaction/NuanceItemStatusTransaction.php', 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', @@ -1690,6 +1692,7 @@ phutil_register_library_map(array( 'NuanceSourceTransactionType' => 'applications/nuance/xaction/NuanceSourceTransactionType.php', 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', + 'NuanceTrashCommand' => 'applications/nuance/command/NuanceTrashCommand.php', 'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php', 'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php', 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', @@ -6714,6 +6717,7 @@ phutil_register_library_map(array( 'MultimeterLabel' => 'MultimeterDimension', 'MultimeterSampleController' => 'MultimeterController', 'MultimeterViewer' => 'MultimeterDimension', + 'NuanceCommandImplementation' => 'Phobject', 'NuanceConduitAPIMethod' => 'ConduitAPIMethod', 'NuanceConsoleController' => 'NuanceController', 'NuanceContentSource' => 'PhabricatorContentSource', @@ -6759,6 +6763,7 @@ phutil_register_library_map(array( 'NuanceItemRequestorTransaction' => 'NuanceItemTransactionType', 'NuanceItemSearchEngine' => 'PhabricatorApplicationSearchEngine', 'NuanceItemSourceTransaction' => 'NuanceItemTransactionType', + 'NuanceItemStatusTransaction' => 'NuanceItemTransactionType', 'NuanceItemTransaction' => 'NuanceTransaction', 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -6822,6 +6827,7 @@ phutil_register_library_map(array( 'NuanceSourceTransactionType' => 'PhabricatorModularTransactionType', 'NuanceSourceViewController' => 'NuanceSourceController', 'NuanceTransaction' => 'PhabricatorModularTransaction', + 'NuanceTrashCommand' => 'NuanceCommandImplementation', 'NuanceWorker' => 'PhabricatorWorker', 'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', diff --git a/src/applications/nuance/command/NuanceCommandImplementation.php b/src/applications/nuance/command/NuanceCommandImplementation.php new file mode 100644 index 0000000000..46220266ff --- /dev/null +++ b/src/applications/nuance/command/NuanceCommandImplementation.php @@ -0,0 +1,107 @@ +actor = $actor; + return $this; + } + + final public function getActor() { + return $this->actor; + } + + abstract public function getCommandName(); + abstract public function canApplyToItem(NuanceItem $item); + + abstract protected function executeCommand( + NuanceItem $item, + NuanceItemCommand $command); + + final public function applyCommand( + NuanceItem $item, + NuanceItemCommand $command) { + + $command_key = $command->getCommand(); + $implementation_key = $this->getCommandKey(); + if ($command_key !== $implementation_key) { + throw new Exception( + pht( + 'This command implementation("%s") can not apply a command of a '. + 'different type ("%s").', + $implementation_key, + $command_key)); + } + + if (!$this->canApplyToItem($item)) { + throw new Exception( + pht( + 'This command implementation ("%s") can not be applied to an '. + 'item of type "%s".', + $implementation_key, + $item->getItemType())); + } + + $this->transactionQueue = array(); + + $command_type = NuanceItemCommandTransaction::TRANSACTIONTYPE; + $command_xaction = $this->newTransaction($command_type); + + $result = $this->executeCommand($item, $command); + + $xactions = $this->transactionQueue; + $this->transactionQueue = array(); + + $command_xaction->setNewValue( + array( + 'command' => $command->getCommand(), + 'parameters' => $command->getParameters(), + 'result' => $result, + )); + + // TODO: Maybe preserve the actor's original content source? + $source = PhabricatorContentSource::newForSource( + PhabricatorDaemonContentSource::SOURCECONST); + + $actor = $this->getActor(); + + id(new NuanceItemEditor()) + ->setActor($actor) + ->setActingAsPHID($command->getAuthorPHID()) + ->setContentSource($source) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true) + ->applyTransactions($item, $xactions); + } + + final public function getCommandKey() { + return $this->getPhobjectClassConstant('COMMANDKEY'); + } + + final public static function getAllCommands() { + return id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getCommandKey') + ->execute(); + } + + protected function newTransaction($type) { + $xaction = id(new NuanceItemTransaction()) + ->setTransactionType($type); + + $this->transactionQueue[] = $xaction; + + return $xaction; + } + + protected function newStatusTransaction($status) { + return $this->newTransaction(NuanceItemStatusTransaction::TRANSACTIONTYPE) + ->setNewValue($status); + } + +} diff --git a/src/applications/nuance/command/NuanceTrashCommand.php b/src/applications/nuance/command/NuanceTrashCommand.php new file mode 100644 index 0000000000..1f8a729277 --- /dev/null +++ b/src/applications/nuance/command/NuanceTrashCommand.php @@ -0,0 +1,23 @@ +getImplementation(); + return ($type instanceof NuanceFormItemType); + } + + protected function executeCommand( + NuanceItem $item, + NuanceItemCommand $command) { + $this->newStatusTransaction(NuanceItem::STATUS_CLOSED); + } + +} diff --git a/src/applications/nuance/item/NuanceGitHubEventItemType.php b/src/applications/nuance/item/NuanceGitHubEventItemType.php index b7b90690b7..b8bfb3ccab 100644 --- a/src/applications/nuance/item/NuanceGitHubEventItemType.php +++ b/src/applications/nuance/item/NuanceGitHubEventItemType.php @@ -329,6 +329,9 @@ final class NuanceGitHubEventItemType NuanceItem $item, NuanceItemCommand $command) { + // TODO: This code is no longer reachable, and has moved to + // CommandImplementation subclasses. + $action = $command->getCommand(); switch ($action) { case 'sync': diff --git a/src/applications/nuance/item/NuanceItemType.php b/src/applications/nuance/item/NuanceItemType.php index de64977cb3..3a65ad0195 100644 --- a/src/applications/nuance/item/NuanceItemType.php +++ b/src/applications/nuance/item/NuanceItemType.php @@ -106,46 +106,6 @@ abstract class NuanceItemType return $this->newWorkCommands($item); } - final public function applyCommand( - NuanceItem $item, - NuanceItemCommand $command) { - - $result = $this->handleCommand($item, $command); - - if ($result === null) { - return; - } - - $xaction = id(new NuanceItemTransaction()) - ->setTransactionType(NuanceItemCommandTransaction::TRANSACTIONTYPE) - ->setNewValue( - array( - 'command' => $command->getCommand(), - 'parameters' => $command->getParameters(), - 'result' => $result, - )); - - $viewer = $this->getViewer(); - - // TODO: Maybe preserve the actor's original content source? - $source = PhabricatorContentSource::newForSource( - PhabricatorDaemonContentSource::SOURCECONST); - - $editor = id(new NuanceItemEditor()) - ->setActor($viewer) - ->setActingAsPHID($command->getAuthorPHID()) - ->setContentSource($source) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true) - ->applyTransactions($item, array($xaction)); - } - - protected function handleCommand( - NuanceItem $item, - NuanceItemCommand $command) { - return null; - } - final protected function newContentSource( NuanceItem $item, $agent_phid) { diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php index b1deab3af2..09a106ca7a 100644 --- a/src/applications/nuance/storage/NuanceItem.php +++ b/src/applications/nuance/storage/NuanceItem.php @@ -9,7 +9,6 @@ final class NuanceItem const STATUS_IMPORTING = 'importing'; const STATUS_ROUTING = 'routing'; const STATUS_OPEN = 'open'; - const STATUS_ASSIGNED = 'assigned'; const STATUS_CLOSED = 'closed'; protected $status; diff --git a/src/applications/nuance/worker/NuanceItemUpdateWorker.php b/src/applications/nuance/worker/NuanceItemUpdateWorker.php index 5f33f885f9..30d5621872 100644 --- a/src/applications/nuance/worker/NuanceItemUpdateWorker.php +++ b/src/applications/nuance/worker/NuanceItemUpdateWorker.php @@ -68,13 +68,29 @@ final class NuanceItemUpdateWorker ->execute(); $commands = msort($commands, 'getID'); + $executors = NuanceCommandImplementation::getAllCommands(); foreach ($commands as $command) { $command ->setStatus(NuanceItemCommand::STATUS_EXECUTING) ->save(); try { - $impl->applyCommand($item, $command); + $command_key = $command->getCommand(); + + $executor = idx($executors, $command_key); + if (!$executor) { + throw new Exception( + pht( + 'Unable to execute command "%s": this command does not have '. + 'a recognized command implementation.', + $command_key)); + } + + $executor = clone $executor; + + $executor + ->setActor($viewer) + ->applyCommand($item, $command); $command ->setStatus(NuanceItemCommand::STATUS_DONE) diff --git a/src/applications/nuance/xaction/NuanceItemCommandTransaction.php b/src/applications/nuance/xaction/NuanceItemCommandTransaction.php index bf1cbdf8d6..6aa1d6473f 100644 --- a/src/applications/nuance/xaction/NuanceItemCommandTransaction.php +++ b/src/applications/nuance/xaction/NuanceItemCommandTransaction.php @@ -9,14 +9,14 @@ final class NuanceItemCommandTransaction return null; } - public function applyInternalEffects($object, $value) { - // TODO: Probably implement this. - } - public function getTitle() { + $spec = $this->getNewValue(); + $command_key = idx($spec, 'command', '???'); + return pht( - '%s applied a command to this item.', - $this->renderAuthor()); + '%s applied a "%s" command to this item.', + $this->renderAuthor(), + $command_key); } } diff --git a/src/applications/nuance/xaction/NuanceItemStatusTransaction.php b/src/applications/nuance/xaction/NuanceItemStatusTransaction.php new file mode 100644 index 0000000000..48c5a16e8c --- /dev/null +++ b/src/applications/nuance/xaction/NuanceItemStatusTransaction.php @@ -0,0 +1,25 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + return pht( + '%s changed the status of this item from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + +} From eb296796aaa579613437e21f911b45ef31be9e32 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Wed, 24 May 2017 12:07:04 -0700 Subject: [PATCH 39/61] Migrate Project sort and filter defaults to modular transactions Test Plan: Unit tests pass, manually changed the default sort and filter on a workboard and observed expected transactions in the DB. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D18013 --- src/__phutil_library_map__.php | 4 +++ .../PhabricatorProjectDefaultController.php | 4 +-- .../PhabricatorProjectTransactionEditor.php | 17 ------------ .../storage/PhabricatorProjectTransaction.php | 19 +++----------- .../PhabricatorProjectFilterTransaction.php | 26 +++++++++++++++++++ .../PhabricatorProjectSortTransaction.php | 26 +++++++++++++++++++ 6 files changed, 61 insertions(+), 35 deletions(-) create mode 100644 src/applications/project/xaction/PhabricatorProjectFilterTransaction.php create mode 100644 src/applications/project/xaction/PhabricatorProjectSortTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a01125ec38..582315661a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3636,6 +3636,7 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', + 'PhabricatorProjectFilterTransaction' => 'applications/project/xaction/PhabricatorProjectFilterTransaction.php', 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', 'PhabricatorProjectHeraldAdapter' => 'applications/project/herald/PhabricatorProjectHeraldAdapter.php', @@ -3694,6 +3695,7 @@ phutil_register_library_map(array( 'PhabricatorProjectSilencedEdgeType' => 'applications/project/edge/PhabricatorProjectSilencedEdgeType.php', 'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php', 'PhabricatorProjectSlugsTransaction' => 'applications/project/xaction/PhabricatorProjectSlugsTransaction.php', + 'PhabricatorProjectSortTransaction' => 'applications/project/xaction/PhabricatorProjectSortTransaction.php', 'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php', 'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php', 'PhabricatorProjectStatusTransaction' => 'applications/project/xaction/PhabricatorProjectStatusTransaction.php', @@ -9082,6 +9084,7 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', + 'PhabricatorProjectFilterTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorProjectHeraldAction' => 'HeraldAction', 'PhabricatorProjectHeraldAdapter' => 'HeraldAdapter', @@ -9139,6 +9142,7 @@ phutil_register_library_map(array( 'PhabricatorProjectSilencedEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectSlug' => 'PhabricatorProjectDAO', 'PhabricatorProjectSlugsTransaction' => 'PhabricatorProjectTransactionType', + 'PhabricatorProjectSortTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectStandardCustomField' => array( 'PhabricatorProjectCustomField', 'PhabricatorStandardCustomFieldInterface', diff --git a/src/applications/project/controller/PhabricatorProjectDefaultController.php b/src/applications/project/controller/PhabricatorProjectDefaultController.php index 0246f33f43..8f42ff9736 100644 --- a/src/applications/project/controller/PhabricatorProjectDefaultController.php +++ b/src/applications/project/controller/PhabricatorProjectDefaultController.php @@ -32,7 +32,7 @@ final class PhabricatorProjectDefaultController $button = pht('Save Default Filter'); $xaction_value = $request->getStr('filter'); - $xaction_type = PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER; + $xaction_type = PhabricatorProjectFilterTransaction::TRANSACTIONTYPE; break; case 'sort': $title = pht('Set Board Default Order'); @@ -43,7 +43,7 @@ final class PhabricatorProjectDefaultController $button = pht('Save Default Order'); $xaction_value = $request->getStr('order'); - $xaction_type = PhabricatorProjectTransaction::TYPE_DEFAULT_SORT; + $xaction_type = PhabricatorProjectSortTransaction::TRANSACTIONTYPE; break; default: return new Aphront404Response(); diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 69d16c3786..e73db3b026 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -30,8 +30,6 @@ final class PhabricatorProjectTransactionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; - $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_SORT; - $types[] = PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER; $types[] = PhabricatorProjectTransaction::TYPE_BACKGROUND; return $types; @@ -42,10 +40,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: - return $object->getDefaultWorkboardSort(); - case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: - return $object->getDefaultWorkboardFilter(); case PhabricatorProjectTransaction::TYPE_BACKGROUND: return $object->getWorkboardBackgroundColor(); } @@ -58,9 +52,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: - case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: - return $xaction->getNewValue(); case PhabricatorProjectTransaction::TYPE_BACKGROUND: $value = $xaction->getNewValue(); if (!strlen($value)) { @@ -77,12 +68,6 @@ final class PhabricatorProjectTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: - $object->setDefaultWorkboardSort($xaction->getNewValue()); - return; - case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: - $object->setDefaultWorkboardFilter($xaction->getNewValue()); - return; case PhabricatorProjectTransaction::TYPE_BACKGROUND: $object->setWorkboardBackgroundColor($xaction->getNewValue()); return; @@ -99,8 +84,6 @@ final class PhabricatorProjectTransactionEditor $new = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_DEFAULT_SORT: - case PhabricatorProjectTransaction::TYPE_DEFAULT_FILTER: case PhabricatorProjectTransaction::TYPE_BACKGROUND: return; } diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index cfb99d7469..8e026df045 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -3,8 +3,6 @@ final class PhabricatorProjectTransaction extends PhabricatorModularTransaction { - const TYPE_DEFAULT_SORT = 'project:sort'; - const TYPE_DEFAULT_FILTER = 'project:filter'; const TYPE_BACKGROUND = 'project:background'; // NOTE: This is deprecated, members are just a normal edge now. @@ -60,8 +58,6 @@ final class PhabricatorProjectTransaction public function shouldHideForFeed() { switch ($this->getTransactionType()) { - case self::TYPE_DEFAULT_SORT: - case self::TYPE_DEFAULT_FILTER: case self::TYPE_BACKGROUND: return true; } @@ -69,11 +65,12 @@ final class PhabricatorProjectTransaction return parent::shouldHideForFeed(); } + public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE: - case self::TYPE_DEFAULT_SORT: - case self::TYPE_DEFAULT_FILTER: + case PhabricatorProjectSortTransaction::TRANSACTIONTYPE: + case PhabricatorProjectFilterTransaction::TRANSACTIONTYPE: case self::TYPE_BACKGROUND: return true; } @@ -140,16 +137,6 @@ final class PhabricatorProjectTransaction } break; - case self::TYPE_DEFAULT_SORT: - return pht( - '%s changed the default sort order for the project workboard.', - $author_handle); - - case self::TYPE_DEFAULT_FILTER: - return pht( - '%s changed the default filter for the project workboard.', - $author_handle); - case self::TYPE_BACKGROUND: return pht( '%s changed the background color of the project workboard.', diff --git a/src/applications/project/xaction/PhabricatorProjectFilterTransaction.php b/src/applications/project/xaction/PhabricatorProjectFilterTransaction.php new file mode 100644 index 0000000000..d3d94fbb74 --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectFilterTransaction.php @@ -0,0 +1,26 @@ +getDefaultWorkboardFilter(); + } + + public function applyInternalEffects($object, $value) { + $object->setDefaultWorkboardFilter($value); + } + + public function getTitle() { + return pht( + '%s changed the default filter for the project workboard.', + $this->renderAuthor()); + } + + public function shouldHide() { + return true; + } + +} diff --git a/src/applications/project/xaction/PhabricatorProjectSortTransaction.php b/src/applications/project/xaction/PhabricatorProjectSortTransaction.php new file mode 100644 index 0000000000..f070f6dd19 --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectSortTransaction.php @@ -0,0 +1,26 @@ +getDefaultWorkboardSort(); + } + + public function applyInternalEffects($object, $value) { + $object->setDefaultWorkboardSort($value); + } + + public function getTitle() { + return pht( + '%s changed the default sort order for the project workboard.', + $this->renderAuthor()); + } + + public function shouldHide() { + return true; + } + +} From 88466addee2624d80771fec4fe6204e7b50f61b7 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Wed, 24 May 2017 12:46:49 -0700 Subject: [PATCH 40/61] Migrate Project workboard background color to modular transactions Summary: Removes now-unused method as well. Fixes T12673. Test Plan: UI fiddling. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Maniphest Tasks: T12673 Differential Revision: https://secure.phabricator.com/D18014 --- src/__phutil_library_map__.php | 2 + ...icatorProjectBoardBackgroundController.php | 3 +- .../PhabricatorProjectTransactionEditor.php | 58 ------------------- .../storage/PhabricatorProjectTransaction.php | 19 +----- ...rProjectWorkboardBackgroundTransaction.php | 26 +++++++++ 5 files changed, 31 insertions(+), 77 deletions(-) create mode 100644 src/applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 582315661a..7510f2e42c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3716,6 +3716,7 @@ phutil_register_library_map(array( 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', 'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php', 'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php', + 'PhabricatorProjectWorkboardBackgroundTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php', 'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php', 'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php', 'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php', @@ -9166,6 +9167,7 @@ phutil_register_library_map(array( 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject', + 'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType', 'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', diff --git a/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php b/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php index 99260d1770..be4049bb73 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php @@ -37,7 +37,8 @@ final class PhabricatorProjectBoardBackgroundController $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorProjectTransaction::TYPE_BACKGROUND) + ->setTransactionType( + PhabricatorProjectWorkboardBackgroundTransaction::TRANSACTIONTYPE) ->setNewValue($background_key); id(new PhabricatorProjectTransactionEditor()) diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index e73db3b026..393c4569f6 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -30,67 +30,9 @@ final class PhabricatorProjectTransactionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; - $types[] = PhabricatorProjectTransaction::TYPE_BACKGROUND; - return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_BACKGROUND: - return $object->getWorkboardBackgroundColor(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_BACKGROUND: - $value = $xaction->getNewValue(); - if (!strlen($value)) { - return null; - } - return $value; - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_BACKGROUND: - $object->setWorkboardBackgroundColor($xaction->getNewValue()); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - switch ($xaction->getTransactionType()) { - case PhabricatorProjectTransaction::TYPE_BACKGROUND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index 8e026df045..158c2480c0 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -3,8 +3,6 @@ final class PhabricatorProjectTransaction extends PhabricatorModularTransaction { - const TYPE_BACKGROUND = 'project:background'; - // NOTE: This is deprecated, members are just a normal edge now. const TYPE_MEMBERS = 'project:members'; @@ -56,22 +54,12 @@ final class PhabricatorProjectTransaction return parent::shouldHide(); } - public function shouldHideForFeed() { - switch ($this->getTransactionType()) { - case self::TYPE_BACKGROUND: - return true; - } - - return parent::shouldHideForFeed(); - } - - public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case PhabricatorProjectWorkboardTransaction::TRANSACTIONTYPE: case PhabricatorProjectSortTransaction::TRANSACTIONTYPE: case PhabricatorProjectFilterTransaction::TRANSACTIONTYPE: - case self::TYPE_BACKGROUND: + case PhabricatorProjectWorkboardBackgroundTransaction::TRANSACTIONTYPE: return true; } @@ -136,11 +124,6 @@ final class PhabricatorProjectTransaction } } break; - - case self::TYPE_BACKGROUND: - return pht( - '%s changed the background color of the project workboard.', - $author_handle); } return parent::getTitle(); diff --git a/src/applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php b/src/applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php new file mode 100644 index 0000000000..620959b0a2 --- /dev/null +++ b/src/applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php @@ -0,0 +1,26 @@ +getWorkboardBackgroundColor(); + } + + public function applyInternalEffects($object, $value) { + $object->setWorkboardBackgroundColor($value); + } + + public function getTitle() { + return pht( + '%s changed the background color of the project workboard.', + $this->renderAuthor()); + } + + public function shouldHide() { + return true; + } + +} From 709c304d76d16e3d5585dd31f291a41b46883494 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 11:47:40 -0700 Subject: [PATCH 41/61] Group query results under the "ANCESTOR" operator unconditionally Summary: Fixes T12753. See that task for reproduction instructions. We add a `GROUP BY` clause to queries with an "ANCESTOR" edge constraint only if the constaint has more than one PHID, but this is incorrect: the same row can be found twice by an ANCESTOR query if task T is tagged with both "B" and "C", children of "A", and the user queries for "tasks in A". Instead, always add GROUP BY for ANCESTOR queries. Test Plan: - Followed test plan in T12753. - Saw proper paging controls after change. - Saw `GROUP BY` in DarkConsole. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12753 Differential Revision: https://secure.phabricator.com/D18012 --- .../policy/PhabricatorCursorPagedPolicyAwareQuery.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 2bd374d5db..3ef2a72e6f 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1811,11 +1811,16 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery case PhabricatorQueryConstraint::OPERATOR_NOT: case PhabricatorQueryConstraint::OPERATOR_AND: case PhabricatorQueryConstraint::OPERATOR_OR: - case PhabricatorQueryConstraint::OPERATOR_ANCESTOR: if (count($list) > 1) { return true; } break; + case PhabricatorQueryConstraint::OPERATOR_ANCESTOR: + // NOTE: We must always group query results rows when using an + // "ANCESTOR" operator because a single task may be related to + // two different descendants of a particular ancestor. For + // discussion, see T12753. + return true; case PhabricatorQueryConstraint::OPERATOR_NULL: return true; } From 7cfa8a831535c4f51b5aa8b72d60c0b74f8614f4 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 25 May 2017 10:55:39 -0700 Subject: [PATCH 42/61] Add ImageHref attribute for PHUIObjectItemListView Summary: In some cases we may want a different URI for the image on an item than the header/title of the item (like user / title). This prioritizes ImageHref over Href. Test Plan: uiexamples Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18016 --- .../uiexample/examples/PHUIObjectItemListExample.php | 2 ++ src/view/phui/PHUIObjectItemView.php | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/applications/uiexample/examples/PHUIObjectItemListExample.php b/src/applications/uiexample/examples/PHUIObjectItemListExample.php index 691c84554c..6bc521dca2 100644 --- a/src/applications/uiexample/examples/PHUIObjectItemListExample.php +++ b/src/applications/uiexample/examples/PHUIObjectItemListExample.php @@ -330,6 +330,8 @@ final class PHUIObjectItemListExample extends PhabricatorUIExample { $list->addItem( id(new PHUIObjectItemView()) ->setImageURI($default_project->getViewURI()) + ->setImageHref('#') + ->setHref('$$$') ->setHeader(pht('Default Project Profile Image')) ->setGrippable(true) ->addAttribute(pht('This is the default project profile image.'))); diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php index 59547c4442..1182d9be92 100644 --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -19,6 +19,7 @@ final class PHUIObjectItemView extends AphrontTagView { private $headIcons = array(); private $disabled; private $imageURI; + private $imageHref; private $imageIcon; private $titleText; private $badge; @@ -127,6 +128,11 @@ final class PHUIObjectItemView extends AphrontTagView { return $this; } + public function setImageHref($image_href) { + $this->imageHref = $image_href; + return $this; + } + public function getImageURI() { return $this->imageURI; } @@ -575,11 +581,12 @@ final class PHUIObjectItemView extends AphrontTagView { $this->getImageIcon()); } - if ($image && $this->href) { + if ($image && (strlen($this->href) || strlen($this->imageHref))) { + $image_href = ($this->imageHref) ? $this->imageHref : $this->href; $image = phutil_tag( 'a', array( - 'href' => $this->href, + 'href' => $image_href, ), $image); } From f29b54944f9cfbc20d9e3c0e05ef9141599d34c3 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Thu, 25 May 2017 13:41:21 -0700 Subject: [PATCH 43/61] Make closed objects in global typeahead look closed Summary: Fixes T6906. I found the code in `behavior-search-typeahead.js` that was throwing away the closedness-detction work done in `Prejab.js::transformDatasourceResults`. Modified it to re-add the correct class name to the `phabricator-main-search-typeahead-result` elements. Then I found some CSS in `typeahead-browse.css` and completely flailed around until realizing that particular CSS only gets loaded when hitting the typeahead endpoint directly. Copied the relevant bit of CSS over to `main-menu-view.css` (but maybe it should be removed from `typeahead-browse.css`?). This is my first JS/CSS change, so please don't assume I did anything right. Test Plan: {F4975800} Reviewers: #blessed_reviewers, chad Reviewed By: #blessed_reviewers, chad Subscribers: epriestley Maniphest Tasks: T6906 Differential Revision: https://secure.phabricator.com/D18017 --- resources/celerity/map.php | 44 +++++++++---------- webroot/rsrc/css/aphront/typeahead-browse.css | 16 ------- .../css/application/base/main-menu-view.css | 16 +++++++ .../rsrc/js/core/behavior-search-typeahead.js | 4 ++ 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a71d9f524e..bcfae6b7e6 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,8 +9,8 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '71865bdf', - 'core.pkg.js' => '599698a7', + 'core.pkg.css' => 'd556e3e2', + 'core.pkg.js' => '21d34805', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', 'differential.pkg.js' => '1d120743', @@ -35,11 +35,11 @@ return array( 'rsrc/css/aphront/table-view.css' => '34cf86b4', 'rsrc/css/aphront/tokenizer.css' => '9a8cb501', 'rsrc/css/aphront/tooltip.css' => '173b9431', - 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', + 'rsrc/css/aphront/typeahead-browse.css' => '4f82e510', 'rsrc/css/aphront/typeahead.css' => '8a84cc7d', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/auth/auth.css' => '0877ed6e', - 'rsrc/css/application/base/main-menu-view.css' => '5294060f', + 'rsrc/css/application/base/main-menu-view.css' => 'de9fe8c4', 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phui-theme.css' => '9f261c6b', 'rsrc/css/application/base/standard-page-view.css' => 'eb5b80c5', @@ -514,7 +514,7 @@ return array( 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', - 'rsrc/js/core/behavior-search-typeahead.js' => 'eded9ee8', + 'rsrc/js/core/behavior-search-typeahead.js' => 'd0a99ab4', 'rsrc/js/core/behavior-select-content.js' => 'bf5374ef', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 'rsrc/js/core/behavior-setup-check-https.js' => '491416b3', @@ -668,7 +668,7 @@ return array( 'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-remarkup-assist' => 'acd29eee', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', - 'javelin-behavior-phabricator-search-typeahead' => 'eded9ee8', + 'javelin-behavior-phabricator-search-typeahead' => 'd0a99ab4', 'javelin-behavior-phabricator-show-older-transactions' => 'ae95d984', 'javelin-behavior-phabricator-tooltips' => 'c420b0b9', 'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6', @@ -792,7 +792,7 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => 'c19dd9b9', - 'phabricator-main-menu-view' => '5294060f', + 'phabricator-main-menu-view' => 'de9fe8c4', 'phabricator-nav-view-css' => 'faf6a6fc', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', @@ -914,7 +914,7 @@ return array( 'syntax-default-css' => '9923583c', 'syntax-highlighting-css' => 'cae95e89', 'tokens-css' => '3d0f239e', - 'typeahead-browse-css' => '8904346a', + 'typeahead-browse-css' => '4f82e510', 'unhandled-exception-css' => '4c96257a', ), 'requires' => array( @@ -1307,9 +1307,6 @@ return array( 'javelin-vector', 'javelin-typeahead-static-source', ), - '5294060f' => array( - 'phui-theme-css', - ), '54b612ba' => array( 'javelin-color', 'javelin-install', @@ -2016,6 +2013,17 @@ return array( 'javelin-vector', 'phabricator-diff-inline', ), + 'd0a99ab4' => array( + 'javelin-behavior', + 'javelin-typeahead-ondemand-source', + 'javelin-typeahead', + 'javelin-dom', + 'javelin-uri', + 'javelin-util', + 'javelin-stratcom', + 'phabricator-prefab', + 'phuix-icon-view', + ), 'd0c516d5' => array( 'javelin-behavior', 'javelin-dom', @@ -2088,6 +2096,9 @@ return array( 'javelin-typeahead-ondemand-source', 'javelin-dom', ), + 'de9fe8c4' => array( + 'phui-theme-css', + ), 'e0ec7f2f' => array( 'javelin-behavior', 'javelin-dom', @@ -2157,17 +2168,6 @@ return array( 'javelin-dom', 'phabricator-draggable-list', ), - 'eded9ee8' => array( - 'javelin-behavior', - 'javelin-typeahead-ondemand-source', - 'javelin-typeahead', - 'javelin-dom', - 'javelin-uri', - 'javelin-util', - 'javelin-stratcom', - 'phabricator-prefab', - 'phuix-icon-view', - ), 'edf8a145' => array( 'javelin-behavior', 'javelin-uri', diff --git a/webroot/rsrc/css/aphront/typeahead-browse.css b/webroot/rsrc/css/aphront/typeahead-browse.css index 625354bb71..7439d299e7 100644 --- a/webroot/rsrc/css/aphront/typeahead-browse.css +++ b/webroot/rsrc/css/aphront/typeahead-browse.css @@ -64,19 +64,3 @@ input.typeahead-browse-input { margin-top: 1px; margin-left: 6px; } - -.typeahead-browse-item .phabricator-main-search-typeahead-result { - margin: 2px 0; - padding: 0 8px; -} - -.typeahead-browse-item .phabricator-main-search-typeahead-result.has-image { - padding-left: 48px; -} - -.typeahead-browse-item - .phabricator-main-search-typeahead-result.result-closed - .result-name { - text-decoration: line-through; - color: {$lightgreytext}; -} diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 28148ae71a..eb5cfad8c7 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -309,6 +309,22 @@ a.phabricator-core-user-menu .caret:before { color: {$darkgreytext}; } +.phabricator-main-search-typeahead-result.result-closed { + opacity: .8; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); +} + +.phabricator-main-search-typeahead-result.result-closed + .result-name { + text-decoration: line-through; + color: {$lightgreytext}; +} + +.phabricator-main-search-typeahead-result.has-image { + padding-left: 48px; +} + .phabricator-main-search-typeahead-result .result-type { color: {$lightgreytext}; font-size: {$smallestfontsize}; diff --git a/webroot/rsrc/js/core/behavior-search-typeahead.js b/webroot/rsrc/js/core/behavior-search-typeahead.js index fc752a6079..ddcc2e6aaa 100644 --- a/webroot/rsrc/js/core/behavior-search-typeahead.js +++ b/webroot/rsrc/js/core/behavior-search-typeahead.js @@ -45,6 +45,10 @@ JX.behavior('phabricator-search-typeahead', function(config) { JX.$N('span', {className: 'result-type'}, object.type) ]); + if (object.closed) { + JX.DOM.alterClass(render, 'result-closed', true); + } + object.display = render; return object; From 84742a94db1301a80534fa0d90abb3464cb57aae Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 25 May 2017 13:03:41 -0700 Subject: [PATCH 44/61] Restore missing feed rendering for Maniphest points transactions Summary: See downstream . These got dropped in refactoring, or maybe never existed. Test Plan: {F4977212} Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D18018 --- .../ManiphestTaskPointsTransaction.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php b/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php index 6d8548fdb4..b1c20af9e6 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php +++ b/src/applications/maniphest/xaction/ManiphestTaskPointsTransaction.php @@ -50,6 +50,32 @@ final class ManiphestTaskPointsTransaction } } + public function getTitleForFeed() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s set the point value for %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } else if ($new === null) { + return pht( + '%s removed the point value for %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s changed the point value for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { $errors = array(); From 19572f53fdfedd13e5c9267a52868d0fe9eb0ae0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 25 May 2017 13:19:30 -0700 Subject: [PATCH 45/61] Don't consider accepting on behalf of valid-but-accepted reviewers to be a validation error Summary: Fixes T12757. Here's a simple repro for this: - Add a package you own as a reviewer to a revision you're reviewing. - Open two windows, select "Accept", don't submit the form. - Submit the form in window A. - Submit the fomr in window B. Previously, window B would show an error, because we considered accepting on behalf of the package invalid, as the package had already accepted. Instead, let repeat-accepts through without complaint. Some product stuff: - We could roadblock users with a more narrow validation error message here instead, like "Package X has already been accepted.", but I think this would be more annoying than helpful. - If your accept has no effect (i.e., everything you're accepting for has already accepted) we currently just let it through. I think this is fine -- and a bit tricky to tailor -- but the ideal/consistent beavior is to do a "no effect" warning like "All the reviewers you're accepting for have already accepted.". This is sufficiently finnicky/rare (and probably not terribly useful/desiable in this specific case)that I'm just punting. Test Plan: Did the flow above, got an "Accept" instead of a validation error. Reviewers: chad, lvital Reviewed By: chad, lvital Subscribers: lvital Maniphest Tasks: T12757 Differential Revision: https://secure.phabricator.com/D18019 --- .../DifferentialRevisionAcceptTransaction.php | 21 +++++++++++++------ .../DifferentialRevisionReviewTransaction.php | 10 +++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php index 7d1f1a92ef..9b6aad3ad1 100644 --- a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php @@ -50,7 +50,8 @@ final class DifferentialRevisionAcceptTransaction protected function getActionOptions( PhabricatorUser $viewer, - DifferentialRevision $revision) { + DifferentialRevision $revision, + $include_accepted = false) { $reviewers = $revision->getReviewers(); @@ -98,10 +99,13 @@ final class DifferentialRevisionAcceptTransaction } } - if ($reviewer->isAccepted($diff_phid)) { - // If a reviewer is already in a full "accepted" state, don't - // include that reviewer as an option. - continue; + if (!$include_accepted) { + if ($reviewer->isAccepted($diff_phid)) { + // If a reviewer is already in a full "accepted" state, don't + // include that reviewer as an option unless we're listing all + // reviwers, including reviewers who have already accepted. + continue; + } } $reviewer_phids[$reviewer_phid] = $reviewer_phid; @@ -185,7 +189,12 @@ final class DifferentialRevisionAcceptTransaction 'least one reviewer.')); } - list($options) = $this->getActionOptions($actor, $object); + // NOTE: We're including reviewers who have already been accepted in this + // check. Legitimate users may race one another to accept on behalf of + // packages. If we get a form submission which includes a reviewer which + // someone has already accepted, that's fine. See T12757. + + list($options) = $this->getActionOptions($actor, $object, true); foreach ($value as $phid) { if (!isset($options[$phid])) { throw new Exception( diff --git a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php index d44de8706c..c30514b9ab 100644 --- a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php @@ -17,6 +17,16 @@ abstract class DifferentialRevisionReviewTransaction $viewer = $this->getActor(); list($options, $default) = $this->getActionOptions($viewer, $object); + // Remove reviewers which aren't actionable. In the case of "Accept", we + // may allow the transaction to proceed with some reviewers who have + // already accepted, to avoid race conditions where two reviewers fill + // out the form at the same time and accept on behalf of the same package. + // It's okay for these reviewers to survive validation, but they should + // not survive beyond this point. + $value = array_fuse($value); + $value = array_intersect($value, array_keys($options)); + $value = array_values($value); + sort($default); sort($value); From 6b3d04683d8796053cd9ead3cb30e71548c155ff Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 25 May 2017 14:43:58 -0700 Subject: [PATCH 46/61] Clean up SIMPLE button styles Summary: Some of these are unused, defaults to a lighter color naturally. Test Plan: uiexamples, grep, phriction Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18020 --- resources/celerity/map.php | 10 +++++----- .../uiexample/examples/PHUIButtonExample.php | 3 --- src/view/phui/PHUIButtonView.php | 4 ---- webroot/rsrc/css/phui/phui-button.css | 10 +++++----- webroot/rsrc/css/phui/phui-document-pro.css | 4 +++- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index bcfae6b7e6..1497f7ce7f 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => 'd556e3e2', + 'core.pkg.css' => '2c6a5ba4', 'core.pkg.js' => '21d34805', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -140,14 +140,14 @@ return array( 'rsrc/css/phui/phui-basic-nav-view.css' => 'a0705f53', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '269cbc99', - 'rsrc/css/phui/phui-button.css' => '8d23596a', + 'rsrc/css/phui/phui-button.css' => 'ccd8c6c5', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => '57af2e14', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', 'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb', 'rsrc/css/phui/phui-curtain-view.css' => '55dd0e59', - 'rsrc/css/phui/phui-document-pro.css' => '62c4dcbf', + 'rsrc/css/phui/phui-document-pro.css' => '58199f99', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', @@ -838,7 +838,7 @@ return array( 'phui-basic-nav-view-css' => 'a0705f53', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '269cbc99', - 'phui-button-css' => '8d23596a', + 'phui-button-css' => 'ccd8c6c5', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', 'phui-calendar-list-css' => '576be600', @@ -851,7 +851,7 @@ return array( 'phui-curtain-view-css' => '55dd0e59', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', - 'phui-document-view-pro-css' => '62c4dcbf', + 'phui-document-view-pro-css' => '58199f99', 'phui-feed-story-css' => '44a9c8e9', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '1320ed01', diff --git a/src/applications/uiexample/examples/PHUIButtonExample.php b/src/applications/uiexample/examples/PHUIButtonExample.php index ae699eb7a3..900125cbc2 100644 --- a/src/applications/uiexample/examples/PHUIButtonExample.php +++ b/src/applications/uiexample/examples/PHUIButtonExample.php @@ -131,9 +131,6 @@ final class PHUIButtonExample extends PhabricatorUIExample { ); $colors = array( PHUIButtonView::SIMPLE, - PHUIButtonView::SIMPLE_YELLOW, - PHUIButtonView::SIMPLE_GREY, - PHUIButtonView::SIMPLE_BLUE, ); $column = array(); foreach ($colors as $color) { diff --git a/src/view/phui/PHUIButtonView.php b/src/view/phui/PHUIButtonView.php index ee6975357c..ac3f8aabe0 100644 --- a/src/view/phui/PHUIButtonView.php +++ b/src/view/phui/PHUIButtonView.php @@ -5,11 +5,7 @@ final class PHUIButtonView extends AphrontTagView { const GREEN = 'green'; const GREY = 'grey'; const DISABLED = 'disabled'; - const SIMPLE = 'simple'; - const SIMPLE_YELLOW = 'simple simple-yellow'; - const SIMPLE_GREY = 'simple simple-grey'; - const SIMPLE_BLUE = 'simple simple-blue'; const SMALL = 'small'; const BIG = 'big'; diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css index 09f2233a6c..e9d446a0ac 100644 --- a/webroot/rsrc/css/phui/phui-button.css +++ b/webroot/rsrc/css/phui/phui-button.css @@ -91,8 +91,8 @@ input[type="submit"].simple, a.simple, a.simple:visited { background: #fff; - color: {$blue}; - border: 1px solid {$blue}; + color: {$bluetext}; + border: 1px solid {$lightblueborder}; } a.simple.current { @@ -103,7 +103,7 @@ button.simple .phui-icon-view, input[type="submit"].simple .phui-icon-view, a.simple .phui-icon-view, a.simple:visited .phui-icon-view { - color: {$blue}; + color: {$lightbluetext}; } a.disabled, @@ -145,10 +145,10 @@ button.green:hover { a.button.simple:hover, button.simple:hover { - background-color: {$blue}; + background-color: {$lightblue}; background-image: linear-gradient(to bottom, {$blue}, {$blue}); color: #fff; - transition: 0.1s; + transition: 0s; } a.button.simple:hover .phui-icon-view, diff --git a/webroot/rsrc/css/phui/phui-document-pro.css b/webroot/rsrc/css/phui/phui-document-pro.css index 0aef43ed90..8ece71db64 100644 --- a/webroot/rsrc/css/phui/phui-document-pro.css +++ b/webroot/rsrc/css/phui/phui-document-pro.css @@ -75,7 +75,8 @@ a.button.phui-document-toc { display: inline-block; height: 16px; width: 20px; - padding: 3px 8px 4px 8px; + padding-left: 8px; + padding-right: 8px; } .phui-document-view-pro .phui-document-toc-list { @@ -105,6 +106,7 @@ a.button.phui-document-toc { .phui-document-toc-open .phui-document-toc { background-color: {$blue}; + border-color: {$blue}; } .phui-document-toc-open .phui-document-toc .phui-icon-view { From 9bbea869b3dd904253c44b678e3c1625a72db31d Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 25 May 2017 15:24:41 -0700 Subject: [PATCH 47/61] Move setLaunchButton to setSideColumn for ObjectItem Summary: Makes this a bit more flexible and allow UI to take over `col-2` completely. Also cleaned up application search a little with tags Test Plan: Review various pages, grep for callsites. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18021 --- resources/celerity/map.php | 6 ++-- .../guides/view/PhabricatorGuideListView.php | 4 +-- .../meta/query/PhabricatorAppSearchEngine.php | 33 ++++++++++++++----- .../phame/query/PhameBlogSearchEngine.php | 5 +-- src/view/phui/PHUIObjectItemView.php | 14 ++++---- .../phui/object-item/phui-oi-list-view.css | 4 +-- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 1497f7ce7f..3011b17643 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '2c6a5ba4', + 'core.pkg.css' => 'b666574e', 'core.pkg.js' => '21d34805', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -132,7 +132,7 @@ 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' => '78fdc98e', + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'ed19241b', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', 'rsrc/css/phui/phui-action-list.css' => 'c01858f4', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', @@ -875,7 +875,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' => '78fdc98e', + 'phui-oi-list-view-css' => 'ed19241b', 'phui-oi-simple-ui-css' => 'a8beebea', 'phui-pager-css' => '77d8a794', 'phui-pinboard-view-css' => '2495140e', diff --git a/src/applications/guides/view/PhabricatorGuideListView.php b/src/applications/guides/view/PhabricatorGuideListView.php index 384caf15ee..04ab7c3058 100644 --- a/src/applications/guides/view/PhabricatorGuideListView.php +++ b/src/applications/guides/view/PhabricatorGuideListView.php @@ -30,8 +30,8 @@ final class PhabricatorGuideListView extends AphrontView { ->setText(pht('Skip')) ->setTag('a') ->setHref($skip_href) - ->setColor(PHUIButtonView::GREY); - $list_item->setLaunchButton($skip); + ->setColor(PHUIButtonView::SIMPLE); + $list_item->setSideColumn($skip); } $list->addItem($list_item); } diff --git a/src/applications/meta/query/PhabricatorAppSearchEngine.php b/src/applications/meta/query/PhabricatorAppSearchEngine.php index b609a8b137..ee938abbbb 100644 --- a/src/applications/meta/query/PhabricatorAppSearchEngine.php +++ b/src/applications/meta/query/PhabricatorAppSearchEngine.php @@ -218,20 +218,39 @@ final class PhabricatorAppSearchEngine $configure = id(new PHUIButtonView()) ->setTag('a') + ->setIcon('fa-gears') ->setHref('/applications/view/'.get_class($application).'/') ->setText(pht('Configure')) ->setColor(PHUIButtonView::GREY); $name = $application->getName(); - if ($application->isPrototype()) { - $name = $name.' '.pht('(Prototype)'); - } $item = id(new PHUIObjectItemView()) ->setHeader($name) ->setImageIcon($icon) - ->setSubhead($description) - ->setLaunchButton($configure); + ->setSideColumn($configure); + + if (!$application->isFirstParty()) { + $tag = id(new PHUITagView()) + ->setName(pht('Extension')) + ->setIcon('fa-puzzle-piece') + ->setColor(PHUITagView::COLOR_BLUE) + ->setType(PHUITagView::TYPE_SHADE) + ->setSlimShady(true); + $item->addAttribute($tag); + } + + if ($application->isPrototype()) { + $prototype_tag = id(new PHUITagView()) + ->setName(pht('Prototype')) + ->setIcon('fa-exclamation-circle') + ->setColor(PHUITagView::COLOR_ORANGE) + ->setType(PHUITagView::TYPE_SHADE) + ->setSlimShady(true); + $item->addAttribute($prototype_tag); + } + + $item->addAttribute($description); if ($application->getBaseURI() && $application->isInstalled()) { $item->setHref($application->getBaseURI()); @@ -242,10 +261,6 @@ final class PhabricatorAppSearchEngine $item->setDisabled(true); } - if (!$application->isFirstParty()) { - $item->addAttribute(pht('Extension')); - } - $list->addItem($item); } diff --git a/src/applications/phame/query/PhameBlogSearchEngine.php b/src/applications/phame/query/PhameBlogSearchEngine.php index d006745780..3d23a9763d 100644 --- a/src/applications/phame/query/PhameBlogSearchEngine.php +++ b/src/applications/phame/query/PhameBlogSearchEngine.php @@ -97,8 +97,9 @@ final class PhameBlogSearchEngine $button = id(new PHUIButtonView()) ->setTag('a') ->setText('New Post') - ->setHref($this->getApplicationURI('/post/edit/?blog='.$id)); - $item->setLaunchButton($button); + ->setHref($this->getApplicationURI('/post/edit/?blog='.$id)) + ->setColor(PHUIButtonView::SIMPLE); + $item->setSideColumn($button); } $list->addItem($item); diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php index 1182d9be92..070d436cf6 100644 --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -25,7 +25,7 @@ final class PHUIObjectItemView extends AphrontTagView { private $badge; private $countdownNum; private $countdownNoun; - private $launchButton; + private $sideColumn; private $coverImage; private $description; @@ -229,9 +229,8 @@ final class PHUIObjectItemView extends AphrontTagView { return $this; } - public function setLaunchButton(PHUIButtonView $button) { - $button->setSize(PHUIButtonView::SMALL); - $this->launchButton = $button; + public function setSideColumn($column) { + $this->sideColumn = $column; return $this; } @@ -652,14 +651,15 @@ final class PHUIObjectItemView extends AphrontTagView { )); } - if ($this->launchButton) { + /* Fixed width, right column container. */ + if ($this->sideColumn) { $column2 = phutil_tag( 'div', array( - 'class' => 'phui-oi-col2 phui-oi-launch-button', + 'class' => 'phui-oi-col2 phui-oi-side-column', ), array( - $this->launchButton, + $this->sideColumn, )); } diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css index cbc2d43238..788b0e73ec 100644 --- a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css @@ -650,13 +650,13 @@ ul.phui-oi-list-view .phui-oi-selected /* - Launcher Button -------------------------------------------------------- */ -.phui-oi-col2.phui-oi-launch-button { +.phui-oi-col2.phui-oi-side-column { text-align: right; vertical-align: middle; padding-right: 4px; } -.device-phone .phui-oi-col2.phui-oi-launch-button { +.device-phone .phui-oi-col2.phui-oi-side-column { padding: 0 8px 8px; text-align: left; } From 66de16fbc48fb782002e3cc777e3a7c8dd5e006a Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Thu, 25 May 2017 17:27:20 -0700 Subject: [PATCH 48/61] Diffusion import documentation update Summary: Fixes T12761. Test Plan: doitlive Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Maniphest Tasks: T12761 Differential Revision: https://secure.phabricator.com/D18023 --- src/docs/user/userguide/diffusion_existing.diviner | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs/user/userguide/diffusion_existing.diviner b/src/docs/user/userguide/diffusion_existing.diviner index b5b1fbdf76..bf09d9ef1f 100644 --- a/src/docs/user/userguide/diffusion_existing.diviner +++ b/src/docs/user/userguide/diffusion_existing.diviner @@ -44,8 +44,8 @@ Importing Repositories There are two primary ways to import an existing repository: **Observe First**: In Git or Mercurial, you can observe the repository first. -Once the import completes, disable the **Observe** URI to automatically convert -it into a hosted repository. +Once the import completes, change the "I/O Type" on the **Observe** URI to +"No I/O" mode to automatically convert it into a hosted repository. **Push to Empty Repository**: Create an activate an empty repository, then push all of your changes to the empty repository. From 5b43d5c89ccc58d2a907dd8b7b45e94a99e4000a Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 24 May 2017 13:18:43 -0700 Subject: [PATCH 49/61] Allow Nuance commands to try to apply immediately Summary: Ref T12738. By default, we process Nuance commands in the background. The intent is to let the user continue working at full speed if Twitter or GitHub (or whatever) is being a little slow. Some commands don't do anything heavy and can be processed in the foreground. Let commands choose to try foreground execution. Test Plan: Threw complaints in the trash, saw them immediately go into the trash. Reviewers: chad Reviewed By: chad Subscribers: avivey Maniphest Tasks: T12738 Differential Revision: https://secure.phabricator.com/D18015 --- .../command/NuanceCommandImplementation.php | 6 ++ .../nuance/command/NuanceTrashCommand.php | 6 ++ .../controller/NuanceItemActionController.php | 49 +++++++++++--- .../nuance/worker/NuanceItemUpdateWorker.php | 65 +++++++++++++++++-- 4 files changed, 111 insertions(+), 15 deletions(-) diff --git a/src/applications/nuance/command/NuanceCommandImplementation.php b/src/applications/nuance/command/NuanceCommandImplementation.php index 46220266ff..2b47e40654 100644 --- a/src/applications/nuance/command/NuanceCommandImplementation.php +++ b/src/applications/nuance/command/NuanceCommandImplementation.php @@ -19,6 +19,12 @@ abstract class NuanceCommandImplementation abstract public function getCommandName(); abstract public function canApplyToItem(NuanceItem $item); + public function canApplyImmediately( + NuanceItem $item, + NuanceItemCommand $command) { + return false; + } + abstract protected function executeCommand( NuanceItem $item, NuanceItemCommand $command); diff --git a/src/applications/nuance/command/NuanceTrashCommand.php b/src/applications/nuance/command/NuanceTrashCommand.php index 1f8a729277..b5ac851539 100644 --- a/src/applications/nuance/command/NuanceTrashCommand.php +++ b/src/applications/nuance/command/NuanceTrashCommand.php @@ -14,6 +14,12 @@ final class NuanceTrashCommand return ($type instanceof NuanceFormItemType); } + public function canApplyImmediately( + NuanceItem $item, + NuanceItemCommand $command) { + return true; + } + protected function executeCommand( NuanceItem $item, NuanceItemCommand $command) { diff --git a/src/applications/nuance/controller/NuanceItemActionController.php b/src/applications/nuance/controller/NuanceItemActionController.php index c6dc139b11..39ae8fd995 100644 --- a/src/applications/nuance/controller/NuanceItemActionController.php +++ b/src/applications/nuance/controller/NuanceItemActionController.php @@ -53,6 +53,25 @@ final class NuanceItemActionController extends NuanceController { $impl->setViewer($viewer); $impl->setController($this); + $executors = NuanceCommandImplementation::getAllCommands(); + $executor = idx($executors, $action); + if (!$executor) { + return new Aphront404Response(); + } + + $executor = id(clone $executor) + ->setActor($viewer); + + if (!$executor->canApplyToItem($item)) { + return $this->newDialog() + ->setTitle(pht('Command Not Supported')) + ->appendParagraph( + pht( + 'This item does not support the specified command ("%s").', + $action)) + ->addCancelButton($cancel_uri); + } + $command = NuanceItemCommand::initializeNewCommand() ->setItemPHID($item->getPHID()) ->setAuthorPHID($viewer->getPHID()) @@ -64,17 +83,29 @@ final class NuanceItemActionController extends NuanceController { $command->save(); - // TODO: Here, we should check if the command should be tried immediately, - // and just defer it to the daemons if not. If we're going to try to apply - // the command directly, we should first acquire the worker lock. If we - // can not, we should defer the command even if it's an immediate command. - // For the moment, skip all this stuff by deferring unconditionally. + // If this command can be applied immediately, try to apply it now. - $should_defer = true; - if ($should_defer) { + // In most cases, local commands (like closing an item) can be applied + // immediately. + + // Commands that require making a call to a remote system (for example, + // to reply to a tweet or close a remote object) are usually done in the + // background so the user doesn't have to wait for the operation to + // complete before they can continue work. + + $did_apply = false; + $immediate = $executor->canApplyImmediately($item, $command); + if ($immediate) { + // TODO: Move this stuff to a new Engine, and have the controller and + // worker both call into the Engine. + $worker = new NuanceItemUpdateWorker(array()); + $did_apply = $worker->executeCommands($item, array($command)); + } + + // If this can't be applied immediately or we were unable to get a lock + // fast enough, do the update in the background instead. + if (!$did_apply) { $item->scheduleUpdate(); - } else { - // ... } if ($queue) { diff --git a/src/applications/nuance/worker/NuanceItemUpdateWorker.php b/src/applications/nuance/worker/NuanceItemUpdateWorker.php index 30d5621872..cd6637187c 100644 --- a/src/applications/nuance/worker/NuanceItemUpdateWorker.php +++ b/src/applications/nuance/worker/NuanceItemUpdateWorker.php @@ -6,9 +6,7 @@ final class NuanceItemUpdateWorker protected function doWork() { $item_phid = $this->getTaskDataValue('itemPHID'); - $hash = PhabricatorHash::digestForIndex($item_phid); - $lock_key = "nuance.item.{$hash}"; - $lock = PhabricatorGlobalLock::newLock($lock_key); + $lock = $this->newLock($item_phid); $lock->lock(1); try { @@ -55,9 +53,6 @@ final class NuanceItemUpdateWorker private function applyCommands(NuanceItem $item) { $viewer = $this->getViewer(); - $impl = $item->getImplementation(); - $impl->setViewer($viewer); - $commands = id(new NuanceItemCommandQuery()) ->setViewer($viewer) ->withItemPHIDs(array($item->getPHID())) @@ -68,8 +63,60 @@ final class NuanceItemUpdateWorker ->execute(); $commands = msort($commands, 'getID'); + $this->executeCommandList($item, $commands); + } + + public function executeCommands(NuanceItem $item, array $commands) { + if (!$commands) { + return true; + } + + $item_phid = $item->getPHID(); + $viewer = $this->getViewer(); + + $lock = $this->newLock($item_phid); + try { + $lock->lock(1); + } catch (PhutilLockException $ex) { + return false; + } + + try { + $item = $this->loadItem($item_phid); + + // Reload commands now that we have a lock, to make sure we don't + // execute any commands twice by mistake. + $commands = id(new NuanceItemCommandQuery()) + ->setViewer($viewer) + ->withIDs(mpull($commands, 'getID')) + ->execute(); + + $this->executeCommandList($item, $commands); + } catch (Exception $ex) { + $lock->unlock(); + throw $ex; + } + + $lock->unlock(); + + return true; + } + + private function executeCommandList(NuanceItem $item, array $commands) { + $viewer = $this->getViewer(); + $executors = NuanceCommandImplementation::getAllCommands(); foreach ($commands as $command) { + if ($command->getItemPHID() !== $item->getPHID()) { + throw new Exception( + pht('Trying to apply a command to the wrong item!')); + } + + if ($command->getStatus() !== NuanceItemCommand::STATUS_ISSUED) { + // Never execute commands which have already been issued. + continue; + } + $command ->setStatus(NuanceItemCommand::STATUS_EXECUTING) ->save(); @@ -105,4 +152,10 @@ final class NuanceItemUpdateWorker } } + private function newLock($item_phid) { + $hash = PhabricatorHash::digestForIndex($item_phid); + $lock_key = "nuance.item.{$hash}"; + return PhabricatorGlobalLock::newLock($lock_key); + } + } From 718c39131da809cbcc40276193ae201d60e1e4d2 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 26 May 2017 08:58:35 -0700 Subject: [PATCH 50/61] Add a little style to Phriction ToC menu Summary: Adds some indentation and color. Ref T9868. Test Plan: A long page with multiple indentation levels. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T9868 Differential Revision: https://secure.phabricator.com/D18025 --- resources/celerity/map.php | 4 +-- webroot/rsrc/css/phui/phui-document-pro.css | 27 ++++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3011b17643..8f5dee69e8 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -147,7 +147,7 @@ return array( 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', 'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb', 'rsrc/css/phui/phui-curtain-view.css' => '55dd0e59', - 'rsrc/css/phui/phui-document-pro.css' => '58199f99', + 'rsrc/css/phui/phui-document-pro.css' => 'bb18da6b', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', @@ -851,7 +851,7 @@ return array( 'phui-curtain-view-css' => '55dd0e59', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', - 'phui-document-view-pro-css' => '58199f99', + 'phui-document-view-pro-css' => 'bb18da6b', 'phui-feed-story-css' => '44a9c8e9', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '1320ed01', diff --git a/webroot/rsrc/css/phui/phui-document-pro.css b/webroot/rsrc/css/phui/phui-document-pro.css index 8ece71db64..a4c05a0ecd 100644 --- a/webroot/rsrc/css/phui/phui-document-pro.css +++ b/webroot/rsrc/css/phui/phui-document-pro.css @@ -84,7 +84,7 @@ a.button.phui-document-toc { border: 1px solid {$lightgreyborder}; border-radius: 3px; box-shadow: {$dropshadow}; - width: 200px; + width: 260px; position: absolute; z-index: 30; background-color: #fff; @@ -114,17 +114,38 @@ a.button.phui-document-toc { } .phui-document-view-pro .phui-document-toc-content { - margin: 4px 12px; + margin: 8px 16px; } .phui-document-view-pro .phui-document-toc-header { font-weight: bold; color: {$bluetext}; margin-bottom: 8px; + text-transform: uppercase; + font-size: {$smallerfontsize}; } .phui-document-view-pro .phui-document-toc-content li { - margin: 4px 8px; + margin: 4px 8px 4px 0; +} + +.phui-document-view-pro .phui-document-toc-content a { + padding: 2px 0; + display: block; + text-decoration: none; + color: {$darkbluetext}; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.phui-document-view-pro .phui-document-toc-content a:hover { + color: {$anchor}; + text-decoration: underline; +} + +.phui-document-view-pro .phui-document-toc-content li + ul { + margin: 4px 0 4px 8px; } .phui-document-view-pro .phui-document-content .phabricator-remarkup { From 69538274c1aceb40374124063bb902cf32da76e4 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 26 May 2017 08:46:48 -0700 Subject: [PATCH 51/61] Garbage collect old daemon records based on modification date, not creation date Summary: Fixes T12720. Currently, old daemon records are collected based on creation date. By default, the GC collects them after 7 days. After T12298, this can incorrectly collect hibernating daemons which are in state "wait". In all cases, this could fail to collect daemons which are stuck in "running" for a long time for some reason. This doesn't seem to be causing any problems right now, but it makes me hesitant to do "dateCreated + not running or waiting" since that might make this become a problem, or make an existing problem with this that we just haven't bumped into worse. Daemons always heartbeat periodically and update their rows, so `dateModified` is always fresh, so collect rows based only on modification date. Test Plan: - Ran daemons (`bin/phd start`). - Waited a few minutes. - Verified that hibernating daemons in the "wait" state had fresh timestamps. - Verified that very old daemons still got GC'd properly. ``` mysql> select id, daemon, status, FROM_UNIXTIME(dateCreated), FROM_UNIXTIME(dateModified) from daemon_log; +-------+--------------------------------------+--------+----------------------------+-----------------------------+ | id | daemon | status | FROM_UNIXTIME(dateCreated) | FROM_UNIXTIME(dateModified) | +-------+--------------------------------------+--------+----------------------------+-----------------------------+ | 73377 | PhabricatorTaskmasterDaemon | exit | 2017-05-19 10:53:03 | 2017-05-19 12:38:54 | ... | 73388 | PhabricatorRepositoryPullLocalDaemon | run | 2017-05-26 08:43:29 | 2017-05-26 08:45:30 | | 73389 | PhabricatorTriggerDaemon | run | 2017-05-26 08:43:29 | 2017-05-26 08:46:35 | | 73390 | PhabricatorTaskmasterDaemon | wait | 2017-05-26 08:43:29 | 2017-05-26 08:46:35 | | 73391 | PhabricatorTaskmasterDaemon | wait | 2017-05-26 08:43:33 | 2017-05-26 08:46:33 | | 73392 | PhabricatorTaskmasterDaemon | wait | 2017-05-26 08:43:37 | 2017-05-26 08:46:31 | | 73393 | PhabricatorTaskmasterDaemon | wait | 2017-05-26 08:43:40 | 2017-05-26 08:46:33 | +-------+--------------------------------------+--------+----------------------------+-----------------------------+ 17 rows in set (0.00 sec) ``` Note that: - The oldest daemon is <7 days old -- I had some other older rows but they got GC'd properly. - The hibernating taskmasters (at the bottom, in state "wait") have recent/more-current `dateModified` dates than their `dateCreated` dates. Reviewers: chad, amckinley Reviewed By: chad Maniphest Tasks: T12720 Differential Revision: https://secure.phabricator.com/D18024 --- .../PhabricatorDaemonLogGarbageCollector.php | 5 ++--- src/applications/daemon/storage/PhabricatorDaemonLog.php | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php b/src/applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php index 3ff26e3db7..fd7de9dd33 100644 --- a/src/applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php +++ b/src/applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php @@ -19,10 +19,9 @@ final class PhabricatorDaemonLogGarbageCollector queryfx( $conn_w, - 'DELETE FROM %T WHERE dateCreated < %d AND status != %s LIMIT 100', + 'DELETE FROM %T WHERE dateModified < %d LIMIT 100', $table->getTableName(), - $this->getGarbageEpoch(), - PhabricatorDaemonLog::STATUS_RUNNING); + $this->getGarbageEpoch()); return ($conn_w->getAffectedRows() == 100); } diff --git a/src/applications/daemon/storage/PhabricatorDaemonLog.php b/src/applications/daemon/storage/PhabricatorDaemonLog.php index 2e61da3872..d3ac485ea2 100644 --- a/src/applications/daemon/storage/PhabricatorDaemonLog.php +++ b/src/applications/daemon/storage/PhabricatorDaemonLog.php @@ -37,13 +37,13 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO 'status' => array( 'columns' => array('status'), ), - 'dateCreated' => array( - 'columns' => array('dateCreated'), - ), 'key_daemonID' => array( 'columns' => array('daemonID'), 'unique' => true, ), + 'key_modified' => array( + 'columns' => array('dateModified'), + ), ), ) + parent::getConfiguration(); } From 2d79229083437a10bb16c4eb8bff393506f9c887 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 26 May 2017 09:43:40 -0700 Subject: [PATCH 52/61] Modernize FeedQuery a little bit Summary: Ref T12762. Updates some conventions and methods. This has no (meaningful) behavioral changes. Test Plan: - Grepped for `setFilterPHIDs()`. - Viewed main feed, user feed, project feed. - Called `feed.query`. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12762 Differential Revision: https://secure.phabricator.com/D18027 --- .../conduit/FeedQueryConduitAPIMethod.php | 10 ++-- .../feed/query/PhabricatorFeedQuery.php | 60 +++++++++---------- .../query/PhabricatorFeedSearchEngine.php | 2 +- ...PhabricatorPeopleProfileViewController.php | 2 +- .../PhabricatorProjectProfileController.php | 2 +- 5 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php b/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php index 661b70a7ab..bddc4f5921 100644 --- a/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php +++ b/src/applications/feed/conduit/FeedQueryConduitAPIMethod.php @@ -67,16 +67,16 @@ final class FeedQueryConduitAPIMethod extends FeedConduitAPIMethod { if (!$limit) { $limit = $this->getDefaultLimit(); } - $filter_phids = $request->getValue('filterPHIDs'); - if (!$filter_phids) { - $filter_phids = array(); - } $query = id(new PhabricatorFeedQuery()) ->setLimit($limit) - ->setFilterPHIDs($filter_phids) ->setViewer($user); + $filter_phids = $request->getValue('filterPHIDs'); + if ($filter_phids) { + $query->withFilterPHIDs($filter_phids); + } + $after = $request->getValue('after'); if (strlen($after)) { $query->setAfterID($after); diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php index 13cfb266ed..7335a6d5b1 100644 --- a/src/applications/feed/query/PhabricatorFeedQuery.php +++ b/src/applications/feed/query/PhabricatorFeedQuery.php @@ -6,7 +6,7 @@ final class PhabricatorFeedQuery private $filterPHIDs; private $chronologicalKeys; - public function setFilterPHIDs(array $phids) { + public function withFilterPHIDs(array $phids) { $this->filterPHIDs = $phids; return $this; } @@ -16,50 +16,46 @@ final class PhabricatorFeedQuery return $this; } + public function newResultObject() { + return new PhabricatorFeedStoryData(); + } + protected function loadPage() { - $story_table = new PhabricatorFeedStoryData(); - $conn = $story_table->establishConnection('r'); - - $data = queryfx_all( - $conn, - 'SELECT story.* FROM %T story %Q %Q %Q %Q %Q', - $story_table->getTableName(), - $this->buildJoinClause($conn), - $this->buildWhereClause($conn), - $this->buildGroupClause($conn), - $this->buildOrderClause($conn), - $this->buildLimitClause($conn)); - - return $data; + // NOTE: We return raw rows from this method, which is a little unusual. + return $this->loadStandardPageRows($this->newResultObject()); } protected function willFilterPage(array $data) { return PhabricatorFeedStory::loadAllFromRows($data, $this->getViewer()); } - protected function buildJoinClause(AphrontDatabaseConnection $conn_r) { + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { + $joins = parent::buildJoinClauseParts($conn); + // NOTE: We perform this join unconditionally (even if we have no filter // PHIDs) to omit rows which have no story references. These story data // rows are notifications or realtime alerts. $ref_table = new PhabricatorFeedStoryReference(); - return qsprintf( - $conn_r, + $joins[] = qsprintf( + $conn, 'JOIN %T ref ON ref.chronologicalKey = story.chronologicalKey', $ref_table->getTableName()); + + return $joins; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); - if ($this->filterPHIDs) { + if ($this->filterPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'ref.objectPHID IN (%Ls)', $this->filterPHIDs); } - if ($this->chronologicalKeys) { + if ($this->chronologicalKeys !== null) { // NOTE: We want to use integers in the query so we can take advantage // of keys, but can't use %d on 32-bit systems. Make sure all the keys // are integers and then format them raw. @@ -73,21 +69,19 @@ final class PhabricatorFeedQuery } $where[] = qsprintf( - $conn_r, + $conn, 'ref.chronologicalKey IN (%Q)', implode(', ', $keys)); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } - protected function buildGroupClause(AphrontDatabaseConnection $conn_r) { - if ($this->filterPHIDs) { - return qsprintf($conn_r, 'GROUP BY ref.chronologicalKey'); + protected function buildGroupClause(AphrontDatabaseConnection $conn) { + if ($this->filterPHIDs !== null) { + return qsprintf($conn, 'GROUP BY ref.chronologicalKey'); } else { - return qsprintf($conn_r, 'GROUP BY story.chronologicalKey'); + return qsprintf($conn, 'GROUP BY story.chronologicalKey'); } } @@ -120,6 +114,10 @@ final class PhabricatorFeedQuery return $item['chronologicalKey']; } + protected function getPrimaryTableAlias() { + return 'story'; + } + public function getQueryApplicationClass() { return 'PhabricatorFeedApplication'; } diff --git a/src/applications/feed/query/PhabricatorFeedSearchEngine.php b/src/applications/feed/query/PhabricatorFeedSearchEngine.php index b8caf60ae7..43a0b716ca 100644 --- a/src/applications/feed/query/PhabricatorFeedSearchEngine.php +++ b/src/applications/feed/query/PhabricatorFeedSearchEngine.php @@ -56,7 +56,7 @@ final class PhabricatorFeedSearchEngine $phids = array_mergev($phids); if ($phids) { - $query->setFilterPHIDs($phids); + $query->withFilterPHIDs($phids); } return $query; diff --git a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php index 9db106081d..7bcab34b17 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php @@ -229,7 +229,7 @@ final class PhabricatorPeopleProfileViewController $viewer) { $query = new PhabricatorFeedQuery(); - $query->setFilterPHIDs( + $query->withFilterPHIDs( array( $user->getPHID(), )); diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index e47cc678bc..d9fe019751 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -73,7 +73,7 @@ final class PhabricatorProjectProfileController $stories = id(new PhabricatorFeedQuery()) ->setViewer($viewer) - ->setFilterPHIDs( + ->withFilterPHIDs( array( $project->getPHID(), )) From 6fed08a98e042c883fcd482e4ec876f11d02de1e Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 26 May 2017 10:08:33 -0700 Subject: [PATCH 53/61] Modernize FeedSearchEngine a little bit Summary: Ref T12762. This updates FeedSeachEngine to user modern construction. I've tried to retain behavior exactly, although the "Include stories about projects I'm a member of" checkbox is now nonstandard/obsolete. We could likely fold that into "Include Projects" in a future change which does a backward compatibility break. Test Plan: - Queried feed without constraints. - Queried feed by user, project, "stuff I'm a member of", prebuilt "Tags" query. - Viewed user profile / project profile feeds. - Used function tokens (`viewer()`, etc). Reviewers: chad Reviewed By: chad Maniphest Tasks: T12762 Differential Revision: https://secure.phabricator.com/D18028 --- .../feed/query/PhabricatorFeedQuery.php | 14 +++ .../query/PhabricatorFeedSearchEngine.php | 100 +++++++----------- 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php index 7335a6d5b1..f8f67f7a3e 100644 --- a/src/applications/feed/query/PhabricatorFeedQuery.php +++ b/src/applications/feed/query/PhabricatorFeedQuery.php @@ -89,6 +89,20 @@ final class PhabricatorFeedQuery return array('key'); } + public function getBuiltinOrders() { + return array( + 'newest' => array( + 'vector' => array('key'), + 'name' => pht('Creation (Newest First)'), + 'aliases' => array('created'), + ), + 'oldest' => array( + 'vector' => array('-key'), + 'name' => pht('Creation (Oldest First)'), + ), + ); + } + public function getOrderableColumns() { $table = ($this->filterPHIDs ? 'ref' : 'story'); return array( diff --git a/src/applications/feed/query/PhabricatorFeedSearchEngine.php b/src/applications/feed/query/PhabricatorFeedSearchEngine.php index 43a0b716ca..6dae9f9c37 100644 --- a/src/applications/feed/query/PhabricatorFeedSearchEngine.php +++ b/src/applications/feed/query/PhabricatorFeedSearchEngine.php @@ -11,50 +11,62 @@ final class PhabricatorFeedSearchEngine return 'PhabricatorFeedApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - $saved->setParameter( - 'userPHIDs', - $this->readUsersFromRequest($request, 'users')); - - $saved->setParameter( - 'projectPHIDs', - array_values($request->getArr('projectPHIDs'))); - - $saved->setParameter( - 'viewerProjects', - $request->getBool('viewerProjects')); - - return $saved; + public function newQuery() { + return new PhabricatorFeedQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new PhabricatorFeedQuery()); + protected function shouldShowOrderField() { + return false; + } + + protected function buildCustomSearchFields() { + return array( + id(new PhabricatorUsersSearchField()) + ->setLabel(pht('Include Users')) + ->setKey('userPHIDs'), + // NOTE: This query is not executed with EdgeLogic, so we can't use + // a fancy logical datasource. + id(new PhabricatorSearchDatasourceField()) + ->setDatasource(new PhabricatorProjectDatasource()) + ->setLabel(pht('Include Projects')) + ->setKey('projectPHIDs'), + + // NOTE: This is a legacy field retained only for backward + // compatibility. If the projects field used EdgeLogic, we could use + // `viewerprojects()` to execute an equivalent query. + id(new PhabricatorSearchCheckboxesField()) + ->setKey('viewerProjects') + ->setOptions( + array( + 'self' => pht('Include stories about projects I am a member of.'), + )), + ); + } + + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); $phids = array(); - - $user_phids = $saved->getParameter('userPHIDs'); - if ($user_phids) { - $phids[] = $user_phids; + if ($map['userPHIDs']) { + $phids += array_fuse($map['userPHIDs']); } - $proj_phids = $saved->getParameter('projectPHIDs'); - if ($proj_phids) { - $phids[] = $proj_phids; + if ($map['projectPHIDs']) { + $phids += array_fuse($map['projectPHIDs']); } - $viewer_projects = $saved->getParameter('viewerProjects'); + // NOTE: This value may be `true` for older saved queries, or + // `array('self')` for newer ones. + $viewer_projects = $map['viewerProjects']; if ($viewer_projects) { $viewer = $this->requireViewer(); $projects = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->withMemberPHIDs(array($viewer->getPHID())) ->execute(); - $phids[] = mpull($projects, 'getPHID'); + $phids += array_fuse(mpull($projects, 'getPHID')); } - $phids = array_mergev($phids); if ($phids) { $query->withFilterPHIDs($phids); } @@ -62,36 +74,6 @@ final class PhabricatorFeedSearchEngine return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $user_phids = $saved_query->getParameter('userPHIDs', array()); - $proj_phids = $saved_query->getParameter('projectPHIDs', array()); - $viewer_projects = $saved_query->getParameter('viewerProjects'); - - $form - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setName('users') - ->setLabel(pht('Include Users')) - ->setValue($user_phids)) - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorProjectDatasource()) - ->setName('projectPHIDs') - ->setLabel(pht('Include Projects')) - ->setValue($proj_phids)) - ->appendChild( - id(new AphrontFormCheckboxControl()) - ->addCheckbox( - 'viewerProjects', - 1, - pht('Include stories about projects I am a member of.'), - $viewer_projects)); - } - protected function getURI($path) { return '/feed/'.$path; } @@ -117,7 +99,7 @@ final class PhabricatorFeedSearchEngine case 'all': return $query; case 'projects': - return $query->setParameter('viewerProjects', true); + return $query->setParameter('viewerProjects', array('self')); } return parent::buildSavedQueryFromBuiltin($query_key); From 46a33c07dc0c5aa89022dafcc0c253d1340a6071 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 26 May 2017 10:22:29 -0700 Subject: [PATCH 54/61] Allow users to query feed by a date range Summary: Ref T12762. Test Plan: - Ran queries with start date, end date, both, neither. - Used EXPLAIN to try to make sure doing the bitshift isn't going to be a performance issue. {F4978842} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12762 Differential Revision: https://secure.phabricator.com/D18029 --- .../feed/query/PhabricatorFeedQuery.php | 26 ++++++++++++++++ .../query/PhabricatorFeedSearchEngine.php | 30 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php index f8f67f7a3e..ae1da3aba0 100644 --- a/src/applications/feed/query/PhabricatorFeedQuery.php +++ b/src/applications/feed/query/PhabricatorFeedQuery.php @@ -5,6 +5,8 @@ final class PhabricatorFeedQuery private $filterPHIDs; private $chronologicalKeys; + private $rangeMin; + private $rangeMax; public function withFilterPHIDs(array $phids) { $this->filterPHIDs = $phids; @@ -16,6 +18,12 @@ final class PhabricatorFeedQuery return $this; } + public function withEpochInRange($range_min, $range_max) { + $this->rangeMin = $range_min; + $this->rangeMax = $range_max; + return $this; + } + public function newResultObject() { return new PhabricatorFeedStoryData(); } @@ -74,6 +82,24 @@ final class PhabricatorFeedQuery implode(', ', $keys)); } + // NOTE: We may not have 64-bit PHP, so do the shifts in MySQL instead. + // From EXPLAIN, it appears like MySQL is smart enough to compute the + // result and make use of keys to execute the query. + + if ($this->rangeMin !== null) { + $where[] = qsprintf( + $conn, + 'ref.chronologicalKey >= (%d << 32)', + $this->rangeMin); + } + + if ($this->rangeMax !== null) { + $where[] = qsprintf( + $conn, + 'ref.chronologicalKey < (%d << 32)', + $this->rangeMax); + } + return $where; } diff --git a/src/applications/feed/query/PhabricatorFeedSearchEngine.php b/src/applications/feed/query/PhabricatorFeedSearchEngine.php index 6dae9f9c37..d17c756524 100644 --- a/src/applications/feed/query/PhabricatorFeedSearchEngine.php +++ b/src/applications/feed/query/PhabricatorFeedSearchEngine.php @@ -30,6 +30,12 @@ final class PhabricatorFeedSearchEngine ->setDatasource(new PhabricatorProjectDatasource()) ->setLabel(pht('Include Projects')) ->setKey('projectPHIDs'), + id(new PhabricatorSearchDateControlField()) + ->setLabel(pht('Occurs After')) + ->setKey('rangeStart'), + id(new PhabricatorSearchDateControlField()) + ->setLabel(pht('Occurs Before')) + ->setKey('rangeEnd'), // NOTE: This is a legacy field retained only for backward // compatibility. If the projects field used EdgeLogic, we could use @@ -71,6 +77,30 @@ final class PhabricatorFeedSearchEngine $query->withFilterPHIDs($phids); } + $range_min = $map['rangeStart']; + if ($range_min) { + $range_min = $range_min->getEpoch(); + } + + $range_max = $map['rangeEnd']; + if ($range_max) { + $range_max = $range_max->getEpoch(); + } + + if ($range_min && $range_max) { + if ($range_min > $range_max) { + throw new PhabricatorSearchConstraintException( + pht( + 'The specified "Occurs Before" date is earlier in time than the '. + 'specified "Occurs After" date, so this query can never match '. + 'any results.')); + } + } + + if ($range_min || $range_max) { + $query->withEpochInRange($range_min, $range_max); + } + return $query; } From fc8465252fb1fa737671e34b4085d922770daa36 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 26 May 2017 10:34:42 -0700 Subject: [PATCH 55/61] Add "View All" header buttons to user and project feed boxes Summary: Fixes T12762. Currently, there's no way to get from these boxes into generaly history in Feed, and it isn't clear that the operation is possible. For now, add some simple links. See T12762 for future work. Test Plan: - Viewed user profles, saw "View All". - Viewed project profiles, saw "View All". {F4978858} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12762 Differential Revision: https://secure.phabricator.com/D18030 --- .../PhabricatorPeopleProfileViewController.php | 15 ++++++++++++++- .../PhabricatorProjectProfileController.php | 14 +++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php index 7bcab34b17..5dce872c4b 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php @@ -28,8 +28,21 @@ final class PhabricatorPeopleProfileViewController $name = $user->getUsername(); $feed = $this->buildPeopleFeed($user, $viewer); + + $view_all = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon( + id(new PHUIIconView()) + ->setIcon('fa-list-ul')) + ->setText(pht('View All')) + ->setHref('/feed/?userPHIDs='.$user->getPHID()); + + $feed_header = id(new PHUIHeaderView()) + ->setHeader(pht('Recent Activity')) + ->addActionLink($view_all); + $feed = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Recent Activity')) + ->setHeader($feed_header) ->addClass('project-view-feed') ->appendChild($feed); diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index d9fe019751..1f59398930 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -80,9 +80,21 @@ final class PhabricatorProjectProfileController ->setLimit(50) ->execute(); + $view_all = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon( + id(new PHUIIconView()) + ->setIcon('fa-list-ul')) + ->setText(pht('View All')) + ->setHref('/feed/?projectPHIDs='.$project->getPHID()); + + $feed_header = id(new PHUIHeaderView()) + ->setHeader(pht('Recent Activity')) + ->addActionLink($view_all); + $feed = $this->renderStories($stories); $feed = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Recent Activity')) + ->setHeader($feed_header) ->addClass('project-view-feed') ->appendChild($feed); From b27c2ed6d1e68e94f36db661f856c99d94fc161e Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Fri, 26 May 2017 13:01:28 -0700 Subject: [PATCH 56/61] Index Project milestones to accurately reflect milestone membership Summary: Fixes T12505. `PhabricatorProjectsMembershipIndexEngineExtension->materializeProject()` was incorrectly bailing early for milestone objects, which prevented milestone members from being calculated correctly. This was causing problems where (for example) an Owners package owned by a milestone wasn't being satisfied when a member of the milestone approved a revision. Test Plan: Invoked migration, observed that a user's milestones correctly showed up when searched for. Also observed that accepting a revision on behalf of a milestone now satisfies Owners rules. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12505 Differential Revision: https://secure.phabricator.com/D18033 --- .../sql/autopatches/20170526.milestones.php | 11 ++++++ ...ProjectsMembershipIndexEngineExtension.php | 35 ++++++++++--------- 2 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 resources/sql/autopatches/20170526.milestones.php diff --git a/resources/sql/autopatches/20170526.milestones.php b/resources/sql/autopatches/20170526.milestones.php new file mode 100644 index 0000000000..2e30ac4775 --- /dev/null +++ b/resources/sql/autopatches/20170526.milestones.php @@ -0,0 +1,11 @@ +getPHID(), + array( + 'force' => true, + )); +} diff --git a/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php b/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php index 567f5b749e..5acfaf913a 100644 --- a/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php +++ b/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php @@ -34,29 +34,30 @@ final class PhabricatorProjectsMembershipIndexEngineExtension } private function materializeProject(PhabricatorProject $project) { - if ($project->isMilestone()) { - return; - } - $material_type = PhabricatorProjectMaterializedMemberEdgeType::EDGECONST; $member_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; $project_phid = $project->getPHID(); - $descendants = id(new PhabricatorProjectQuery()) - ->setViewer($this->getViewer()) - ->withAncestorProjectPHIDs(array($project->getPHID())) - ->withIsMilestone(false) - ->withHasSubprojects(false) - ->execute(); - $descendant_phids = mpull($descendants, 'getPHID'); - - if ($descendant_phids) { - $source_phids = $descendant_phids; - $has_subprojects = true; - } else { - $source_phids = array($project->getPHID()); + if ($project->isMilestone()) { + $source_phids = array($project->getParentProjectPHID()); $has_subprojects = false; + } else { + $descendants = id(new PhabricatorProjectQuery()) + ->setViewer($this->getViewer()) + ->withAncestorProjectPHIDs(array($project->getPHID())) + ->withIsMilestone(false) + ->withHasSubprojects(false) + ->execute(); + $descendant_phids = mpull($descendants, 'getPHID'); + + if ($descendant_phids) { + $source_phids = $descendant_phids; + $has_subprojects = true; + } else { + $source_phids = array($project->getPHID()); + $has_subprojects = false; + } } $conn_w = $project->establishConnection('w'); From aefc006ba503eb47113372e7adf2888fdf79d8a0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 26 May 2017 09:26:06 -0700 Subject: [PATCH 57/61] Move DiffusionHistoryListView to DiffusionCommitListView Summary: I think this name is more accurate, also add proper links to author image. Test Plan: Review commits in sandbox, see new URL on image. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18026 --- src/__phutil_library_map__.php | 4 ++-- ...fusionHistoryListView.php => DiffusionCommitListView.php} | 5 ++++- .../controller/PhabricatorPeopleProfileCommitsController.php | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) rename src/applications/diffusion/view/{DiffusionHistoryListView.php => DiffusionCommitListView.php} (95%) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7510f2e42c..9605ebfc14 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -661,6 +661,7 @@ phutil_register_library_map(array( 'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php', 'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php', 'DiffusionCommitListController' => 'applications/diffusion/controller/DiffusionCommitListController.php', + 'DiffusionCommitListView' => 'applications/diffusion/view/DiffusionCommitListView.php', 'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php', 'DiffusionCommitMessageHeraldField' => 'applications/diffusion/herald/DiffusionCommitMessageHeraldField.php', 'DiffusionCommitPackageAuditHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageAuditHeraldField.php', @@ -728,7 +729,6 @@ phutil_register_library_map(array( 'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php', 'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', - 'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php', 'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php', @@ -5634,6 +5634,7 @@ phutil_register_library_map(array( 'DiffusionCommitHookEngine' => 'Phobject', 'DiffusionCommitHookRejectException' => 'Exception', 'DiffusionCommitListController' => 'DiffusionController', + 'DiffusionCommitListView' => 'AphrontView', 'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitMessageHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitPackageAuditHeraldField' => 'DiffusionCommitHeraldField', @@ -5704,7 +5705,6 @@ phutil_register_library_map(array( ), 'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionHistoryController' => 'DiffusionController', - 'DiffusionHistoryListView' => 'AphrontView', 'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', diff --git a/src/applications/diffusion/view/DiffusionHistoryListView.php b/src/applications/diffusion/view/DiffusionCommitListView.php similarity index 95% rename from src/applications/diffusion/view/DiffusionHistoryListView.php rename to src/applications/diffusion/view/DiffusionCommitListView.php index 00a6eb0741..b3f2a9fb0c 100644 --- a/src/applications/diffusion/view/DiffusionHistoryListView.php +++ b/src/applications/diffusion/view/DiffusionCommitListView.php @@ -1,6 +1,6 @@ renderLink(); $author_image_uri = $handles[$author_phid]->getImageURI(); + $author_image_href = $handles[$author_phid]->getURI(); } else { $author_name = $commit->getCommitData()->getAuthorName(); $author_image_uri = celerity_get_resource_uri('/rsrc/image/people/user0.png'); + $author_image_href = null; } $commit_tag = id(new PHUITagView()) @@ -132,6 +134,7 @@ final class DiffusionHistoryListView extends AphrontView { ->setDisabled($commit->isUnreachable()) ->setDescription($message) ->setImageURI($author_image_uri) + ->setImageHref($author_image_href) ->addByline(pht('Author: %s', $author_name)) ->addIcon('none', $committed) ->addAttribute($commit_tag); diff --git a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php index 81e4fa304e..c18c5f4d96 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileCommitsController.php @@ -60,7 +60,7 @@ final class PhabricatorPeopleProfileCommitsController ->setLimit(100) ->execute(); - $list = id(new DiffusionHistoryListView()) + $list = id(new DiffusionCommitListView()) ->setViewer($viewer) ->setCommits($commits) ->setNoDataString(pht('No recent commits.')); From 81809713e0780aeb135cd4f8b32131a0adf7e5dd Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 26 May 2017 11:42:31 -0700 Subject: [PATCH 58/61] Try layering state icons on PHUICircleIconView Summary: I think this is reasonable for my current use case, but stacking icons overally is pretty clunky. Test Plan: UIExamples {F4978899} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18032 --- resources/celerity/map.php | 6 +-- .../uiexample/examples/PHUIIconExample.php | 17 +++++++ src/view/phui/PHUIIconCircleView.php | 47 ++++++++++++++++++- webroot/rsrc/css/phui/phui-icon.css | 34 +++++++++++++- 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 8f5dee69e8..a2119c98a4 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => 'b666574e', + 'core.pkg.css' => '19f6f61f', 'core.pkg.js' => '21d34805', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '7d4cfa59', @@ -158,7 +158,7 @@ return array( 'rsrc/css/phui/phui-header-view.css' => 'a3d1aecd', 'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', - 'rsrc/css/phui/phui-icon.css' => '12b387a1', + 'rsrc/css/phui/phui-icon.css' => '4c6d624c', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-view.css' => '6e217679', @@ -862,7 +862,7 @@ return array( 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'f0592bcf', 'phui-icon-set-selector-css' => '87db8fee', - 'phui-icon-view-css' => '12b387a1', + 'phui-icon-view-css' => '4c6d624c', 'phui-image-mask-css' => 'a8498f9c', 'phui-info-panel-css' => '27ea50a1', 'phui-info-view-css' => '6e217679', diff --git a/src/applications/uiexample/examples/PHUIIconExample.php b/src/applications/uiexample/examples/PHUIIconExample.php index 8e01d6e16a..1bf96ce8e5 100644 --- a/src/applications/uiexample/examples/PHUIIconExample.php +++ b/src/applications/uiexample/examples/PHUIIconExample.php @@ -130,6 +130,23 @@ final class PHUIIconExample extends PhabricatorUIExample { ->addClass('mmr'); } + $circles = array('fa-gear', 'fa-recycle'); + $colors = array('green', 'pink', 'red', 'sky', 'violet'); + foreach ($circles as $circle) { + $states = PHUIIconCircleView::getStateMap(); + foreach ($states as $state => $name) { + $i = array_rand($colors); + $circleview[] = + id(new PHUIIconCircleView()) + ->setIcon($circle) + ->setSize(PHUIIconCircleView::SMALL) + ->setState($state) + ->setColor($colors[$i]) + ->setHref('#') + ->addClass('mmr'); + } + } + $squares = array('fa-briefcase', 'fa-code', 'fa-globe', 'fa-home'); $squareview = array(); foreach ($squares as $icon) { diff --git a/src/view/phui/PHUIIconCircleView.php b/src/view/phui/PHUIIconCircleView.php index 083818969f..11e2a2ac3b 100644 --- a/src/view/phui/PHUIIconCircleView.php +++ b/src/view/phui/PHUIIconCircleView.php @@ -6,10 +6,22 @@ final class PHUIIconCircleView extends AphrontTagView { private $icon; private $color; private $size; + private $state; const SMALL = 'circle-small'; const MEDIUM = 'circle-medium'; + const STATE_FAIL = 'fa-times-circle'; + const STATE_INFO = 'fa-info-circle'; + const STATE_STOP = 'fa-stop-circle'; + const STATE_START = 'fa-play-circle'; + const STATE_PAUSE = 'fa-pause-circle'; + const STATE_SUCCESS = 'fa-check-circle'; + const STATE_WARNING = 'fa-exclamation-circle'; + const STATE_PLUS = 'fa-plus-circle'; + const STATE_MINUS = 'fa-minus-circle'; + const STATE_UNKNOWN = 'fa-question-circle'; + public function setHref($href) { $this->href = $href; return $this; @@ -30,6 +42,11 @@ final class PHUIIconCircleView extends AphrontTagView { return $this; } + public function setState($state) { + $this->state = $state; + return $this; + } + protected function getTagName() { $tag = 'span'; if ($this->href) { @@ -54,6 +71,10 @@ final class PHUIIconCircleView extends AphrontTagView { $classes[] = $this->size; } + if ($this->state) { + $classes[] = 'phui-icon-circle-state'; + } + return array( 'href' => $this->href, 'class' => $classes, @@ -61,8 +82,32 @@ final class PHUIIconCircleView extends AphrontTagView { } protected function getTagContent() { + $state = null; + if ($this->state) { + $state = id(new PHUIIconView()) + ->setIcon($this->state.' '.$this->color) + ->addClass('phui-icon-circle-state-icon'); + } + return id(new PHUIIconView()) - ->setIcon($this->icon); + ->setIcon($this->icon) + ->addClass('phui-icon-circle-icon') + ->appendChild($state); + } + + public static function getStateMap() { + return array( + self::STATE_FAIL => pht('Failure'), + self::STATE_INFO => pht('Information'), + self::STATE_STOP => pht('Stop'), + self::STATE_START => pht('Start'), + self::STATE_PAUSE => pht('Pause'), + self::STATE_SUCCESS => pht('Success'), + self::STATE_WARNING => pht('Warning'), + self::STATE_PLUS => pht('Plus'), + self::STATE_MINUS => pht('Minus'), + self::STATE_UNKNOWN => pht('Unknown'), + ); } } diff --git a/webroot/rsrc/css/phui/phui-icon.css b/webroot/rsrc/css/phui/phui-icon.css index 22b33bca11..627b7632fe 100644 --- a/webroot/rsrc/css/phui/phui-icon.css +++ b/webroot/rsrc/css/phui/phui-icon.css @@ -57,6 +57,7 @@ img.phui-image-disabled { cursor: pointer; background: transparent; padding: 0; + position: relative; } .phui-icon-circle.circle-medium { @@ -65,7 +66,21 @@ img.phui-image-disabled { border-radius: 36px; } -.phui-icon-circle .phui-icon-view { +.phui-icon-circle.phui-icon-circle-state { + border-color: transparent; + background-color: {$bluebackground}; +} + +.phui-icon-circle.phui-icon-circle-state .phui-icon-circle-icon { + color: {$bluetext}; + font-size: 16px; +} + +a.phui-icon-circle.phui-icon-circle-state:hover { + border-color: transparent !important; +} + +.phui-icon-circle .phui-icon-circle-icon { height: 24px; width: 24px; font-size: 11px; @@ -74,7 +89,7 @@ img.phui-image-disabled { cursor: pointer; } -.phui-icon-circle.circle-medium .phui-icon-view { +.phui-icon-circle.circle-medium .phui-icon-circle-icon { font-size: 18px; line-height: 36px; } @@ -129,6 +144,21 @@ a.phui-icon-circle.hover-red:hover .phui-icon-view { color: {$red}; } +a.phui-icon-circle .phui-icon-view.phui-icon-circle-state-icon { + position: absolute; + width: 14px; + height: 14px; + display: inline-block; + font-size: 12px; + right: -3px; + top: -4px; + text-shadow: + -1px -1px 0 #fff, + 1px -1px 0 #fff, + -1px 1px 0 #fff, + 1px 1px 0 #fff; +} + /* - Icon in a Square ------------------------------------------------------- */ .phui-icon-view.phui-icon-square { From 742c3a834fc5cd19a4b53e9ff31f7b0efd67e239 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 2 Mar 2017 05:02:53 -0800 Subject: [PATCH 59/61] Provide UI hints about task subtypes Summary: Ref T12314. Open to counterdiffs / iterating / suggestions / skipping most or all of this, mostly just throwing this out there as a maybe-reasonable first pass. When a task has a subtype (like "Plant" or "Animal"), provide some hints on the task list, workboards, and task detail. To make these hints more useful, allow subtypes to have icons and colors. Also use these icons and colors in the typeahead tokens. The current rule is that we show the subtype if it's not the default subtype. Another rule we could use is "show the subtype if there's more than one subtype defined", but my guess is that most installs will mostly have something like "normal task" as the default subtype. Test Plan: The interfaces this affects are: task detail view, task list view, workboard cards, subtype typeahead. {F3539128} {F3539144} {F3539167} {F3539185} Reviewers: chad Reviewed By: chad Subscribers: johnny-bit, bbrdaric, benwick, fooishbar Maniphest Tasks: T12314 Differential Revision: https://secure.phabricator.com/D17451 --- .../PhabricatorManiphestConfigOptions.php | 7 ++ .../ManiphestTaskDetailController.php | 6 ++ .../maniphest/storage/ManiphestTask.php | 5 ++ .../storage/ManiphestTransaction.php | 10 +++ .../ManiphestTaskSubtypeDatasource.php | 1 + .../maniphest/view/ManiphestTaskListView.php | 10 +++ .../xaction/ManiphestTaskTransactionType.php | 10 --- .../project/view/ProjectBoardTaskCard.php | 7 ++ .../PhabricatorEditEngineSubtype.php | 70 ++++++++++++++++++- 9 files changed, 113 insertions(+), 13 deletions(-) diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php index 4a1927c5a8..9d927ffca1 100644 --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -335,9 +335,16 @@ dictionary with these keys: "task", "feature", or "bug". - `name` //Required string.// Human-readable name for this subtype, like "Task", "Feature Request" or "Bug Report". + - `tag` //Optional string.// Tag text for this subtype. + - `color` //Optional string.// Display color for this subtype. + - `icon` //Optional string.// Icon for the subtype. Each subtype must have a unique key, and you must define a subtype with the key "%s", which is used as a default subtype. + +The tag text (`tag`) is used to set the text shown in the subtype tag on list +views and workboards. If you do not configure it, the default subtype will have +no subtype tag and other subtypes will use their name as tag text. EOTEXT , $subtype_default_key)); diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 7859599a2f..92fe703f91 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -240,6 +240,12 @@ final class ManiphestTaskDetailController extends ManiphestController { } } + $subtype = $task->newSubtypeObject(); + if ($subtype && $subtype->hasTagView()) { + $subtype_tag = $subtype->newTagView(); + $view->addTag($subtype_tag); + } + return $view; } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 16937da2f2..7cf9d3353f 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -540,6 +540,11 @@ final class ManiphestTask extends ManiphestDAO ); } + public function newSubtypeObject() { + $subtype_key = $this->getEditEngineSubtype(); + $subtype_map = $this->newEditEngineSubtypeMap(); + return idx($subtype_map, $subtype_key); + } /* -( PhabricatorFulltextInterface )--------------------------------------- */ diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php index 0d27ddc5da..e2739c1d09 100644 --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -211,4 +211,14 @@ final class ManiphestTransaction return parent::getNoEffectDescription(); } + public function renderSubtypeName($value) { + $object = $this->getObject(); + $map = $object->newEditEngineSubtypeMap(); + if (!isset($map[$value])) { + return $value; + } + + return $map[$value]->getName(); + } + } diff --git a/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php index 2678e946b4..c061c694e4 100644 --- a/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php +++ b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php @@ -32,6 +32,7 @@ final class ManiphestTaskSubtypeDatasource $result = id(new PhabricatorTypeaheadResult()) ->setIcon($subtype->getIcon()) + ->setColor($subtype->getColor()) ->setPHID($key) ->setName($subtype->getName()); diff --git a/src/applications/maniphest/view/ManiphestTaskListView.php b/src/applications/maniphest/view/ManiphestTaskListView.php index 6f714d0c5c..de6b386ac8 100644 --- a/src/applications/maniphest/view/ManiphestTaskListView.php +++ b/src/applications/maniphest/view/ManiphestTaskListView.php @@ -56,6 +56,9 @@ final class ManiphestTaskListView extends ManiphestView { Javelin::initBehavior('maniphest-list-editor'); } + $subtype_map = id(new ManiphestTask()) + ->newEditEngineSubtypeMap(); + foreach ($this->tasks as $task) { $item = id(new PHUIObjectItemView()) ->setUser($this->getUser()) @@ -94,6 +97,13 @@ final class ManiphestTaskListView extends ManiphestView { $item->addSigil('maniphest-task'); } + $subtype = $task->newSubtypeObject(); + if ($subtype && $subtype->hasTagView()) { + $subtype_tag = $subtype->newTagView() + ->setSlimShady(true); + $item->addAttribute($subtype_tag); + } + $project_handles = array_select_keys( $handles, array_reverse($task->getProjectPHIDs())); diff --git a/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php b/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php index 699ef11631..c59de163c6 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php +++ b/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php @@ -3,14 +3,4 @@ abstract class ManiphestTaskTransactionType extends PhabricatorModularTransactionType { - public function renderSubtypeName($value) { - $object = $this->getObject(); - $map = $object->newEditEngineSubtypeMap(); - if (!isset($map[$value])) { - return $value; - } - - return $map[$value]->getName(); - } - } diff --git a/src/applications/project/view/ProjectBoardTaskCard.php b/src/applications/project/view/ProjectBoardTaskCard.php index 100fee20b3..1a6807ec45 100644 --- a/src/applications/project/view/ProjectBoardTaskCard.php +++ b/src/applications/project/view/ProjectBoardTaskCard.php @@ -108,6 +108,13 @@ final class ProjectBoardTaskCard extends Phobject { } } + $subtype = $task->newSubtypeObject(); + if ($subtype && $subtype->hasTagView()) { + $subtype_tag = $subtype->newTagView() + ->setSlimShady(true); + $card->addAttribute($subtype_tag); + } + if ($task->isClosed()) { $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus()); $icon = id(new PHUIIconView()) diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php index ff14ae239b..df367955af 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -8,6 +8,9 @@ final class PhabricatorEditEngineSubtype private $key; private $name; + private $icon; + private $tagText; + private $color; public function setKey($key) { $this->key = $key; @@ -27,8 +30,48 @@ final class PhabricatorEditEngineSubtype return $this->name; } + public function setIcon($icon) { + $this->icon = $icon; + return $this; + } + public function getIcon() { - return 'fa-drivers-license-o'; + return $this->icon; + } + + public function setTagText($text) { + $this->tagText = $text; + return $this; + } + + public function getTagText() { + return $this->tagText; + } + + public function setColor($color) { + $this->color = $color; + return $this; + } + + public function getColor() { + return $this->color; + } + + public function hasTagView() { + return (bool)strlen($this->getTagText()); + } + + public function newTagView() { + $view = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_OUTLINE) + ->setName($this->getTagText()); + + $color = $this->getColor(); + if ($color) { + $view->setColor($color); + } + + return $view; } public static function validateSubtypeKey($subtype) { @@ -72,6 +115,9 @@ final class PhabricatorEditEngineSubtype array( 'key' => 'string', 'name' => 'string', + 'tag' => 'optional string', + 'color' => 'optional string', + 'icon' => 'optional string', )); $key = $value['key']; @@ -113,9 +159,27 @@ final class PhabricatorEditEngineSubtype $key = $entry['key']; $name = $entry['name']; - $map[$key] = id(new self()) + $tag_text = idx($entry, 'tag'); + if ($tag_text === null) { + if ($key != self::SUBTYPE_DEFAULT) { + $tag_text = phutil_utf8_strtoupper($name); + } + } + + $color = idx($entry, 'color', 'blue'); + $icon = idx($entry, 'icon', 'fa-drivers-license-o'); + + $subtype = id(new self()) ->setKey($key) - ->setName($name); + ->setName($name) + ->setTagText($tag_text) + ->setIcon($icon); + + if ($color) { + $subtype->setColor($color); + } + + $map[$key] = $subtype; } return $map; From 04fd93e51e0368543773b72ed2dfef09d94080aa Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Fri, 26 May 2017 13:47:02 -0700 Subject: [PATCH 60/61] Drop DifferentialDraft storage Summary: Fixes T12104. Test Plan: Ran `bin/storage upgrade` and observed table dun got dropped. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Maniphest Tasks: T12104 Differential Revision: https://secure.phabricator.com/D18034 --- .../sql/autopatches/20141106.uniqdrafts.php | 29 +------------------ .../20170526.dropdifferentialdrafts.sql | 1 + src/__phutil_library_map__.php | 2 -- .../storage/DifferentialDraft.php | 23 --------------- 4 files changed, 2 insertions(+), 53 deletions(-) create mode 100644 resources/sql/autopatches/20170526.dropdifferentialdrafts.sql delete mode 100644 src/applications/differential/storage/DifferentialDraft.php diff --git a/resources/sql/autopatches/20141106.uniqdrafts.php b/resources/sql/autopatches/20141106.uniqdrafts.php index 31d6a53cb7..85b05f9ced 100644 --- a/resources/sql/autopatches/20141106.uniqdrafts.php +++ b/resources/sql/autopatches/20141106.uniqdrafts.php @@ -1,30 +1,3 @@ establishConnection('w'); - -$duplicates = queryfx_all( - $conn_w, - 'SELECT DISTINCT u.id id FROM %T u - JOIN %T v - ON u.objectPHID = v.objectPHID - AND u.authorPHID = v.authorPHID - AND u.draftKey = v.draftKey - AND u.id < v.id', - $table->getTableName(), - $table->getTableName()); - -$duplicates = ipull($duplicates, 'id'); -foreach (PhabricatorLiskDAO::chunkSQL($duplicates) as $chunk) { - queryfx( - $conn_w, - 'DELETE FROM %T WHERE id IN (%Q)', - $table->getTableName(), - $chunk); -} +// This table has been removed; see T12104 for details. diff --git a/resources/sql/autopatches/20170526.dropdifferentialdrafts.sql b/resources/sql/autopatches/20170526.dropdifferentialdrafts.sql new file mode 100644 index 0000000000..057bcb0d90 --- /dev/null +++ b/resources/sql/autopatches/20170526.dropdifferentialdrafts.sql @@ -0,0 +1 @@ +DROP TABLE {$NAMESPACE}_differential.differential_draft; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9605ebfc14..1b742b5730 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -441,7 +441,6 @@ phutil_register_library_map(array( 'DifferentialDiffTransactionQuery' => 'applications/differential/query/DifferentialDiffTransactionQuery.php', 'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php', - 'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php', 'DifferentialExactUserFunctionDatasource' => 'applications/differential/typeahead/DifferentialExactUserFunctionDatasource.php', 'DifferentialFieldParseException' => 'applications/differential/exception/DifferentialFieldParseException.php', 'DifferentialFieldValidationException' => 'applications/differential/exception/DifferentialFieldValidationException.php', @@ -5391,7 +5390,6 @@ phutil_register_library_map(array( 'DifferentialDiffTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', - 'DifferentialDraft' => 'DifferentialDAO', 'DifferentialExactUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialFieldParseException' => 'Exception', 'DifferentialFieldValidationException' => 'Exception', diff --git a/src/applications/differential/storage/DifferentialDraft.php b/src/applications/differential/storage/DifferentialDraft.php deleted file mode 100644 index 7dbe2f68bd..0000000000 --- a/src/applications/differential/storage/DifferentialDraft.php +++ /dev/null @@ -1,23 +0,0 @@ - array( - 'draftKey' => 'text64', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_unique' => array( - 'columns' => array('objectPHID', 'authorPHID', 'draftKey'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - -} From 9d37ad3022bfff8a2900b9d728e6abbb6a1e27f0 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Fri, 26 May 2017 15:39:18 -0700 Subject: [PATCH 61/61] Add maniphest.priority.search method Summary: Start on plan outlined in T12124. Adds a new Conduit method for querying information about task priorities. Test Plan: Ran locally; observed expected output: {F4979109} Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D18035 --- src/__phutil_library_map__.php | 2 + ...aniphestPrioritySearchConduitAPIMethod.php | 44 +++++++++++++++++++ .../constants/ManiphestTaskPriority.php | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1b742b5730..ce3cc27784 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1494,6 +1494,7 @@ phutil_register_library_map(array( 'ManiphestPointsConfigOptionType' => 'applications/maniphest/config/ManiphestPointsConfigOptionType.php', 'ManiphestPriorityConfigOptionType' => 'applications/maniphest/config/ManiphestPriorityConfigOptionType.php', 'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php', + 'ManiphestPrioritySearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php', 'ManiphestProjectNameFulltextEngineExtension' => 'applications/maniphest/engineextension/ManiphestProjectNameFulltextEngineExtension.php', 'ManiphestQueryConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php', 'ManiphestQueryStatusesConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php', @@ -6593,6 +6594,7 @@ phutil_register_library_map(array( 'ManiphestPointsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestPriorityConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand', + 'ManiphestPrioritySearchConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestProjectNameFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'ManiphestQueryConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestQueryStatusesConduitAPIMethod' => 'ManiphestConduitAPIMethod', diff --git a/src/applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php new file mode 100644 index 0000000000..eab06fb780 --- /dev/null +++ b/src/applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php @@ -0,0 +1,44 @@ +'; + } + + public function getRequiredScope() { + return self::SCOPE_ALWAYS; + } + + protected function execute(ConduitAPIRequest $request) { + $config = ManiphestTaskPriority::getConfig(); + + $results = array(); + foreach ($config as $code => $priority) { + $priority['value'] = $code; + $results[] = $priority; + } + + return array('data' => $results); + } + +} diff --git a/src/applications/maniphest/constants/ManiphestTaskPriority.php b/src/applications/maniphest/constants/ManiphestTaskPriority.php index 16a35a9e83..dd2ab69c69 100644 --- a/src/applications/maniphest/constants/ManiphestTaskPriority.php +++ b/src/applications/maniphest/constants/ManiphestTaskPriority.php @@ -110,7 +110,7 @@ final class ManiphestTaskPriority extends ManiphestConstants { return idx($config, 'disabled', false); } - private static function getConfig() { + public static function getConfig() { $config = PhabricatorEnv::getEnvConfig('maniphest.priorities'); krsort($config); return $config;