Add a standalone view for browsing changesets of very large revisions
Summary: Ref T13110. Installs have various reasons for sending unreviewable changes (changes where the text of the change will never be reviewed by a human) through Differential anyway. Prepare for accommodating this more gracefully by building a standalone changeset list page which paginates the changesets. Test Plan: Clicked the new "Changeset List" button on a revision, was taken to a separate page. Maniphest Tasks: T13110 Differential Revision: https://secure.phabricator.com/D19295
This commit is contained in:
		@@ -389,6 +389,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php',
 | 
			
		||||
    'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php',
 | 
			
		||||
    'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php',
 | 
			
		||||
    'DifferentialChangesetListController' => 'applications/differential/controller/DifferentialChangesetListController.php',
 | 
			
		||||
    'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php',
 | 
			
		||||
    'DifferentialChangesetOneUpMailRenderer' => 'applications/differential/render/DifferentialChangesetOneUpMailRenderer.php',
 | 
			
		||||
    'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php',
 | 
			
		||||
@@ -397,6 +398,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php',
 | 
			
		||||
    'DifferentialChangesetQuery' => 'applications/differential/query/DifferentialChangesetQuery.php',
 | 
			
		||||
    'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php',
 | 
			
		||||
    'DifferentialChangesetSearchEngine' => 'applications/differential/query/DifferentialChangesetSearchEngine.php',
 | 
			
		||||
    'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php',
 | 
			
		||||
    'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php',
 | 
			
		||||
    'DifferentialChangesetTwoUpTestRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpTestRenderer.php',
 | 
			
		||||
@@ -5605,6 +5607,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'DifferentialChangesetDetailView' => 'AphrontView',
 | 
			
		||||
    'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject',
 | 
			
		||||
    'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer',
 | 
			
		||||
    'DifferentialChangesetListController' => 'DifferentialController',
 | 
			
		||||
    'DifferentialChangesetListView' => 'AphrontView',
 | 
			
		||||
    'DifferentialChangesetOneUpMailRenderer' => 'DifferentialChangesetRenderer',
 | 
			
		||||
    'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer',
 | 
			
		||||
@@ -5613,6 +5616,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase',
 | 
			
		||||
    'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
 | 
			
		||||
    'DifferentialChangesetRenderer' => 'Phobject',
 | 
			
		||||
    'DifferentialChangesetSearchEngine' => 'PhabricatorApplicationSearchEngine',
 | 
			
		||||
    'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer',
 | 
			
		||||
    'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer',
 | 
			
		||||
    'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer',
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,13 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
 | 
			
		||||
        '(?:query/(?P<queryKey>[^/]+)/)?'
 | 
			
		||||
          => 'DifferentialRevisionListController',
 | 
			
		||||
        'diff/' => array(
 | 
			
		||||
          '(?P<id>[1-9]\d*)/' => 'DifferentialDiffViewController',
 | 
			
		||||
          '(?P<id>[1-9]\d*)/' => array(
 | 
			
		||||
            '' => 'DifferentialDiffViewController',
 | 
			
		||||
            'changesets/' => array(
 | 
			
		||||
              $this->getQueryRoutePattern()
 | 
			
		||||
                => 'DifferentialChangesetListController',
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          'create/' => 'DifferentialDiffCreateController',
 | 
			
		||||
        ),
 | 
			
		||||
        'changeset/' => 'DifferentialChangesetViewController',
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class DifferentialChangesetListController
 | 
			
		||||
  extends DifferentialController {
 | 
			
		||||
 | 
			
		||||
  private $diff;
 | 
			
		||||
 | 
			
		||||
  public function shouldAllowPublic() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function handleRequest(AphrontRequest $request) {
 | 
			
		||||
    $viewer = $this->getViewer();
 | 
			
		||||
 | 
			
		||||
    $diff = id(new DifferentialDiffQuery())
 | 
			
		||||
      ->setViewer($viewer)
 | 
			
		||||
      ->withIDs(array($request->getURIData('id')))
 | 
			
		||||
      ->executeOne();
 | 
			
		||||
    if (!$diff) {
 | 
			
		||||
      return new Aphront404Response();
 | 
			
		||||
    }
 | 
			
		||||
    $this->diff = $diff;
 | 
			
		||||
 | 
			
		||||
    return id(new DifferentialChangesetSearchEngine())
 | 
			
		||||
      ->setController($this)
 | 
			
		||||
      ->setDiff($diff)
 | 
			
		||||
      ->buildResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function buildApplicationCrumbs() {
 | 
			
		||||
    $crumbs = parent::buildApplicationCrumbs();
 | 
			
		||||
 | 
			
		||||
    $diff = $this->diff;
 | 
			
		||||
    if ($diff) {
 | 
			
		||||
      $revision = $diff->getRevision();
 | 
			
		||||
      if ($revision) {
 | 
			
		||||
        $crumbs->addTextCrumb(
 | 
			
		||||
          $revision->getMonogram(),
 | 
			
		||||
          $revision->getURI());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $crumbs->addTextCrumb(
 | 
			
		||||
        pht('Diff %d', $diff->getID()),
 | 
			
		||||
        $diff->getURI());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $crumbs;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -399,8 +399,18 @@ final class DifferentialRevisionViewController extends DifferentialController {
 | 
			
		||||
          ->appendChild($other_view));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $view_button = id(new PHUIButtonView())
 | 
			
		||||
      ->setTag('a')
 | 
			
		||||
      ->setText(pht('Changeset List'))
 | 
			
		||||
      ->setHref('/differential/diff/'.$target->getID().'/changesets/')
 | 
			
		||||
      ->setIcon('fa-align-left');
 | 
			
		||||
 | 
			
		||||
    $tab_header = id(new PHUIHeaderView())
 | 
			
		||||
      ->setHeader(pht('Revision Contents'))
 | 
			
		||||
      ->addActionLink($view_button);
 | 
			
		||||
 | 
			
		||||
    $tab_view = id(new PHUIObjectBoxView())
 | 
			
		||||
      ->setHeaderText(pht('Revision Contents'))
 | 
			
		||||
      ->setHeader($tab_header)
 | 
			
		||||
      ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
 | 
			
		||||
      ->addTabGroup($tab_group);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,19 +41,12 @@ final class DifferentialChangesetQuery
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function newResultObject() {
 | 
			
		||||
    return new DifferentialChangeset();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function loadPage() {
 | 
			
		||||
    $table = new DifferentialChangeset();
 | 
			
		||||
    $conn_r = $table->establishConnection('r');
 | 
			
		||||
 | 
			
		||||
    $data = queryfx_all(
 | 
			
		||||
      $conn_r,
 | 
			
		||||
      'SELECT * FROM %T %Q %Q %Q',
 | 
			
		||||
      $table->getTableName(),
 | 
			
		||||
      $this->buildWhereClause($conn_r),
 | 
			
		||||
      $this->buildOrderClause($conn_r),
 | 
			
		||||
      $this->buildLimitClause($conn_r));
 | 
			
		||||
 | 
			
		||||
    return $table->loadAllFromArray($data);
 | 
			
		||||
    return $this->loadStandardPage($this->newResultObject());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function willFilterPage(array $changesets) {
 | 
			
		||||
@@ -124,26 +117,24 @@ final class DifferentialChangesetQuery
 | 
			
		||||
    return $changesets;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
 | 
			
		||||
    $where = array();
 | 
			
		||||
  protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
 | 
			
		||||
    $where = parent::buildWhereClauseParts($conn);
 | 
			
		||||
 | 
			
		||||
    if ($this->diffs !== null) {
 | 
			
		||||
      $where[] = qsprintf(
 | 
			
		||||
        $conn_r,
 | 
			
		||||
        $conn,
 | 
			
		||||
        'diffID IN (%Ld)',
 | 
			
		||||
        mpull($this->diffs, 'getID'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($this->ids !== null) {
 | 
			
		||||
      $where[] = qsprintf(
 | 
			
		||||
        $conn_r,
 | 
			
		||||
        $conn,
 | 
			
		||||
        'id IN (%Ld)',
 | 
			
		||||
        $this->ids);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $where[] = $this->buildPagingClause($conn_r);
 | 
			
		||||
 | 
			
		||||
    return $this->formatWhereClause($where);
 | 
			
		||||
    return $where;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getQueryApplicationClass() {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,133 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class DifferentialChangesetSearchEngine
 | 
			
		||||
  extends PhabricatorApplicationSearchEngine {
 | 
			
		||||
 | 
			
		||||
  private $diff;
 | 
			
		||||
 | 
			
		||||
  public function setDiff(DifferentialDiff $diff) {
 | 
			
		||||
    $this->diff = $diff;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getDiff() {
 | 
			
		||||
    return $this->diff;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getResultTypeDescription() {
 | 
			
		||||
    return pht('Differential Changesets');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getApplicationClassName() {
 | 
			
		||||
    return 'PhabricatorDifferentialApplication';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function newQuery() {
 | 
			
		||||
    $query = id(new DifferentialChangesetQuery());
 | 
			
		||||
 | 
			
		||||
    if ($this->diff) {
 | 
			
		||||
      $query->withDiffs(array($this->diff));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function buildQueryFromParameters(array $map) {
 | 
			
		||||
    $query = $this->newQuery();
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function buildCustomSearchFields() {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getURI($path) {
 | 
			
		||||
    $diff = $this->getDiff();
 | 
			
		||||
    if ($diff) {
 | 
			
		||||
      return '/differential/diff/'.$diff->getID().'/changesets/'.$path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    throw new PhutilMethodNotImplementedException();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getBuiltinQueryNames() {
 | 
			
		||||
    $names = array();
 | 
			
		||||
    $names['all'] = pht('All Changesets');
 | 
			
		||||
    return $names;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function buildSavedQueryFromBuiltin($query_key) {
 | 
			
		||||
    $query = $this->newSavedQuery();
 | 
			
		||||
    $query->setQueryKey($query_key);
 | 
			
		||||
 | 
			
		||||
    $viewer = $this->requireViewer();
 | 
			
		||||
 | 
			
		||||
    switch ($query_key) {
 | 
			
		||||
      case 'all':
 | 
			
		||||
        return $query->setParameter('order', 'oldest');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return parent::buildSavedQueryFromBuiltin($query_key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function renderResultList(
 | 
			
		||||
    array $changesets,
 | 
			
		||||
    PhabricatorSavedQuery $query,
 | 
			
		||||
    array $handles) {
 | 
			
		||||
 | 
			
		||||
    assert_instances_of($changesets, 'DifferentialChangeset');
 | 
			
		||||
    $viewer = $this->requireViewer();
 | 
			
		||||
 | 
			
		||||
    $rows = array();
 | 
			
		||||
    foreach ($changesets as $changeset) {
 | 
			
		||||
      $link = phutil_tag(
 | 
			
		||||
        'a',
 | 
			
		||||
        array(
 | 
			
		||||
          'href' => '/differential/changeset/?ref='.$changeset->getID(),
 | 
			
		||||
        ),
 | 
			
		||||
        $changeset->getDisplayFilename());
 | 
			
		||||
 | 
			
		||||
      $type = $changeset->getChangeType();
 | 
			
		||||
 | 
			
		||||
      $title = DifferentialChangeType::getFullNameForChangeType($type);
 | 
			
		||||
 | 
			
		||||
      $add_lines = $changeset->getAddLines();
 | 
			
		||||
      if (!$add_lines) {
 | 
			
		||||
        $add_lines = null;
 | 
			
		||||
      } else {
 | 
			
		||||
        $add_lines = '+'.$add_lines;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $rem_lines = $changeset->getDelLines();
 | 
			
		||||
      if (!$rem_lines) {
 | 
			
		||||
        $rem_lines = null;
 | 
			
		||||
      } else {
 | 
			
		||||
        $rem_lines = '-'.$rem_lines;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $rows[] = array(
 | 
			
		||||
        $changeset->newFileTreeIcon(),
 | 
			
		||||
        $title,
 | 
			
		||||
        $link,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $table = id(new AphrontTableView($rows))
 | 
			
		||||
      ->setHeaders(
 | 
			
		||||
        array(
 | 
			
		||||
          null,
 | 
			
		||||
          pht('Change'),
 | 
			
		||||
          pht('Path'),
 | 
			
		||||
        ))
 | 
			
		||||
      ->setColumnClasses(
 | 
			
		||||
        array(
 | 
			
		||||
          null,
 | 
			
		||||
          null,
 | 
			
		||||
          'pri wide',
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    return id(new PhabricatorApplicationSearchResultView())
 | 
			
		||||
      ->setTable($table);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user