diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 2716e0d4c5..e83581e17c 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -204,6 +204,8 @@ phutil_register_library_map(array(
'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/commits',
'DifferentialController' => 'applications/differential/controller/base',
'DifferentialDAO' => 'applications/differential/storage/base',
+ 'DifferentialDateCreatedFieldSpecification' => 'applications/differential/field/specification/datecreated',
+ 'DifferentialDateModifiedFieldSpecification' => 'applications/differential/field/specification/datemodified',
'DifferentialDefaultFieldSelector' => 'applications/differential/field/selector/default',
'DifferentialDependenciesFieldSpecification' => 'applications/differential/field/specification/dependencies',
'DifferentialDiff' => 'applications/differential/storage/diff',
@@ -1033,6 +1035,8 @@ phutil_register_library_map(array(
'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialController' => 'PhabricatorController',
'DifferentialDAO' => 'PhabricatorLiskDAO',
+ 'DifferentialDateCreatedFieldSpecification' => 'DifferentialFieldSpecification',
+ 'DifferentialDateModifiedFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialDefaultFieldSelector' => 'DifferentialFieldSelector',
'DifferentialDependenciesFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialDiff' => 'DifferentialDAO',
diff --git a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
index c00e2d1a67..57dbfba859 100644
--- a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
+++ b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php
@@ -366,6 +366,10 @@ class DifferentialRevisionListController extends DifferentialController {
private function buildViews($filter, $user_phid, array $revisions) {
$user = $this->getRequest()->getUser();
+ $template = id(new DifferentialRevisionListView())
+ ->setUser($user)
+ ->setFields(DifferentialRevisionListView::getDefaultFields());
+
$views = array();
switch ($filter) {
case 'active':
@@ -373,18 +377,16 @@ class DifferentialRevisionListController extends DifferentialController {
$revisions,
$user_phid);
- $view = id(new DifferentialRevisionListView())
+ $view = id(clone $template)
->setRevisions($active)
- ->setUser($user)
->setNoDataString("You have no active revisions requiring action.");
$views[] = array(
'title' => 'Action Required',
'view' => $view,
);
- $view = id(new DifferentialRevisionListView())
+ $view = id(clone $template)
->setRevisions($waiting)
- ->setUser($user)
->setNoDataString("You have no active revisions waiting on others.");
$views[] = array(
'title' => 'Waiting On Others',
@@ -401,9 +403,8 @@ class DifferentialRevisionListController extends DifferentialController {
'subscribed' => 'Revisions by Subscriber',
'all' => 'Revisions',
);
- $view = id(new DifferentialRevisionListView())
- ->setRevisions($revisions)
- ->setUser($user);
+ $view = id(clone $template)
+ ->setRevisions($revisions);
$views[] = array(
'title' => idx($titles, $filter),
'view' => $view,
@@ -412,6 +413,7 @@ class DifferentialRevisionListController extends DifferentialController {
default:
throw new Exception("Unknown filter '{$filter}'!");
}
+
return $views;
}
diff --git a/src/applications/differential/field/selector/base/DifferentialFieldSelector.php b/src/applications/differential/field/selector/base/DifferentialFieldSelector.php
index 9ae8cfa0ca..7b58e92414 100644
--- a/src/applications/differential/field/selector/base/DifferentialFieldSelector.php
+++ b/src/applications/differential/field/selector/base/DifferentialFieldSelector.php
@@ -1,7 +1,7 @@
getAuthorPHID();
}
+ public function shouldAppearOnRevisionList() {
+ return true;
+ }
+
+ public function renderHeaderForRevisionList() {
+ return 'Author';
+ }
+
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ return $this->getHandle($revision->getAuthorPHID())->renderLink();
+ }
+
+ public function getRequiredHandlePHIDsForRevisionList(
+ DifferentialRevision $revision) {
+ return array($revision->getAuthorPHID());
+ }
+
}
diff --git a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
index 6e26e58244..30a912b45b 100644
--- a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
+++ b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
@@ -27,6 +27,7 @@
* @task storage Field Storage
* @task edit Extending the Revision Edit Interface
* @task view Extending the Revision View Interface
+ * @task list Extending the Revision List Interface
* @task conduit Extending the Conduit View Interface
* @task commit Extending Commit Messages
* @task load Loading Additional Data
@@ -264,6 +265,59 @@ abstract class DifferentialFieldSpecification {
}
+/* -( Extending the Revision List Interface )------------------------------ */
+
+
+ /**
+ * Determine if this field should appear in the table on the revision list
+ * interface.
+ *
+ * @return bool True if this field should appear in the table.
+ *
+ * @task list
+ */
+ public function shouldAppearOnRevisionList() {
+ return false;
+ }
+
+
+ /**
+ * Return a column header for revision list tables.
+ *
+ * @return string Column header.
+ *
+ * @task list
+ */
+ public function renderHeaderForRevisionList() {
+ throw new DifferentialFieldSpecificationIncompleteException($this);
+ }
+
+
+ /**
+ * Optionally, return a column class for revision list tables.
+ *
+ * @return string CSS class for table cells.
+ *
+ * @task list
+ */
+ public function getColumnClassForRevisionList() {
+ return null;
+ }
+
+
+ /**
+ * Return a table cell value for revision list tables.
+ *
+ * @param DifferentialRevision The revision to render a value for.
+ * @return string Table cell value.
+ *
+ * @task list
+ */
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ throw new DifferentialFieldSpecificationIncompleteException($this);
+ }
+
+
/* -( Extending the Conduit Interface )------------------------------------ */
@@ -483,6 +537,7 @@ abstract class DifferentialFieldSpecification {
return array();
}
+
/**
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
* field to render correctly on the view interface.
@@ -498,6 +553,25 @@ abstract class DifferentialFieldSpecification {
return $this->getRequiredHandlePHIDs();
}
+
+ /**
+ * Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
+ * field to render correctly on the list interface.
+ *
+ * This is a more specific version of @{method:getRequiredHandlePHIDs} which
+ * can be overridden to improve field performance by loading only data you
+ * need.
+ *
+ * @param DifferentialRevision The revision to pull PHIDs for.
+ * @return list List of PHIDs to load handles for.
+ * @task load
+ */
+ public function getRequiredHandlePHIDsForRevisionList(
+ DifferentialRevision $revision) {
+ return array();
+ }
+
+
/**
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
* field to render correctly on the edit interface.
diff --git a/src/applications/differential/field/specification/datecreated/DifferentialDateCreatedFieldSpecification.php b/src/applications/differential/field/specification/datecreated/DifferentialDateCreatedFieldSpecification.php
new file mode 100644
index 0000000000..b0b21a5bf5
--- /dev/null
+++ b/src/applications/differential/field/specification/datecreated/DifferentialDateCreatedFieldSpecification.php
@@ -0,0 +1,38 @@
+getDateCreated(), $this->getUser());
+ }
+
+}
diff --git a/src/applications/differential/field/specification/datecreated/__init__.php b/src/applications/differential/field/specification/datecreated/__init__.php
new file mode 100644
index 0000000000..79276ec487
--- /dev/null
+++ b/src/applications/differential/field/specification/datecreated/__init__.php
@@ -0,0 +1,13 @@
+getDateModified(), $this->getUser());
+ }
+
+}
diff --git a/src/applications/differential/field/specification/datemodified/__init__.php b/src/applications/differential/field/specification/datemodified/__init__.php
new file mode 100644
index 0000000000..8cfaee8f62
--- /dev/null
+++ b/src/applications/differential/field/specification/datemodified/__init__.php
@@ -0,0 +1,13 @@
+getLineCount()));
}
+ public function shouldAppearOnRevisionList() {
+ return true;
+ }
+
+ public function renderHeaderForRevisionList() {
+ return 'Lines';
+ }
+
+ public function getColumnClassForRevisionList() {
+ return 'n';
+ }
+
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ return number_format($revision->getLineCount());
+ }
+
}
diff --git a/src/applications/differential/field/specification/reviewers/DifferentialReviewersFieldSpecification.php b/src/applications/differential/field/specification/reviewers/DifferentialReviewersFieldSpecification.php
index a40f961e72..1065edef14 100644
--- a/src/applications/differential/field/specification/reviewers/DifferentialReviewersFieldSpecification.php
+++ b/src/applications/differential/field/specification/reviewers/DifferentialReviewersFieldSpecification.php
@@ -1,7 +1,7 @@
parseCommitMessageUserList($value);
}
+ public function shouldAppearOnRevisionList() {
+ return true;
+ }
+
+ public function renderHeaderForRevisionList() {
+ return 'Reviewers';
+ }
+
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ $reviewer_phids = $revision->getReviewers();
+ if ($reviewer_phids) {
+ $first = reset($reviewer_phids);
+ if (count($reviewer_phids) > 1) {
+ $suffix = ' (+'.(count($reviewer_phids) - 1).')';
+ } else {
+ $suffix = null;
+ }
+ return $this->getHandle($first)->renderLink().$suffix;
+ } else {
+ return 'None';
+ }
+ }
+
+ public function getRequiredHandlePHIDsForRevisionList(
+ DifferentialRevision $revision) {
+ $reviewer_phids = $revision->getReviewers();
+ if ($reviewer_phids) {
+ return array(reset($reviewer_phids));
+ }
+ return array();
+ }
+
}
diff --git a/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php b/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
index 769fe79334..9d451b1252 100644
--- a/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
+++ b/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
@@ -92,4 +92,16 @@ final class DifferentialRevisionIDFieldSpecification
return null;
}
+ public function shouldAppearOnRevisionList() {
+ return true;
+ }
+
+ public function renderHeaderForRevisionList() {
+ return 'ID';
+ }
+
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ return 'D'.$revision->getID();
+ }
+
}
diff --git a/src/applications/differential/field/specification/revisionstatus/DifferentialRevisionStatusFieldSpecification.php b/src/applications/differential/field/specification/revisionstatus/DifferentialRevisionStatusFieldSpecification.php
index a64320d04d..4fb35648ea 100644
--- a/src/applications/differential/field/specification/revisionstatus/DifferentialRevisionStatusFieldSpecification.php
+++ b/src/applications/differential/field/specification/revisionstatus/DifferentialRevisionStatusFieldSpecification.php
@@ -54,4 +54,17 @@ final class DifferentialRevisionStatusFieldSpecification
return ''.$status.''.$next_step;
}
+ public function shouldAppearOnRevisionList() {
+ return true;
+ }
+
+ public function renderHeaderForRevisionList() {
+ return 'Status';
+ }
+
+ public function renderValueForRevisionList(DifferentialRevision $revision) {
+ return ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
+ $revision->getStatus());
+ }
+
}
diff --git a/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php b/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
index 9a55539144..81883a45c5 100644
--- a/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
+++ b/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
@@ -1,7 +1,7 @@
'/D'.$revision->getID(),
+ ),
+ phutil_escape_html($revision->getTitle()));
+ }
+
}
diff --git a/src/applications/differential/field/specification/title/__init__.php b/src/applications/differential/field/specification/title/__init__.php
index ddc512831d..7f0db8769f 100644
--- a/src/applications/differential/field/specification/title/__init__.php
+++ b/src/applications/differential/field/specification/title/__init__.php
@@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/differential/field/exception/
phutil_require_module('phabricator', 'applications/differential/field/specification/base');
phutil_require_module('phabricator', 'view/form/control/textarea');
+phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/differential/view/revisionlist/DifferentialRevisionListView.php b/src/applications/differential/view/revisionlist/DifferentialRevisionListView.php
index 472a0de152..5389a6b90f 100644
--- a/src/applications/differential/view/revisionlist/DifferentialRevisionListView.php
+++ b/src/applications/differential/view/revisionlist/DifferentialRevisionListView.php
@@ -25,6 +25,12 @@ final class DifferentialRevisionListView extends AphrontView {
private $handles;
private $user;
private $noDataString;
+ private $fields;
+
+ public function setFields(array $fields) {
+ $this->fields = $fields;
+ return $this;
+ }
public function setRevisions(array $revisions) {
$this->revisions = $revisions;
@@ -33,14 +39,12 @@ final class DifferentialRevisionListView extends AphrontView {
public function getRequiredHandlePHIDs() {
$phids = array();
- foreach ($this->revisions as $revision) {
- $phids[] = $revision->getAuthorPHID();
- $reviewers = $revision->getReviewers();
- if ($reviewers) {
- $phids[] = head($reviewers);
+ foreach ($this->fields as $field) {
+ foreach ($this->revisions as $revision) {
+ $phids[] = $field->getRequiredHandlePHIDsForRevisionList($revision);
}
}
- return $phids;
+ return array_mergev($phids);
}
public function setHandles(array $handles) {
@@ -65,67 +69,30 @@ final class DifferentialRevisionListView extends AphrontView {
throw new Exception("Call setUser() before render()!");
}
+ foreach ($this->fields as $field) {
+ $field->setUser($this->user);
+ $field->setHandles($this->handles);
+ }
+
$rows = array();
foreach ($this->revisions as $revision) {
- $status = $revision->getStatus();
- $status =
- ArcanistDifferentialRevisionStatus::getNameForRevisionStatus($status);
-
- $reviewer_phids = $revision->getReviewers();
- if ($reviewer_phids) {
- $first = reset($reviewer_phids);
- if (count($reviewer_phids) > 1) {
- $suffix = ' (+'.(count($reviewer_phids) - 1).')';
- } else {
- $suffix = null;
- }
- $reviewers = $this->handles[$first]->renderLink().$suffix;
- } else {
- $reviewers = 'None';
+ $row = array();
+ foreach ($this->fields as $field) {
+ $row[] = $field->renderValueForRevisionList($revision);
}
+ $rows[] = $row;
+ }
- $link = phutil_render_tag(
- 'a',
- array(
- 'href' => '/D'.$revision->getID(),
- ),
- phutil_escape_html($revision->getTitle()));
-
- $rows[] = array(
- 'D'.$revision->getID(),
- $link,
- phutil_escape_html($status),
- number_format($revision->getLineCount()),
- $this->handles[$revision->getAuthorPHID()]->renderLink(),
- $reviewers,
- phabricator_datetime($revision->getDateModified(), $user),
- phabricator_date($revision->getDateCreated(), $user),
- );
+ $headers = array();
+ $classes = array();
+ foreach ($this->fields as $field) {
+ $headers[] = $field->renderHeaderForRevisionList();
+ $classes[] = $field->getColumnClassForRevisionList();
}
$table = new AphrontTableView($rows);
- $table->setHeaders(
- array(
- 'ID',
- 'Revision',
- 'Status',
- 'Lines',
- 'Author',
- 'Reviewers',
- 'Modified',
- 'Created',
- ));
- $table->setColumnClasses(
- array(
- null,
- 'wide pri',
- null,
- 'n',
- null,
- null,
- 'right',
- 'right',
- ));
+ $table->setHeaders($headers);
+ $table->setColumnClasses($classes);
if ($this->noDataString) {
$table->setNoDataString($this->noDataString);
@@ -134,4 +101,22 @@ final class DifferentialRevisionListView extends AphrontView {
return $table->render();
}
+ public static function getDefaultFields() {
+ $selector = DifferentialFieldSelector::newSelector();
+ $fields = $selector->getFieldSpecifications();
+ foreach ($fields as $key => $field) {
+ if (!$field->shouldAppearOnRevisionList()) {
+ unset($fields[$key]);
+ }
+ }
+
+ if (!$fields) {
+ throw new Exception(
+ "Phabricator configuration has no fields that appear on the list ".
+ "interface!");
+ }
+
+ return $selector->sortFieldsForRevisionList($fields);
+ }
+
}
diff --git a/src/applications/differential/view/revisionlist/__init__.php b/src/applications/differential/view/revisionlist/__init__.php
index 090036fc33..e941167b4d 100644
--- a/src/applications/differential/view/revisionlist/__init__.php
+++ b/src/applications/differential/view/revisionlist/__init__.php
@@ -6,13 +6,10 @@
-phutil_require_module('arcanist', 'differential/constants/revisionstatus');
-
+phutil_require_module('phabricator', 'applications/differential/field/selector/base');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phabricator', 'view/control/table');
-phutil_require_module('phabricator', 'view/utils');
-phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
diff --git a/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php b/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php
index 2c9a7096dc..819f2f7f2d 100644
--- a/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php
+++ b/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php
@@ -292,8 +292,11 @@ class PhabricatorDirectoryMainController
"View Active Revisions \xC2\xBB"));
if ($active) {
+ $fields =
+
$revision_view = id(new DifferentialRevisionListView())
->setRevisions($active)
+ ->setFields(DifferentialRevisionListView::getDefaultFields())
->setUser($user);
$phids = array_merge(
array($user_phid),