1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-30 02:32:42 +01:00

upgrade diffusion to use modern header UI and fix a few quirks

Summary:
upgrades are CrumbsView, HeaderView, PropertyListView, and ActionListView. I had to modify CrumbsView stuff a bit to handle the "advanced" diffusion crumbs.

Quirks fixed include making file tree view show up in diffusion, the page not have extra space when the file tree is hidden, links no longer breaking once you visit files (since without the change the files always got "/" appended and thus 404'd), and a differential quirk where it read "next step:" and that colon is a no no,

Test Plan: played around in diffusion and differential

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, chad

Maniphest Tasks: T2048, T2178

Differential Revision: https://secure.phabricator.com/D4169
This commit is contained in:
Bob Trahan 2012-12-12 17:50:42 -08:00
parent 239eca13d7
commit 9e8387175e
15 changed files with 381 additions and 285 deletions

View file

@ -224,6 +224,7 @@ phutil_register_library_map(array(
'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php', 'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php',
'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php', 'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php',
'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php', 'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php',
'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php',
'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php', 'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php',
'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php', 'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php',
'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php', 'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php',
@ -2570,12 +2571,13 @@ phutil_register_library_map(array(
1 => 'PhabricatorMarkupInterface', 1 => 'PhabricatorMarkupInterface',
2 => 'PonderVotableInterface', 2 => 'PonderVotableInterface',
3 => 'PhabricatorSubscribableInterface', 3 => 'PhabricatorSubscribableInterface',
4 => 'PhabricatorPolicyInterface',
), ),
'PonderQuestionAskController' => 'PonderController', 'PonderQuestionAskController' => 'PonderController',
'PonderQuestionDetailView' => 'AphrontView', 'PonderQuestionDetailView' => 'AphrontView',
'PonderQuestionEditor' => 'PhabricatorEditor', 'PonderQuestionEditor' => 'PhabricatorEditor',
'PonderQuestionPreviewController' => 'PonderController', 'PonderQuestionPreviewController' => 'PonderController',
'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyQuery', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PonderQuestionSummaryView' => 'AphrontView', 'PonderQuestionSummaryView' => 'AphrontView',
'PonderQuestionViewController' => 'PonderController', 'PonderQuestionViewController' => 'PonderController',
'PonderReplyHandler' => 'PhabricatorMailReplyHandler', 'PonderReplyHandler' => 'PhabricatorMailReplyHandler',

View file

@ -398,12 +398,17 @@ final class DifferentialRevisionViewController extends DifferentialController {
PhabricatorFeedStoryNotification::updateObjectNotificationViews( PhabricatorFeedStoryNotification::updateObjectNotificationViews(
$user, $revision->getPHID()); $user, $revision->getPHID());
$object_id = 'D'.$revision->getID();
$top_anchor = id(new PhabricatorAnchorView()) $top_anchor = id(new PhabricatorAnchorView())
->setAnchorName('top') ->setAnchorName('top')
->setNavigationMarker(true); ->setNavigationMarker(true);
$nav = $this->buildSideNavView($revision, $changesets); $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
$nav->selectFilter(''); ->setAnchorName('top')
->setTitle('D'.$revision->getID())
->setBaseURI(new PhutilURI('/D'.$revision->getID()))
->build($changesets);
$nav->appendChild( $nav->appendChild(
array( array(
$reviewer_warning, $reviewer_warning,
@ -412,7 +417,6 @@ final class DifferentialRevisionViewController extends DifferentialController {
$page_pane, $page_pane,
)); ));
$object_id = 'D'.$revision->getID();
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb( $crumbs->addCrumb(
@ -960,103 +964,4 @@ final class DifferentialRevisionViewController extends DifferentialController {
return id(new AphrontRedirectResponse())->setURI($file->getBestURI()); return id(new AphrontRedirectResponse())->setURI($file->getBestURI());
} }
private function buildSideNavView(
DifferentialRevision $revision,
array $changesets) {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/D'.$revision->getID()));
$nav->setFlexible(true);
$nav->addFilter('top', 'D'.$revision->getID(), '#top');
$tree = new PhutilFileTree();
foreach ($changesets as $changeset) {
try {
$tree->addPath($changeset->getFilename(), $changeset);
} catch (Exception $ex) {
// TODO: See T1702. When viewing the versus diff of diffs, we may
// have files with the same filename. For example, if you have a setup
// like this in SVN:
//
// a/
// README
// b/
// README
//
// ...and you run "arc diff" once from a/, and again from b/, you'll
// get two diffs with path README. However, in the versus diff view we
// will compute their absolute repository paths and detect that they
// aren't really the same file. This is correct, but causes us to
// throw when inserting them.
//
// We should probably compute the smallest unique path for each file
// and show these as "a/README" and "b/README" when diffed against
// one another. However, we get this wrong in a lot of places (the
// other TOC shows two "README" files, and we generate the same anchor
// hash for both) so I'm just stopping the bleeding until we can get
// a proper fix in place.
}
}
require_celerity_resource('phabricator-filetree-view-css');
$filetree = array();
$path = $tree;
while (($path = $path->getNextNode())) {
$data = $path->getData();
$name = $path->getName();
$style = 'padding-left: '.(2 + (3 * $path->getDepth())).'px';
$href = null;
if ($data) {
$href = '#'.$data->getAnchorName();
$title = $name;
$icon = 'phabricator-filetree-icon-file';
} else {
$name .= '/';
$title = $path->getFullPath().'/';
$icon = 'phabricator-filetree-icon-dir';
}
$icon = phutil_render_tag(
'span',
array(
'class' => 'phabricator-filetree-icon '.$icon,
),
'');
$name_element = phutil_render_tag(
'span',
array(
'class' => 'phabricator-filetree-name',
),
phutil_escape_html($name));
$filetree[] = javelin_render_tag(
$href ? 'a' : 'span',
array(
'href' => $href,
'style' => $style,
'title' => $title,
'class' => 'phabricator-filetree-item',
),
$icon.$name_element);
}
$tree->destroy();
$filetree =
'<div class="phabricator-filetree">'.
implode("\n", $filetree).
'</div>';
$nav->addFilter('toc', 'Table of Contents', '#toc');
$nav->addCustomBlock($filetree);
$nav->addFilter('comment', 'Add Comment', '#comment');
$nav->setActive(true);
return $nav;
}
} }

View file

@ -0,0 +1,134 @@
<?php
final class DifferentialChangesetFileTreeSideNavBuilder {
private $title;
private $baseURI;
private $anchorName;
public function setAnchorName($anchor_name) {
$this->anchorName = $anchor_name;
return $this;
}
public function getAnchorName() {
return $this->anchorName;
}
public function setBaseURI(PhutilURI $base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function getTitle() {
return $this->title;
}
public function build(array $changesets) {
assert_instances_of($changesets, 'DifferentialChangeset');
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI($this->getBaseURI());
$nav->setFlexible(true);
$anchor = $this->getAnchorName();
$nav->addFilter($anchor, $this->getTitle(), '#'.$anchor);
$tree = new PhutilFileTree();
foreach ($changesets as $changeset) {
try {
$tree->addPath($changeset->getFilename(), $changeset);
} catch (Exception $ex) {
// TODO: See T1702. When viewing the versus diff of diffs, we may
// have files with the same filename. For example, if you have a setup
// like this in SVN:
//
// a/
// README
// b/
// README
//
// ...and you run "arc diff" once from a/, and again from b/, you'll
// get two diffs with path README. However, in the versus diff view we
// will compute their absolute repository paths and detect that they
// aren't really the same file. This is correct, but causes us to
// throw when inserting them.
//
// We should probably compute the smallest unique path for each file
// and show these as "a/README" and "b/README" when diffed against
// one another. However, we get this wrong in a lot of places (the
// other TOC shows two "README" files, and we generate the same anchor
// hash for both) so I'm just stopping the bleeding until we can get
// a proper fix in place.
}
}
require_celerity_resource('phabricator-filetree-view-css');
$filetree = array();
$path = $tree;
while (($path = $path->getNextNode())) {
$data = $path->getData();
$name = $path->getName();
$style = 'padding-left: '.(2 + (3 * $path->getDepth())).'px';
$href = null;
if ($data) {
$href = '#'.$data->getAnchorName();
$title = $name;
$icon = 'phabricator-filetree-icon-file';
} else {
$name .= '/';
$title = $path->getFullPath().'/';
$icon = 'phabricator-filetree-icon-dir';
}
$icon = phutil_render_tag(
'span',
array(
'class' => 'phabricator-filetree-icon '.$icon,
),
'');
$name_element = phutil_render_tag(
'span',
array(
'class' => 'phabricator-filetree-name',
),
phutil_escape_html($name));
$filetree[] = javelin_render_tag(
$href ? 'a' : 'span',
array(
'href' => $href,
'style' => $style,
'title' => $title,
'class' => 'phabricator-filetree-item',
),
$icon.$name_element);
}
$tree->destroy();
$filetree =
'<div class="phabricator-filetree">'.
implode("\n", $filetree).
'</div>';
$nav->addFilter('toc', 'Table of Contents', '#toc');
$nav->addCustomBlock($filetree);
$nav->addFilter('comment', 'Add Comment', '#comment');
$nav->setActive(true);
$nav->selectFilter('');
return $nav;
}
}

View file

@ -83,7 +83,7 @@ final class DifferentialRevisionDetailView extends AphrontView {
} }
} }
if ($next_step) { if ($next_step) {
$properties->addProperty('Next Step:', $next_step); $properties->addProperty('Next Step', $next_step);
} }
foreach ($this->auxiliaryFields as $field) { foreach ($this->auxiliaryFields as $field) {

View file

@ -10,13 +10,6 @@ final class DiffusionBrowseController extends DiffusionController {
$content = array(); $content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
if ($drequest->getTagContent()) { if ($drequest->getTagContent()) {
$title = 'Tag: '.$drequest->getSymbolicCommit(); $title = 'Tag: '.$drequest->getSymbolicCommit();
@ -34,6 +27,7 @@ final class DiffusionBrowseController extends DiffusionController {
DiffusionBrowseQuery::REASON_IS_FILE) { DiffusionBrowseQuery::REASON_IS_FILE) {
$controller = new DiffusionBrowseFileController($this->getRequest()); $controller = new DiffusionBrowseFileController($this->getRequest());
$controller->setDiffusionRequest($drequest); $controller->setDiffusionRequest($drequest);
$controller->setCurrentApplication($this->getCurrentApplication());
return $this->delegateToController($controller); return $this->delegateToController($controller);
} }
@ -85,7 +79,15 @@ final class DiffusionBrowseController extends DiffusionController {
$nav = $this->buildSideNav('browse', false); $nav = $this->buildSideNav('browse', false);
$nav->appendChild($content); $nav->appendChild($content);
return $this->buildStandardPageResponse( $crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav, $nav,
array( array(
'title' => array( 'title' => array(

View file

@ -69,12 +69,6 @@ final class DiffusionBrowseFileController extends DiffusionController {
// Render the page. // Render the page.
$content = array(); $content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$follow = $request->getStr('follow'); $follow = $request->getStr('follow');
if ($follow) { if ($follow) {
@ -114,10 +108,17 @@ final class DiffusionBrowseFileController extends DiffusionController {
$nav = $this->buildSideNav('browse', true); $nav = $this->buildSideNav('browse', true);
$nav->appendChild($content); $nav->appendChild($content);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$nav->setCrumbs($crumbs);
$basename = basename($this->getDiffusionRequest()->getPath()); $basename = basename($this->getDiffusionRequest()->getPath());
return $this->buildStandardPageResponse( return $this->buildApplicationPage(
$nav, $nav,
array( array(
'title' => $basename, 'title' => $basename,

View file

@ -45,13 +45,6 @@ final class DiffusionChangeController extends DiffusionController {
DifferentialChangesetParser::WHITESPACE_SHOW_ALL); DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
$changeset_view->setUser($this->getRequest()->getUser()); $changeset_view->setUser($this->getRequest()->getUser());
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'change',
));
// TODO: This is pretty awkward, unify the CSS between Diffusion and // TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better. // Differential better.
require_celerity_resource('differential-core-view-css'); require_celerity_resource('differential-core-view-css');
@ -62,8 +55,15 @@ final class DiffusionChangeController extends DiffusionController {
$nav = $this->buildSideNav('change', true); $nav = $this->buildSideNav('change', true);
$nav->appendChild($content); $nav->appendChild($content);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'change',
));
$nav->setCrumbs($crumbs);
return $this->buildStandardPageResponse( return $this->buildApplicationPage(
$nav, $nav,
array( array(
'title' => 'Change', 'title' => 'Change',

View file

@ -26,10 +26,6 @@ final class DiffusionCommitController extends DiffusionController {
$callsign = $drequest->getRepository()->getCallsign(); $callsign = $drequest->getRepository()->getCallsign();
$content = array(); $content = array();
$content[] = $this->buildCrumbs(array(
'commit' => true,
));
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
$commit = $drequest->loadCommit(); $commit = $drequest->loadCommit();
@ -51,6 +47,10 @@ final class DiffusionCommitController extends DiffusionController {
$commit_data = $drequest->loadCommitData(); $commit_data = $drequest->loadCommitData();
$commit->attachCommitData($commit_data); $commit->attachCommitData($commit_data);
$top_anchor = id(new PhabricatorAnchorView())
->setAnchorName('top')
->setNavigationMarker(true);
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub'); $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
if ($is_foreign) { if ($is_foreign) {
$subpath = $commit_data->getCommitDetail('svn-subpath'); $subpath = $commit_data->getCommitDetail('svn-subpath');
@ -64,6 +64,7 @@ final class DiffusionCommitController extends DiffusionController {
"didn't affect the tracked subdirectory ('". "didn't affect the tracked subdirectory ('".
phutil_escape_html($subpath)."'), so no information is available."); phutil_escape_html($subpath)."'), so no information is available.");
$content[] = $error_panel; $content[] = $error_panel;
$content[] = $top_anchor;
} else { } else {
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
@ -73,22 +74,32 @@ final class DiffusionCommitController extends DiffusionController {
$parent_query = DiffusionCommitParentsQuery::newFromDiffusionRequest( $parent_query = DiffusionCommitParentsQuery::newFromDiffusionRequest(
$drequest); $drequest);
$headsup_panel = new AphrontHeadsupView(); $headsup_view = id(new PhabricatorHeaderView())
$headsup_panel->setHeader('Commit Detail'); ->setHeader('Commit Detail');
$headsup_panel->setActionList(
$this->renderHeadsupActionList($commit, $repository)); $headsup_actions = $this->renderHeadsupActionList($commit, $repository);
$headsup_panel->setProperties(
$this->getCommitProperties( $commit_properties = $this->loadCommitProperties(
$commit, $commit,
$commit_data, $commit_data,
$parent_query->loadParents())); $parent_query->loadParents()
);
$property_list = id(new PhabricatorPropertyListView())
->setHasKeyboardShortcuts(true);
foreach ($commit_properties as $key => $value) {
$property_list->addProperty($key, $value);
}
$headsup_panel->appendChild( $property_list->addTextContent(
'<div class="diffusion-commit-message phabricator-remarkup">'. '<div class="diffusion-commit-message phabricator-remarkup">'.
$engine->markupText($commit_data->getCommitMessage()). $engine->markupText($commit_data->getCommitMessage()).
'</div>'); '</div>'
);
$content[] = $headsup_panel; $content[] = $top_anchor;
$content[] = $headsup_view;
$content[] = $headsup_actions;
$content[] = $property_list;
} }
$query = new PhabricatorAuditQuery(); $query = new PhabricatorAuditQuery();
@ -289,19 +300,43 @@ final class DiffusionCommitController extends DiffusionController {
'id' => $pane_id 'id' => $pane_id
), ),
$change_list->render(). $change_list->render().
id(new PhabricatorAnchorView())
->setAnchorName('comment')
->setNavigationMarker(true)
->render().
$add_comment_view); $add_comment_view);
$content[] = $main_pane; $content[] = $main_pane;
} }
return $this->buildStandardPageResponse( $commit_id = 'r'.$callsign.$commit->getCommitIdentifier();
$content, $short_name = DiffusionView::nameCommit(
array( $repository,
'title' => 'r'.$callsign.$commit->getCommitIdentifier(), $commit->getCommitIdentifier()
)); );
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
->setAnchorName('top')
->setTitle($short_name)
->setBaseURI(new PhutilURI('/'.$commit_id))
->build($changesets);
foreach ($content as $child) {
$nav->appendChild($child);
} }
private function getCommitProperties( $crumbs = $this->buildCrumbs(array(
'commit' => true,
));
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav,
array(
'title' => $commit_id
)
);
}
private function loadCommitProperties(
PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data, PhabricatorRepositoryCommitData $data,
array $parents) { array $parents) {
@ -766,75 +801,54 @@ final class DiffusionCommitController extends DiffusionController {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $user = $request->getUser();
$actions = array(); $actions = id(new PhabricatorActionListView())
->setUser($user)
->setObject($commit);
// TODO -- integrate permissions into whether or not this action is shown // TODO -- integrate permissions into whether or not this action is shown
$uri = '/diffusion/'.$repository->getCallSign().'/commit/'. $uri = '/diffusion/'.$repository->getCallSign().'/commit/'.
$commit->getCommitIdentifier().'/edit/'; $commit->getCommitIdentifier().'/edit/';
$action = new AphrontHeadsupActionView();
$action->setClass('action-edit');
$action->setURI($uri);
$action->setName('Edit Commit');
$action->setWorkflow(false);
$actions[] = $action;
require_celerity_resource('phabricator-flag-css'); $action = id(new PhabricatorActionView())
$flag = PhabricatorFlagQuery::loadUserFlag($user, $commit->getPHID()); ->setName('Edit Commit')
if ($flag) { ->setHref($uri)
$class = PhabricatorFlagColor::getCSSClass($flag->getColor()); ->setIcon('edit');
$color = PhabricatorFlagColor::getColorName($flag->getColor()); $actions->addAction($action);
$action = new AphrontHeadsupActionView();
$action->setClass('flag-clear '.$class);
$action->setURI('/flag/delete/'.$flag->getID().'/');
$action->setName('Remove '.$color.' Flag');
$action->setWorkflow(true);
$actions[] = $action;
} else {
$action = new AphrontHeadsupActionView();
$action->setClass('phabricator-flag-ghost');
$action->setURI('/flag/edit/'.$commit->getPHID().'/');
$action->setName('Flag Commit');
$action->setWorkflow(true);
$actions[] = $action;
}
require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('phabricator-object-selector-css');
require_celerity_resource('javelin-behavior-phabricator-object-selector'); require_celerity_resource('javelin-behavior-phabricator-object-selector');
if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) { if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
$action = new AphrontHeadsupActionView(); $action = id(new PhabricatorActionView())
$action->setName('Edit Maniphest Tasks'); ->setName('Edit Maniphest Tasks')
$action->setURI('/search/attach/'.$commit->getPHID().'/TASK/edge/'); ->setIcon('attach')
$action->setWorkflow(true); ->setHref('/search/attach/'.$commit->getPHID().'/TASK/edge/')
$action->setClass('attach-maniphest'); ->setWorkflow(true);
$actions[] = $action; $actions->addAction($action);
} }
if ($user->getIsAdmin()) { if ($user->getIsAdmin()) {
$action = new AphrontHeadsupActionView(); $action = id(new PhabricatorActionView())
$action->setName('MetaMTA Transcripts'); ->setName('MetaMTA Transcripts')
$action->setURI('/mail/?phid='.$commit->getPHID()); ->setIcon('file')
$action->setClass('transcripts-metamta'); ->setHref('/mail/?phid='.$commit->getPHID());
$actions[] = $action; $actions->addAction($action);
} }
$action = new AphrontHeadsupActionView(); $action = id(new PhabricatorActionView())
$action->setName('Herald Transcripts'); ->setName('Herald Transcripts')
$action->setURI('/herald/transcript/?phid='.$commit->getPHID()); ->setIcon('file')
$action->setClass('transcripts-herald'); ->setHref('/herald/transcript/?phid='.$commit->getPHID())
$actions[] = $action; ->setWorkflow(true);
$actions->addAction($action);
$action = new AphrontHeadsupActionView(); $action = id(new PhabricatorActionView())
$action->setName('Download Raw Diff'); ->setName('Download Raw Diff')
$action->setURI($request->getRequestURI()->alter('diff', true)); ->setHref($request->getRequestURI()->alter('diff', true))
$action->setClass('action-download'); ->setIcon('download');
$actions[] = $action; $actions->addAction($action);
$action_list = new AphrontHeadsupActionListView(); return $actions;
$action_list->setActions($actions);
return $action_list;
} }
private function buildRefs(DiffusionRequest $request) { private function buildRefs(DiffusionRequest $request) {

View file

@ -72,7 +72,7 @@ abstract class DiffusionController extends PhabricatorController {
$selected_href = $href; $selected_href = $href;
} }
$nav->addFilter($href, $name); $nav->addFilter($href, $name, $href);
} }
$nav->selectFilter($selected_href, null); $nav->selectFilter($selected_href, null);
@ -88,9 +88,11 @@ abstract class DiffusionController extends PhabricatorController {
} }
public function buildCrumbs(array $spec = array()) { public function buildCrumbs(array $spec = array()) {
$crumbs = new AphrontCrumbsView(); $crumbs = $this->buildApplicationCrumbs();
$crumb_list = $this->buildCrumbList($spec); $crumb_list = $this->buildCrumbList($spec);
$crumbs->setCrumbs($crumb_list); foreach ($crumb_list as $crumb) {
$crumbs->addCrumb($crumb);
}
return $crumbs; return $crumbs;
} }
@ -155,15 +157,11 @@ abstract class DiffusionController extends PhabricatorController {
$repository = null; $repository = null;
} }
if ($repository) { $crumb = id(new PhabricatorCrumbView())
$crumb_list[] = phutil_render_tag( ->setName('Diffusion')
'a', ->setHref('/diffusion/');
array( $crumb_list[] = $crumb;
'href' => '/diffusion/', if (!$repository) {
),
'Diffusion');
} else {
$crumb_list[] = 'Diffusion';
return $crumb_list; return $crumb_list;
} }
@ -177,49 +175,53 @@ abstract class DiffusionController extends PhabricatorController {
} }
} }
if (!$spec['view'] && !$spec['commit'] $crumb = id(new PhabricatorCrumbView())
&& !$spec['tags'] && !$spec['branches']) { ->setName($repository_name);
$crumb_list[] = $repository_name; if (!$spec['view'] && !$spec['commit'] &&
!$spec['tags'] && !$spec['branches']) {
$crumb_list[] = $crumb;
return $crumb_list; return $crumb_list;
} }
$crumb->setHref("/diffusion/{$callsign}/");
$crumb_list[] = phutil_render_tag( $crumb_list[] = $crumb;
'a',
array(
'href' => "/diffusion/{$callsign}/",
),
$repository_name);
$raw_commit = $drequest->getRawCommit(); $raw_commit = $drequest->getRawCommit();
if ($spec['tags']) { if ($spec['tags']) {
$crumb = new PhabricatorCrumbView();
if ($spec['commit']) { if ($spec['commit']) {
$crumb_list[] = "Tags for ".phutil_render_tag( $crumb->setName(
'a', "Tags for r{$callsign}{$raw_commit}"
array( );
'href' => $drequest->generateURI( $crumb->setHref($drequest->generateURI(
array( array(
'action' => 'commit', 'action' => 'commit',
'commit' => $raw_commit, 'commit' => $raw_commit,
)), ))
), );
phutil_escape_html("r{$callsign}{$raw_commit}"));
} else { } else {
$crumb_list[] = 'Tags'; $crumb->setName('Tags');
} }
$crumb_list[] = $crumb;
return $crumb_list; return $crumb_list;
} }
if ($spec['branches']) { if ($spec['branches']) {
$crumb_list[] = 'Branches'; $crumb = id(new PhabricatorCrumbView())
->setName('Branches');
$crumb_list[] = $crumb;
return $crumb_list; return $crumb_list;
} }
if ($spec['commit']) { if ($spec['commit']) {
$crumb_list[] = "r{$callsign}{$raw_commit}"; $crumb = id(new PhabricatorCrumbView())
->setName("r{$callsign}{$raw_commit}")
->setHref("r{$callsign}{$raw_commit}");
$crumb_list[] = $crumb;
return $crumb_list; return $crumb_list;
} }
$crumb = new PhabricatorCrumbView();
$view = $spec['view']; $view = $spec['view'];
$path = null; $path = null;
@ -247,7 +249,9 @@ abstract class DiffusionController extends PhabricatorController {
break; break;
case 'change': case 'change':
$view_name = 'Change'; $view_name = 'Change';
$crumb_list[] = phutil_escape_html($path).' ('.$commit_link.')'; $crumb_list[] = $crumb->setRawName(
phutil_escape_html($path).' ('.$commit_link.')'
);
return $crumb_list; return $crumb_list;
} }
@ -255,19 +259,18 @@ abstract class DiffusionController extends PhabricatorController {
'action' => $view, 'action' => $view,
); );
$crumb = id(new PhabricatorCrumbView())
->setName($view_name);
if (!strlen($path)) { if (!strlen($path)) {
$crumb_list[] = $view_name; $crumb_list[] = $crumb;
} else { } else {
$crumb_list[] = phutil_render_tag( $crumb->setHref($drequest->generateURI(
'a',
array(
'href' => $drequest->generateURI(
array( array(
'path' => '', 'path' => '',
) + $uri_params), ) + $uri_params)
), );
$view_name); $crumb_list[] = $crumb;
$path_parts = explode('/', $path); $path_parts = explode('/', $path);
do { do {
@ -292,7 +295,8 @@ abstract class DiffusionController extends PhabricatorController {
$path_sections[] = phutil_escape_html($last); $path_sections[] = phutil_escape_html($last);
$path_sections = '/'.implode('/', $path_sections); $path_sections = '/'.implode('/', $path_sections);
$crumb_list[] = $path_sections; $crumb_list[] = id(new PhabricatorCrumbView())
->setRawName($path_sections);
} }
$last_crumb = array_pop($crumb_list); $last_crumb = array_pop($crumb_list);
@ -307,9 +311,13 @@ abstract class DiffusionController extends PhabricatorController {
) + $uri_params), ) + $uri_params),
), ),
'Jump to HEAD'); 'Jump to HEAD');
$last_crumb .= " @ {$commit_link} ({$jump_link})"; $last_crumb->setRawName(
$last_crumb->getNameForRender() . " @ {$commit_link} ({$jump_link})"
);
} else if ($spec['view'] != 'lint') { } else if ($spec['view'] != 'lint') {
$last_crumb .= " @ HEAD"; $last_crumb->setRawName(
$last_crumb->getNameForRender() . " @ HEAD"
);
} }
$crumb_list[] = $last_crumb; $crumb_list[] = $last_crumb;

View file

@ -39,13 +39,6 @@ final class DiffusionHistoryController extends DiffusionController {
$content = array(); $content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'history',
));
if ($request->getBool('copies')) { if ($request->getBool('copies')) {
$button_title = 'Hide Copies/Branches'; $button_title = 'Hide Copies/Branches';
$copies_new = null; $copies_new = null;
@ -89,8 +82,15 @@ final class DiffusionHistoryController extends DiffusionController {
$nav = $this->buildSideNav('history', false); $nav = $this->buildSideNav('history', false);
$nav->appendChild($content); $nav->appendChild($content);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'history',
));
$nav->setCrumbs($crumbs);
return $this->buildStandardPageResponse( return $this->buildApplicationPage(
$nav, $nav,
array( array(
'title' => 'history', 'title' => 'history',

View file

@ -10,6 +10,7 @@ final class DiffusionLintController extends DiffusionController {
if ($request->getStr('lint') !== null) { if ($request->getStr('lint') !== null) {
$controller = new DiffusionLintDetailsController($request); $controller = new DiffusionLintDetailsController($request);
$controller->setDiffusionRequest($drequest); $controller->setDiffusionRequest($drequest);
$controller->setCurrentApplication($this->getCurrentApplication());
return $this->delegateToController($controller); return $this->delegateToController($controller);
} }
@ -93,14 +94,6 @@ final class DiffusionLintController extends DiffusionController {
$content = array(); $content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$link = null; $link = null;
if ($this->diffusionRequest) { if ($this->diffusionRequest) {
$link = hsprintf( $link = hsprintf(
@ -134,12 +127,22 @@ final class DiffusionLintController extends DiffusionController {
->appendChild($table); ->appendChild($table);
$title = array('Lint'); $title = array('Lint');
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
if ($this->diffusionRequest) { if ($this->diffusionRequest) {
$title[] = $drequest->getCallsign(); $title[] = $drequest->getCallsign();
$content = $this->buildSideNav('lint', false)->appendChild($content); $content = $this->buildSideNav('lint', false)
->setCrumbs($crumbs)
->appendChild($content);
} else {
array_unshift($content, $crumbs);
} }
return $this->buildStandardPageResponse( return $this->buildApplicationPage(
$content, $content,
array('title' => $title)); array('title' => $title));
} }

View file

@ -54,13 +54,6 @@ final class DiffusionLintDetailsController extends DiffusionController {
$content = array(); $content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$pager = id(new AphrontPagerView()) $pager = id(new AphrontPagerView())
->setPageSize($limit) ->setPageSize($limit)
->setOffset($offset) ->setOffset($offset)
@ -86,8 +79,15 @@ final class DiffusionLintDetailsController extends DiffusionController {
$nav = $this->buildSideNav('lint', false); $nav = $this->buildSideNav('lint', false);
$nav->appendChild($content); $nav->appendChild($content);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$nav->setCrumbs($crumbs);
return $this->buildStandardPageResponse( return $this->buildApplicationPage(
$nav, $nav,
array('title' => array( array('title' => array(
'Lint', 'Lint',
@ -107,7 +107,12 @@ final class DiffusionLintDetailsController extends DiffusionController {
$conn = $branch->establishConnection('r'); $conn = $branch->establishConnection('r');
$where = array(); $where = array(
qsprintf(
$conn,
'branchID = %d',
$branch->getID())
);
if ($drequest->getPath() != '') { if ($drequest->getPath() != '') {
$is_dir = (substr($drequest->getPath(), -1) == '/'); $is_dir = (substr($drequest->getPath(), -1) == '/');
$where[] = qsprintf( $where[] = qsprintf(
@ -127,12 +132,9 @@ final class DiffusionLintDetailsController extends DiffusionController {
$conn, $conn,
'SELECT * 'SELECT *
FROM %T FROM %T
WHERE branchID = %d WHERE %Q
AND %Q ORDER BY path, code, line LIMIT %d OFFSET %d',
ORDER BY path, code, line
LIMIT %d OFFSET %d',
PhabricatorRepository::TABLE_LINTMESSAGE, PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
implode(' AND ', $where), implode(' AND ', $where),
$limit, $limit,
$offset); $offset);

View file

@ -95,7 +95,9 @@ abstract class DiffusionView extends AphrontView {
$text); $text);
} }
final public static function linkCommit($repository, $commit) { final public static function nameCommit(
PhabricatorRepository $repository,
$commit) {
switch ($repository->getVersionControlSystem()) { switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
@ -108,7 +110,15 @@ abstract class DiffusionView extends AphrontView {
} }
$callsign = $repository->getCallsign(); $callsign = $repository->getCallsign();
$commit_name = "r{$callsign}{$commit_name}"; return "r{$callsign}{$commit_name}";
}
final public static function linkCommit(
PhabricatorRepository $repository,
$commit) {
$commit_name = self::nameCommit($repository, $commit);
$callsign = $repository->getCallsign();
return phutil_render_tag( return phutil_render_tag(
'a', 'a',

View file

@ -6,12 +6,27 @@ final class PhabricatorCrumbView extends AphrontView {
private $href; private $href;
private $icon; private $icon;
private $isLastCrumb; private $isLastCrumb;
private $rawName;
/**
* Allows for custom HTML inside the name field.
*
* NOTE: you must handle escaping user text if you use this method.
*/
public function setRawName($raw_name) {
$this->rawName = $raw_name;
return $this;
}
public function setName($name) { public function setName($name) {
$this->name = $name; $this->name = $name;
return $this; return $this;
} }
public function getNameForRender() {
return nonempty($this->rawName, phutil_escape_html($this->name));
}
public function setHref($href) { public function setHref($href) {
$this->href = $href; $this->href = $href;
return $this; return $this;
@ -53,7 +68,7 @@ final class PhabricatorCrumbView extends AphrontView {
array( array(
'class' => 'phabricator-crumb-name', 'class' => 'phabricator-crumb-name',
), ),
phutil_escape_html($this->name)); $this->getNameForRender());
$divider = null; $divider = null;
if (!$this->isLastCrumb) { if (!$this->isLastCrumb) {

View file

@ -78,7 +78,7 @@
} }
.device-desktop .local-nav-collapsed .phabricator-nav-content { .device-desktop .local-nav-collapsed .phabricator-nav-content {
margin-left: 2.5em !important; margin-left: 0px !important;
} }
.device .phabricator-nav-col { .device .phabricator-nav-col {