mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-14 00:31:05 +01:00
Add a "jump nav" element to the homepage, for quick tool/object navigation
Summary: - Restore quick methods for getting to common features (upload file, create task, etc.) - Provide a flexible cli-like navigation element similar to stuff used at Facebook (bunny1 / lolbunny). Test Plan: Used jump nav and nav buttons. Reviewers: btrahan, fratrik Reviewed By: btrahan CC: aran, epriestley Differential Revision: https://secure.phabricator.com/D1619
This commit is contained in:
parent
29acc848c1
commit
965a4da042
8 changed files with 256 additions and 15 deletions
|
@ -330,17 +330,6 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/behavior.js',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'javelin-behavior-aphront-basic-tokenizer' =>
|
||||
array(
|
||||
'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js',
|
||||
|
@ -704,6 +693,17 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/owners/owners-path-editor.js',
|
||||
),
|
||||
'javelin-behavior-phabricator-autofocus' =>
|
||||
array(
|
||||
'uri' => '/res/2946bb89/rsrc/js/application/core/behavior-autofocus.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-autofocus.js',
|
||||
),
|
||||
'javelin-behavior-phabricator-keyboard-pager' =>
|
||||
array(
|
||||
'uri' => '/res/56d64eff/rsrc/js/application/core/behavior-keyboard-pager.js',
|
||||
|
@ -1413,6 +1413,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/feed/feed.css',
|
||||
),
|
||||
'phabricator-jump-nav' =>
|
||||
array(
|
||||
'uri' => '/res/69238d2f/rsrc/css/application/directory/phabricator-jump-nav.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/directory/phabricator-jump-nav.css',
|
||||
),
|
||||
'phabricator-keyboard-shortcut' =>
|
||||
array(
|
||||
'uri' => '/res/beed38cd/rsrc/js/application/core/KeyboardShortcut.js',
|
||||
|
@ -1520,6 +1529,17 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/core/ShapedRequest.js',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'phabricator-slowvote-css' =>
|
||||
array(
|
||||
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',
|
||||
|
|
|
@ -32,7 +32,8 @@ class AphrontDefaultApplicationConfiguration
|
|||
|
||||
public function getURIMap() {
|
||||
return $this->getResourceURIMapRules() + array(
|
||||
'/(?:(?P<filter>feed)/)?$' => 'PhabricatorDirectoryMainController',
|
||||
'/(?:(?P<filter>(?:feed|jump))/)?$' =>
|
||||
'PhabricatorDirectoryMainController',
|
||||
'/directory/' => array(
|
||||
'(?P<id>\d+)/$'
|
||||
=> 'PhabricatorDirectoryCategoryViewController',
|
||||
|
|
|
@ -44,6 +44,7 @@ abstract class PhabricatorDirectoryController extends PhabricatorController {
|
|||
|
||||
$nav->addLabel('Phabricator');
|
||||
$nav->addFilter('home', 'Tactical Command', '/');
|
||||
$nav->addFilter('jump', 'Jump Nav');
|
||||
$nav->addFilter('feed', 'Feed');
|
||||
$nav->addSpacer();
|
||||
$nav->addLabel('Applications');
|
||||
|
|
|
@ -37,13 +37,24 @@ class PhabricatorDirectoryMainController
|
|||
$nav = $this->buildNav();
|
||||
$this->filter = $nav->selectFilter($this->filter, 'home');
|
||||
|
||||
$project_query = new PhabricatorProjectQuery();
|
||||
$project_query->setMembers(array($user->getPHID()));
|
||||
$projects = $project_query->execute();
|
||||
switch ($this->filter) {
|
||||
case 'jump':
|
||||
break;
|
||||
case 'home':
|
||||
case 'feed':
|
||||
$project_query = new PhabricatorProjectQuery();
|
||||
$project_query->setMembers(array($user->getPHID()));
|
||||
$projects = $project_query->execute();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown filter '{$this->filter}'!");
|
||||
}
|
||||
|
||||
switch ($this->filter) {
|
||||
case 'feed':
|
||||
return $this->buildFeedResponse($nav, $projects);
|
||||
case 'jump':
|
||||
return $this->buildJumpResponse($nav);
|
||||
default:
|
||||
return $this->buildMainResponse($nav, $projects);
|
||||
}
|
||||
|
@ -53,6 +64,7 @@ class PhabricatorDirectoryMainController
|
|||
private function buildMainResponse($nav, $projects) {
|
||||
$unbreak_panel = $this->buildUnbreakNowPanel();
|
||||
$triage_panel = $this->buildNeedsTriagePanel($projects);
|
||||
$jump_panel = $this->buildJumpPanel();
|
||||
$revision_panel = $this->buildRevisionPanel();
|
||||
$tasks_panel = $this->buildTasksPanel();
|
||||
$feed_view = $this->buildFeedView($projects, $is_full = false);
|
||||
|
@ -61,6 +73,7 @@ class PhabricatorDirectoryMainController
|
|||
$content = array(
|
||||
$unbreak_panel,
|
||||
$triage_panel,
|
||||
$jump_panel,
|
||||
$revision_panel,
|
||||
$tasks_panel,
|
||||
$feed_view,
|
||||
|
@ -75,6 +88,79 @@ class PhabricatorDirectoryMainController
|
|||
));
|
||||
}
|
||||
|
||||
private function buildJumpResponse($nav) {
|
||||
$request = $this->getRequest();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$jump = $request->getStr('jump');
|
||||
$jump = trim($jump);
|
||||
|
||||
$help_href = PhabricatorEnv::getDocLink(
|
||||
'articles/Jump_Nav_User_Guide.html');
|
||||
|
||||
$patterns = array(
|
||||
'/^help/i' => 'uri:'.$help_href,
|
||||
'/^d$/i' => 'uri:/differential/',
|
||||
'/^r$/i' => 'uri:/diffusion/',
|
||||
'/^t$/i' => 'uri:/maniphest/',
|
||||
'/r([A-Z]+)$/' => 'repository',
|
||||
'/r([A-Z]+)(\S+)$/' => 'commit',
|
||||
'/^d(\d+)$/i' => 'revision',
|
||||
'/^t(\d+)$/i' => 'task',
|
||||
|
||||
// TODO: '/^p$/i' => 'uri:/projects/',
|
||||
// TODO: '/^u$/i' => 'uri:/people/',
|
||||
// TODO: '/^p\s+(\S+)$/i' => 'project',
|
||||
// TODO: '/^u\s+(\S+)$/i' => 'user',
|
||||
// TODO: '/^task:\s+(\S+)/i' => 'create-task',
|
||||
// TODO: '/^(?:s|symbol)\s+(\S+)/i' => 'find-symbol',
|
||||
);
|
||||
|
||||
|
||||
foreach ($patterns as $pattern => $effect) {
|
||||
$matches = null;
|
||||
if (preg_match($pattern, $jump, $matches)) {
|
||||
if (!strncmp($effect, 'uri:', 4)) {
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI(substr($effect, 4));
|
||||
} else {
|
||||
switch ($effect) {
|
||||
case 'repository':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/diffusion/'.$matches[1].'/');
|
||||
case 'commit':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/'.$matches[0]);
|
||||
case 'revision':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/D'.$matches[1]);
|
||||
case 'task':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/T'.$matches[1]);
|
||||
default:
|
||||
throw new Exception("Unknown jump effect '{$effect}'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query = new PhabricatorSearchQuery();
|
||||
$query->setQuery($jump);
|
||||
$query->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/search/'.$query->getQueryKey().'/');
|
||||
}
|
||||
|
||||
|
||||
$nav->appendChild($this->buildJumpPanel());
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Jump Nav',
|
||||
));
|
||||
}
|
||||
|
||||
private function buildFeedResponse($nav, $projects) {
|
||||
$view = $this->buildFeedView($projects, $is_full = true);
|
||||
$nav->appendChild($view);
|
||||
|
@ -360,4 +446,76 @@ class PhabricatorDirectoryMainController
|
|||
'</div>';
|
||||
}
|
||||
|
||||
private function buildJumpPanel() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$uniq_id = celerity_generate_unique_node_id();
|
||||
|
||||
Javelin::initBehavior(
|
||||
'phabricator-autofocus',
|
||||
array(
|
||||
'id' => $uniq_id,
|
||||
));
|
||||
|
||||
require_celerity_resource('phabricator-jump-nav');
|
||||
|
||||
$doc_href = PhabricatorEnv::getDocLink('articles/Jump_Nav_User_Guide.html');
|
||||
$doc_link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $doc_href,
|
||||
),
|
||||
'Jump Nav Use Guide');
|
||||
|
||||
$jump_input = phutil_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'text',
|
||||
'class' => 'phabricator-jump-nav',
|
||||
'name' => 'jump',
|
||||
'id' => $uniq_id,
|
||||
)).
|
||||
phutil_render_tag(
|
||||
'p',
|
||||
array(
|
||||
'class' => 'phabricator-jump-nav-caption',
|
||||
),
|
||||
'Enter the name of an object like <tt>D123</tt> to quickly jump to '.
|
||||
'it. See '.$doc_link.' or type <tt>help</tt>.');
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->appendChild(
|
||||
phabricator_render_form(
|
||||
$user,
|
||||
array(
|
||||
'action' => '/jump/',
|
||||
'method' => 'POST',
|
||||
),
|
||||
$jump_input));
|
||||
|
||||
$nav_buttons = array(
|
||||
'/maniphest/task/create/' => 'Create a Task',
|
||||
'/file/' => 'Upload a File',
|
||||
'/paste/' => 'Create Paste',
|
||||
'/w/' => 'Browse Wiki',
|
||||
'/diffusion/' => 'Browse Code',
|
||||
);
|
||||
|
||||
$panel->appendChild('<div class="phabricator-jump-nav-buttons">');
|
||||
foreach ($nav_buttons as $uri => $name) {
|
||||
$panel->appendChild(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $uri,
|
||||
'class' => 'button grey',
|
||||
),
|
||||
phutil_escape_html($name)));
|
||||
}
|
||||
$panel->appendChild('</div>');
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/differential/query/revision');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisionlist');
|
||||
phutil_require_module('phabricator', 'applications/directory/controller/base');
|
||||
|
@ -17,6 +18,11 @@ phutil_require_module('phabricator', 'applications/maniphest/query');
|
|||
phutil_require_module('phabricator', 'applications/maniphest/view/tasklist');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/project/query/project');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/query');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/layout/minipanel');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
|
|
21
src/docs/userguide/jump.diviner
Normal file
21
src/docs/userguide/jump.diviner
Normal file
|
@ -0,0 +1,21 @@
|
|||
@title Jump Nav User Guide
|
||||
@group userguide
|
||||
|
||||
Command reference for the jump nav.
|
||||
|
||||
= Overview =
|
||||
|
||||
The jump nav provides a quick way to navigate to tools and objects: just type
|
||||
a navigational command into the box and press return.
|
||||
|
||||
= Supported Commands =
|
||||
|
||||
- **help** - Jump to this document.
|
||||
- **T** - Jump to Maniphest.
|
||||
- **T123** - Jump to Maniphest Task 123.
|
||||
- **D** - Jump to Differential.
|
||||
- **D123** - Jump to Differential Revision 123.
|
||||
- **r** - Jump to Diffusion.
|
||||
- **rXYZ** - Jump to Diffusion Repository XYZ.
|
||||
- **rXYZabcdef** - Jump to Diffusion Commit rXYZabcdef.
|
||||
- **(default)** - Search for input.
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @provides phabricator-jump-nav
|
||||
*/
|
||||
|
||||
.phabricator-jump-nav {
|
||||
font-size: 18px;
|
||||
width: 98%;
|
||||
padding: .25em 1%;
|
||||
}
|
||||
|
||||
.phabricator-jump-nav-caption {
|
||||
font-size: 11px;
|
||||
color: #666666;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.phabricator-jump-nav-buttons {
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.phabricator-jump-nav-buttons a.button {
|
||||
margin-right: .75em;
|
||||
width: 125px;
|
||||
text-align: center;
|
||||
}
|
8
webroot/rsrc/js/application/core/behavior-autofocus.js
Normal file
8
webroot/rsrc/js/application/core/behavior-autofocus.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* @provides javelin-behavior-phabricator-autofocus
|
||||
* @requires javelin-behavior javelin-dom
|
||||
*/
|
||||
|
||||
JX.behavior('phabricator-autofocus', function(config) {
|
||||
try { JX.$(config.id).focus(); } catch (x) { }
|
||||
});
|
Loading…
Reference in a new issue