diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 8e4d133aff..86185280b1 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -108,7 +108,7 @@ celerity_register_resource_map(array( ), 'aphront-panel-view-css' => array( - 'uri' => '/res/58da9c70/rsrc/css/aphront/panel-view.css', + 'uri' => '/res/f4157618/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( @@ -126,7 +126,7 @@ celerity_register_resource_map(array( ), 'aphront-side-nav-view-css' => array( - 'uri' => '/res/42f70a69/rsrc/css/aphront/side-nav-view.css', + 'uri' => '/res/ba0e18dd/rsrc/css/aphront/side-nav-view.css', 'type' => 'css', 'requires' => array( @@ -1368,7 +1368,7 @@ celerity_register_resource_map(array( ), 'phabricator-directory-css' => array( - 'uri' => '/res/a3d307c5/rsrc/css/application/directory/phabricator-directory.css', + 'uri' => '/res/61afca2b/rsrc/css/application/directory/phabricator-directory.css', 'type' => 'css', 'requires' => array( @@ -1787,28 +1787,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/540effd7/typeahead.pkg.js', 'type' => 'js', ), - '80580cea' => - array( - 'name' => 'differential.pkg.css', - 'symbols' => - array( - 0 => 'differential-core-view-css', - 1 => 'differential-changeset-view-css', - 2 => 'differential-revision-detail-css', - 3 => 'differential-revision-history-css', - 4 => 'differential-table-of-contents-css', - 5 => 'differential-revision-comment-css', - 6 => 'differential-revision-add-comment-css', - 7 => 'differential-revision-comment-list-css', - 8 => 'phabricator-object-selector-css', - 9 => 'aphront-headsup-action-list-view-css', - 10 => 'phabricator-content-source-view-css', - 11 => 'differential-local-commits-view-css', - ), - 'uri' => '/res/pkg/80580cea/differential.pkg.css', - 'type' => 'css', - ), - '9fd6210b' => + '775f5bae' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -1829,7 +1808,28 @@ celerity_register_resource_map(array( 13 => 'phabricator-remarkup-css', 14 => 'syntax-highlighting-css', ), - 'uri' => '/res/pkg/9fd6210b/core.pkg.css', + 'uri' => '/res/pkg/775f5bae/core.pkg.css', + 'type' => 'css', + ), + '80580cea' => + array( + 'name' => 'differential.pkg.css', + 'symbols' => + array( + 0 => 'differential-core-view-css', + 1 => 'differential-changeset-view-css', + 2 => 'differential-revision-detail-css', + 3 => 'differential-revision-history-css', + 4 => 'differential-table-of-contents-css', + 5 => 'differential-revision-comment-css', + 6 => 'differential-revision-add-comment-css', + 7 => 'differential-revision-comment-list-css', + 8 => 'phabricator-object-selector-css', + 9 => 'aphront-headsup-action-list-view-css', + 10 => 'phabricator-content-source-view-css', + 11 => 'differential-local-commits-view-css', + ), + 'uri' => '/res/pkg/80580cea/differential.pkg.css', 'type' => 'css', ), 'b164acea' => @@ -1854,16 +1854,16 @@ celerity_register_resource_map(array( ), 'reverse' => array( - 'aphront-crumbs-view-css' => '9fd6210b', - 'aphront-dialog-view-css' => '9fd6210b', - 'aphront-form-view-css' => '9fd6210b', + 'aphront-crumbs-view-css' => '775f5bae', + 'aphront-dialog-view-css' => '775f5bae', + 'aphront-form-view-css' => '775f5bae', 'aphront-headsup-action-list-view-css' => '80580cea', - 'aphront-list-filter-view-css' => '9fd6210b', - 'aphront-panel-view-css' => '9fd6210b', - 'aphront-side-nav-view-css' => '9fd6210b', - 'aphront-table-view-css' => '9fd6210b', - 'aphront-tokenizer-control-css' => '9fd6210b', - 'aphront-typeahead-control-css' => '9fd6210b', + 'aphront-list-filter-view-css' => '775f5bae', + 'aphront-panel-view-css' => '775f5bae', + 'aphront-side-nav-view-css' => '775f5bae', + 'aphront-table-view-css' => '775f5bae', + 'aphront-tokenizer-control-css' => '775f5bae', + 'aphront-typeahead-control-css' => '775f5bae', 'differential-changeset-view-css' => '80580cea', 'differential-core-view-css' => '80580cea', 'differential-inline-comment-editor' => '15c4a6dd', @@ -1912,16 +1912,16 @@ celerity_register_resource_map(array( 'javelin-vector' => 'b164acea', 'javelin-workflow' => '46547a92', 'phabricator-content-source-view-css' => '80580cea', - 'phabricator-core-buttons-css' => '9fd6210b', - 'phabricator-core-css' => '9fd6210b', - 'phabricator-directory-css' => '9fd6210b', + 'phabricator-core-buttons-css' => '775f5bae', + 'phabricator-core-css' => '775f5bae', + 'phabricator-directory-css' => '775f5bae', 'phabricator-drag-and-drop-file-upload' => '15c4a6dd', 'phabricator-keyboard-shortcut' => '46547a92', 'phabricator-keyboard-shortcut-manager' => '46547a92', 'phabricator-object-selector-css' => '80580cea', - 'phabricator-remarkup-css' => '9fd6210b', + 'phabricator-remarkup-css' => '775f5bae', 'phabricator-shaped-request' => '15c4a6dd', - 'phabricator-standard-page-view' => '9fd6210b', - 'syntax-highlighting-css' => '9fd6210b', + 'phabricator-standard-page-view' => '775f5bae', + 'syntax-highlighting-css' => '775f5bae', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f3038b30f3..7daeada815 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -472,13 +472,13 @@ phutil_register_library_map(array( 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', - 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', + 'PhabricatorDirectoryCategoryViewController' => 'applications/directory/controller/categoryview', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', + 'PhabricatorDirectoryEditController' => 'applications/directory/controller/edit', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', - 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorDisabledUserController' => 'applications/auth/controller/disabled', 'PhabricatorDraft' => 'applications/draft/storage/draft', @@ -1204,13 +1204,13 @@ phutil_register_library_map(array( 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', - 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', + 'PhabricatorDirectoryCategoryViewController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', + 'PhabricatorDirectoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', - 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDraft' => 'PhabricatorDraftDAO', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index ca44bd3553..e70f0c53fc 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -36,14 +36,14 @@ class AphrontDefaultApplicationConfiguration '$' => 'PhabricatorDirectoryMainController', ), '/directory/' => array( - 'item/$' - => 'PhabricatorDirectoryItemListController', + '(?P\d+)/$' + => 'PhabricatorDirectoryCategoryViewController', + 'edit/$' + => 'PhabricatorDirectoryEditController', 'item/edit/(?:(?P\d+)/)?$' => 'PhabricatorDirectoryItemEditController', 'item/delete/(?P\d+)/' => 'PhabricatorDirectoryItemDeleteController', - 'category/$' - => 'PhabricatorDirectoryCategoryListController', 'category/edit/(?:(?P\d+)/)?$' => 'PhabricatorDirectoryCategoryEditController', 'category/delete/(?P\d+)/' diff --git a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php index 5763562e08..c00e2d1a67 100644 --- a/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php +++ b/src/applications/differential/controller/revisionlist/DifferentialRevisionListController.php @@ -369,26 +369,9 @@ class DifferentialRevisionListController extends DifferentialController { $views = array(); switch ($filter) { case 'active': - $active = array(); - $waiting = array(); - - // Bucket revisions into $active (revisions you need to do something - // about) and $waiting (revisions you're waiting on someone else to do - // something about). - foreach ($revisions as $revision) { - $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; - $needs_review = ($revision->getStatus() == $status_review); - $filter_is_author = ($revision->getAuthorPHID() == $user_phid); - - // If exactly one of "needs review" and "the user is the author" is - // true, the user needs to act on it. Otherwise, they're waiting on - // it. - if ($needs_review ^ $filter_is_author) { - $active[] = $revision; - } else { - $waiting[] = $revision; - } - } + list($active, $waiting) = DifferentialRevisionQuery::splitResponsible( + $revisions, + $user_phid); $view = id(new DifferentialRevisionListView()) ->setRevisions($active) diff --git a/src/applications/differential/controller/revisionlist/__init__.php b/src/applications/differential/controller/revisionlist/__init__.php index 7699cf9983..a0972ce79f 100644 --- a/src/applications/differential/controller/revisionlist/__init__.php +++ b/src/applications/differential/controller/revisionlist/__init__.php @@ -6,8 +6,6 @@ -phutil_require_module('arcanist', 'differential/constants/revisionstatus'); - phutil_require_module('phabricator', 'aphront/response/redirect'); phutil_require_module('phabricator', 'applications/differential/controller/base'); phutil_require_module('phabricator', 'applications/differential/query/revision'); diff --git a/src/applications/differential/query/revision/DifferentialRevisionQuery.php b/src/applications/differential/query/revision/DifferentialRevisionQuery.php index db5f01606c..795d25589a 100644 --- a/src/applications/differential/query/revision/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/revision/DifferentialRevisionQuery.php @@ -785,5 +785,30 @@ final class DifferentialRevisionQuery { } } + public static function splitResponsible(array $revisions, $user_phid) { + $active = array(); + $waiting = array(); + $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; + + // Bucket revisions into $active (revisions you need to do something + // about) and $waiting (revisions you're waiting on someone else to do + // something about). + foreach ($revisions as $revision) { + $needs_review = ($revision->getStatus() == $status_review); + $filter_is_author = ($revision->getAuthorPHID() == $user_phid); + + // If exactly one of "needs review" and "the user is the author" is + // true, the user needs to act on it. Otherwise, they're waiting on + // it. + if ($needs_review ^ $filter_is_author) { + $active[] = $revision; + } else { + $waiting[] = $revision; + } + } + + return array($active, $waiting); + } + } diff --git a/src/applications/directory/controller/base/PhabricatorDirectoryController.php b/src/applications/directory/controller/base/PhabricatorDirectoryController.php index e4000f9142..2c25cf4e6c 100644 --- a/src/applications/directory/controller/base/PhabricatorDirectoryController.php +++ b/src/applications/directory/controller/base/PhabricatorDirectoryController.php @@ -1,7 +1,7 @@ buildStandardPageView(); - $page->setApplicationName('Directory'); $page->setBaseURI('/'); $page->setTitle(idx($data, 'title')); - if ($this->getRequest()->getUser()->getIsAdmin()) { - $tabs = array( - 'categories' => array( - 'href' => '/directory/category/', - 'name' => 'Categories', - ), - 'items' => array( - 'href' => '/directory/item/', - 'name' => 'Items', - ), - ); - } else { - $tabs = array(); - } - - $page->setTabs( - $tabs, - idx($data, 'tab')); $page->setGlyph("\xE2\x9A\x92"); $page->appendChild($view); @@ -55,4 +36,37 @@ abstract class PhabricatorDirectoryController extends PhabricatorController { return $response->setContent($page->render()); } + public function buildNav() { + $user = $this->getRequest()->getUser(); + + $nav = new AphrontSideNavFilterView(); + $nav->setBaseURI(new PhutilURI('/')); + + $nav->addLabel('Phabricator'); + $nav->addFilter('home', 'Tactical Command', '/'); + $nav->addSpacer(); + $nav->addLabel('Applications'); + + $categories = $this->loadDirectoryCategories(); + + foreach ($categories as $category) { + $nav->addFilter( + 'directory/'.$category->getID(), + $category->getName()); + } + + if ($user->getIsAdmin()) { + $nav->addSpacer(); + $nav->addFilter('directory/edit', 'Edit Applications...'); + } + + return $nav; + } + + protected function loadDirectoryCategories() { + $categories = id(new PhabricatorDirectoryCategory())->loadAll(); + $categories = msort($categories, 'getSequence'); + return $categories; + } + } diff --git a/src/applications/directory/controller/base/__init__.php b/src/applications/directory/controller/base/__init__.php index e30b96d052..e21e32734a 100644 --- a/src/applications/directory/controller/base/__init__.php +++ b/src/applications/directory/controller/base/__init__.php @@ -8,7 +8,10 @@ phutil_require_module('phabricator', 'aphront/response/webpage'); phutil_require_module('phabricator', 'applications/base/controller/base'); +phutil_require_module('phabricator', 'applications/directory/storage/category'); +phutil_require_module('phabricator', 'view/layout/sidenavfilter'); +phutil_require_module('phutil', 'parser/uri'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/directory/controller/categorydelete/PhabricatorDirectoryCategoryDeleteController.php b/src/applications/directory/controller/categorydelete/PhabricatorDirectoryCategoryDeleteController.php index 122814fa76..a8035f31f0 100644 --- a/src/applications/directory/controller/categorydelete/PhabricatorDirectoryCategoryDeleteController.php +++ b/src/applications/directory/controller/categorydelete/PhabricatorDirectoryCategoryDeleteController.php @@ -1,7 +1,7 @@ isFormPost()) { $category->delete(); return id(new AphrontRedirectResponse()) - ->setURI('/directory/category/'); + ->setURI('/directory/edit/'); } $dialog = new AphrontDialogView(); @@ -43,7 +43,7 @@ class PhabricatorDirectoryCategoryDeleteController $dialog->setTitle('Really delete this category?'); $dialog->appendChild("Are you sure you want to delete this category?"); $dialog->addSubmitButton('Delete'); - $dialog->addCancelButton('/directory/category/'); + $dialog->addCancelButton('/directory/edit/'); $dialog->setSubmitURI($request->getPath()); return id(new AphrontDialogResponse())->setDialog($dialog); diff --git a/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php b/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php index a20db00702..5317e3fe4d 100644 --- a/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php +++ b/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php @@ -1,7 +1,7 @@ save(); return id(new AphrontRedirectResponse()) - ->setURI('/directory/category/'); + ->setURI('/directory/edit/'); } } @@ -89,7 +89,7 @@ class PhabricatorDirectoryCategoryEditController ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') - ->addCancelButton('/directory/category/')); + ->addCancelButton('/directory/edit/')); $panel = new AphrontPanelView(); if ($category->getID()) { diff --git a/src/applications/directory/controller/categorylist/PhabricatorDirectoryCategoryListController.php b/src/applications/directory/controller/categorylist/PhabricatorDirectoryCategoryListController.php deleted file mode 100644 index 39a67d78a5..0000000000 --- a/src/applications/directory/controller/categorylist/PhabricatorDirectoryCategoryListController.php +++ /dev/null @@ -1,73 +0,0 @@ -loadAll(); - $categories = msort($categories, 'getSequence'); - - $rows = array(); - foreach ($categories as $category) { - $rows[] = array( - $category->getID(), - phutil_render_tag( - 'a', - array( - 'href' => '/directory/category/edit/'.$category->getID().'/', - ), - phutil_escape_html($category->getName())), - javelin_render_tag( - 'a', - array( - 'href' => '/directory/category/delete/'.$category->getID().'/', - 'class' => 'button grey small', - 'sigil' => 'workflow', - ), - 'Delete'), - ); - } - - - $table = new AphrontTableView($rows); - $table->setHeaders( - array( - 'ID', - 'Name', - '', - )); - $table->setColumnClasses( - array( - null, - 'wide', - 'action', - )); - - $panel = new AphrontPanelView(); - $panel->appendChild($table); - $panel->setHeader('Directory Categories'); - $panel->setCreateButton('New Category', '/directory/category/edit/'); - - return $this->buildStandardPageResponse($panel, array( - 'title' => 'Directory Category List', - 'tab' => 'categories', - )); - } - -} diff --git a/src/applications/directory/controller/categoryview/PhabricatorDirectoryCategoryViewController.php b/src/applications/directory/controller/categoryview/PhabricatorDirectoryCategoryViewController.php new file mode 100644 index 0000000000..45cf8457f2 --- /dev/null +++ b/src/applications/directory/controller/categoryview/PhabricatorDirectoryCategoryViewController.php @@ -0,0 +1,78 @@ +id = $data['id']; + } + + public function shouldRequireAdmin() { + return false; + } + + public function processRequest() { + $category = id(new PhabricatorDirectoryCategory())->load($this->id); + if (!$category) { + return new Aphront404Response(); + } + + $items = id(new PhabricatorDirectoryItem())->loadAllWhere( + 'categoryID = %d', + $category->getID()); + $items = msort($items, 'getSortKey'); + + $nav = $this->buildNav(); + $nav->selectFilter('directory/'.$this->id, 'directory/'.$this->id); + + require_celerity_resource('phabricator-directory-css'); + + $item_markup = array(); + foreach ($items as $item) { + $item_markup[] = + '
'. + '

'. + phutil_render_tag( + 'a', + array( + 'href' => $item->getHref(), + ), + phutil_escape_html($item->getName())). + '

'. + '

'.phutil_escape_html($item->getDescription()).'

'. + '
'; + } + + $content = + '
'. + implode("\n", $item_markup). + '
'; + + + $nav->appendChild($content); + + return $this->buildStandardPageResponse( + $nav, + array( + 'title' => 'Directory Category List', + 'tab' => 'categories', + )); + } + +} diff --git a/src/applications/directory/controller/categorylist/__init__.php b/src/applications/directory/controller/categoryview/__init__.php similarity index 57% rename from src/applications/directory/controller/categorylist/__init__.php rename to src/applications/directory/controller/categoryview/__init__.php index 85fcddd51d..d4449fbee6 100644 --- a/src/applications/directory/controller/categorylist/__init__.php +++ b/src/applications/directory/controller/categoryview/__init__.php @@ -6,14 +6,14 @@ +phutil_require_module('phabricator', 'aphront/response/404'); phutil_require_module('phabricator', 'applications/directory/controller/base'); phutil_require_module('phabricator', 'applications/directory/storage/category'); -phutil_require_module('phabricator', 'infrastructure/javelin/markup'); -phutil_require_module('phabricator', 'view/control/table'); -phutil_require_module('phabricator', 'view/layout/panel'); +phutil_require_module('phabricator', 'applications/directory/storage/item'); +phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); -phutil_require_source('PhabricatorDirectoryCategoryListController.php'); +phutil_require_source('PhabricatorDirectoryCategoryViewController.php'); diff --git a/src/applications/directory/controller/itemlist/PhabricatorDirectoryItemListController.php b/src/applications/directory/controller/edit/PhabricatorDirectoryEditController.php similarity index 54% rename from src/applications/directory/controller/itemlist/PhabricatorDirectoryItemListController.php rename to src/applications/directory/controller/edit/PhabricatorDirectoryEditController.php index 6fa924d1c5..0fcd919377 100644 --- a/src/applications/directory/controller/itemlist/PhabricatorDirectoryItemListController.php +++ b/src/applications/directory/controller/edit/PhabricatorDirectoryEditController.php @@ -1,7 +1,7 @@ buildNav(); + $nav->selectFilter('directory/edit', 'directory/edit'); + + $nav->appendChild($this->buildCategoryList()); + $nav->appendChild($this->buildItemList()); + + return $this->buildStandardPageResponse( + $nav, + array( + 'title' => 'Edit Applications', + )); + } + + private function buildCategoryList() { + $categories = id(new PhabricatorDirectoryCategory())->loadAll(); + $categories = msort($categories, 'getSequence'); + + $rows = array(); + foreach ($categories as $category) { + $rows[] = array( + $category->getID(), + phutil_render_tag( + 'a', + array( + 'href' => '/directory/category/edit/'.$category->getID().'/', + ), + phutil_escape_html($category->getName())), + javelin_render_tag( + 'a', + array( + 'href' => '/directory/category/delete/'.$category->getID().'/', + 'class' => 'button grey small', + 'sigil' => 'workflow', + ), + 'Delete'), + ); + } + + $table = new AphrontTableView($rows); + $table->setHeaders( + array( + 'ID', + 'Name', + '', + )); + $table->setColumnClasses( + array( + null, + 'wide', + 'action', + )); + + $panel = new AphrontPanelView(); + $panel->appendChild($table); + $panel->setHeader('Directory Categories'); + $panel->setCreateButton('New Category', '/directory/category/edit/'); + + return $panel; + } + + private function buildItemList() { $items = id(new PhabricatorDirectoryItem())->loadAll(); $items = msort($items, 'getSortKey'); @@ -70,10 +131,6 @@ class PhabricatorDirectoryItemListController $panel->setHeader('Directory Items'); $panel->setCreateButton('New Item', '/directory/item/edit/'); - return $this->buildStandardPageResponse($panel, array( - 'title' => 'Directory Items', - 'tab' => 'items', - )); + return $panel; } - } diff --git a/src/applications/directory/controller/itemlist/__init__.php b/src/applications/directory/controller/edit/__init__.php similarity index 89% rename from src/applications/directory/controller/itemlist/__init__.php rename to src/applications/directory/controller/edit/__init__.php index cd3381ae08..0936a8dd3c 100644 --- a/src/applications/directory/controller/itemlist/__init__.php +++ b/src/applications/directory/controller/edit/__init__.php @@ -17,4 +17,4 @@ phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); -phutil_require_source('PhabricatorDirectoryItemListController.php'); +phutil_require_source('PhabricatorDirectoryEditController.php'); diff --git a/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php b/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php index 4c55f61246..aac5f9da3e 100644 --- a/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php +++ b/src/applications/directory/controller/itemdelete/PhabricatorDirectoryItemDeleteController.php @@ -1,7 +1,7 @@ isFormPost()) { $item->delete(); return id(new AphrontRedirectResponse()) - ->setURI('/directory/item/'); + ->setURI('/directory/edit/'); } $dialog = new AphrontDialogView(); @@ -43,7 +43,7 @@ class PhabricatorDirectoryItemDeleteController $dialog->setTitle('Really delete this item?'); $dialog->appendChild("Are you sure you want to delete this item?"); $dialog->addSubmitButton('Delete'); - $dialog->addCancelButton('/directory/item/'); + $dialog->addCancelButton('/directory/edit/'); $dialog->setSubmitURI($request->getPath()); return id(new AphrontDialogResponse())->setDialog($dialog); diff --git a/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php b/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php index 620c86c846..164f10c744 100644 --- a/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php +++ b/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php @@ -67,7 +67,7 @@ class PhabricatorDirectoryItemEditController if (!$errors) { $item->save(); return id(new AphrontRedirectResponse()) - ->setURI('/directory/item/'); + ->setURI('/directory/edit/'); } } @@ -124,7 +124,7 @@ class PhabricatorDirectoryItemEditController ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') - ->addCancelButton('/directory/item/')); + ->addCancelButton('/directory/edit/')); $panel = new AphrontPanelView(); if ($item->getID()) { diff --git a/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php b/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php index 2119bdeab8..2017b4ac31 100644 --- a/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php +++ b/src/applications/directory/controller/main/PhabricatorDirectoryMainController.php @@ -1,7 +1,7 @@ getRequest()->getUser(); + $project_query = new PhabricatorProjectQuery(); + $project_query->setMembers(array($user->getPHID())); + $projects = $project_query->execute(); - $items = id(new PhabricatorDirectoryItem())->loadAll(); - $items = msort($items, 'getSortKey'); + $unbreak_panel = $this->buildUnbreakNowPanel(); + $triage_panel = $this->buildNeedsTriagePanel($projects); + $revision_panel = $this->buildRevisionPanel(); + $tasks_panel = $this->buildTasksPanel(); + $feed_view = $this->buildFeedView($projects); - $categories = id(new PhabricatorDirectoryCategory())->loadAll(); - $categories = msort($categories, 'getSequence'); + $nav = $this->buildNav(); + $this->filter = $nav->selectFilter($this->filter, 'home'); - $category_map = mpull($categories, 'getName', 'getID'); - $category_map[0] = 'Free Radicals'; - $items = mgroup($items, 'getCategoryID'); + $content = array( + $unbreak_panel, + $triage_panel, + $revision_panel, + $tasks_panel, + $feed_view, + ); - require_celerity_resource('phabricator-directory-css'); + $nav->appendChild($content); - $content = array(); - foreach ($category_map as $id => $category_name) { - $category_items = idx($items, $id); - if (!$category_items) { - continue; - } + return $this->buildStandardPageResponse( + $nav, + array( + 'title' => 'Directory', + 'tab' => 'directory', + )); + } - $item_markup = array(); - foreach ($category_items as $item) { - $item_markup[] = - '
'. - '

'. - phutil_render_tag( - 'a', - array( - 'href' => $item->getHref(), - ), - phutil_escape_html($item->getName())). - '

'. - '

'.phutil_escape_html($item->getDescription()).'

'. - '
'; - } + private function buildUnbreakNowPanel() { + $user = $this->getRequest()->getUser(); + $user_phid = $user->getPHID(); - $content[] = - '
'. - '

'.phutil_escape_html($category_name).'

'. - '
'. - implode("\n", $item_markup). - '
'. - '
'; + $panel = new AphrontPanelView(); + $panel->setHeader('Unbreak Now!'); + $panel->setCaption('Open tasks with "Unbreak Now!" priority.'); + + $task_query = new ManiphestTaskQuery(); + $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); + $task_query->withPriority(ManiphestTaskPriority::PRIORITY_UNBREAK_NOW); + $task_query->setLimit(10); + $task_query->setCalculateRows(true); + + $tasks = $task_query->execute(); + + if ($tasks) { + $panel->addButton( + phutil_render_tag( + 'a', + array( + 'href' => '/maniphest/view/all/', + 'class' => 'grey button', + ), + 'View All Unbreak Now ('.$task_query->getRowCount().") \xC2\xBB")); + + $panel->appendChild($this->buildTaskListView($tasks)); + } else { + $panel->appendChild( + '

Nothing appears to be critically broken right now.

'); } - $content = - '
'. - implode("\n", $content). - '
'; + return $panel; + } - return $this->buildStandardPageResponse($content, array( - 'title' => 'Directory', - 'tab' => 'directory', - )); + private function buildNeedsTriagePanel(array $projects) { + $user = $this->getRequest()->getUser(); + $user_phid = $user->getPHID(); + + $panel = new AphrontPanelView(); + $panel->setHeader('Needs Triage'); + $panel->setCaption( + 'Open tasks with "Needs Triage" priority in '. + 'projects you are a member of.'); + + $task_query = new ManiphestTaskQuery(); + $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); + $task_query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); + $task_query->withProjects(mpull($projects, 'getPHID')); + $task_query->withAnyProject(true); + $task_query->setCalculateRows(true); + $task_query->setLimit(10); + + $tasks = $task_query->execute(); + if ($tasks) { + $panel->addButton( + phutil_render_tag( + 'a', + array( + // TODO: This should filter to just your projects' need-triage + // tasks? + 'href' => '/maniphest/view/alltriage/', + 'class' => 'grey button', + ), + 'View All Triage ('.$task_query->getRowCount().") \xC2\xBB")); + $panel->appendChild($this->buildTaskListView($tasks)); + } else { + $panel->appendChild('

No tasks in your projects need triage.

'); + } + + return $panel; + } + + private function buildRevisionPanel() { + $user = $this->getRequest()->getUser(); + $user_phid = $user->getPHID(); + + $revision_query = new DifferentialRevisionQuery(); + $revision_query->withStatus(DifferentialRevisionQuery::STATUS_OPEN); + $revision_query->withResponsibleUsers(array($user_phid)); + $revision_query->needRelationships(true); + + // NOTE: We need to unlimit this query to hit the responsible user + // fast-path. + $revision_query->setLimit(null); + $revisions = $revision_query->execute(); + + list($active, $waiting) = DifferentialRevisionQuery::splitResponsible( + $revisions, + $user_phid); + + $panel = new AphrontPanelView(); + $panel->setHeader('Revisions Waiting on You'); + $panel->setCaption('Revisions waiting for you for review or commit.'); + + $panel->addButton( + phutil_render_tag( + 'a', + array( + 'href' => '/differential/', + 'class' => 'button grey', + ), + "View Active Revisions \xC2\xBB")); + + if ($active) { + $revision_view = id(new DifferentialRevisionListView()) + ->setRevisions($active) + ->setUser($user); + $phids = array_merge( + array($user_phid), + $revision_view->getRequiredHandlePHIDs()); + $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); + + $revision_view->setHandles($handles); + + $panel->appendChild($revision_view); + } else { + $panel->appendChild('

No revisions are waiting on you.

'); + } + + return $panel; + } + + private function buildTasksPanel() { + $user = $this->getRequest()->getUser(); + $user_phid = $user->getPHID(); + + $task_query = new ManiphestTaskQuery(); + $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); + $task_query->withOwners(array($user_phid)); + $task_query->setCalculateRows(true); + $task_query->setLimit(10); + + $tasks = $task_query->execute(); + + $panel = new AphrontPanelView(); + $panel->setHeader('Assigned Tasks'); + $panel->setCaption('Tasks assigned to you.'); + + if ($tasks) { + $panel->addButton( + phutil_render_tag( + 'a', + array( + 'href' => '/maniphest/', + 'class' => 'button grey', + ), + "View All Assigned Tasks (".$task_query->getRowCount().") \xC2\xBB")); + $panel->appendChild($this->buildTaskListView($tasks)); + } else { + $panel->addButton( + phutil_render_tag( + 'a', + array( + 'href' => '/maniphest/?users='. + ManiphestTaskOwner::OWNER_UP_FOR_GRABS, + 'class' => 'button grey', + ), + "View Unassigned Tasks \xC2\xBB")); + $panel->appendChild('

You have no assigned tasks.

'); + } + + return $panel; + } + + + private function buildTaskListView(array $tasks) { + $user = $this->getRequest()->getUser(); + + $phids = array_filter(mpull($tasks, 'getOwnerPHID')); + $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); + + $view = new ManiphestTaskListView(); + $view->setTasks($tasks); + $view->setUser($user); + $view->setHandles($handles); + + return $view; + } + + private function buildFeedView(array $projects) { + $user = $this->getRequest()->getUser(); + $user_phid = $user->getPHID(); + + $feed_query = new PhabricatorFeedQuery(); + $feed_query->setFilterPHIDs( + array_merge( + array($user_phid), + mpull($projects, 'getPHID'))); + $feed = $feed_query->execute(); + + $builder = new PhabricatorFeedBuilder($feed); + $builder->setUser($user); + $feed_view = $builder->buildView(); + + + return + '
'. + '

Feed

'. + $feed_view->render(). + '
'; } } diff --git a/src/applications/directory/controller/main/__init__.php b/src/applications/directory/controller/main/__init__.php index e9a5b9d06c..88fcc28d03 100644 --- a/src/applications/directory/controller/main/__init__.php +++ b/src/applications/directory/controller/main/__init__.php @@ -6,10 +6,18 @@ +phutil_require_module('phabricator', 'applications/differential/query/revision'); +phutil_require_module('phabricator', 'applications/differential/view/revisionlist'); phutil_require_module('phabricator', 'applications/directory/controller/base'); -phutil_require_module('phabricator', 'applications/directory/storage/category'); -phutil_require_module('phabricator', 'applications/directory/storage/item'); -phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'applications/feed/builder/feed'); +phutil_require_module('phabricator', 'applications/feed/query'); +phutil_require_module('phabricator', 'applications/maniphest/constants/owner'); +phutil_require_module('phabricator', 'applications/maniphest/constants/priority'); +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', 'view/layout/panel'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); diff --git a/src/view/layout/panel/AphrontPanelView.php b/src/view/layout/panel/AphrontPanelView.php index 77f8b7bbf5..9ca537d474 100644 --- a/src/view/layout/panel/AphrontPanelView.php +++ b/src/view/layout/panel/AphrontPanelView.php @@ -1,7 +1,7 @@ caption = $caption; + return $this; + } + public function render() { if ($this->header !== null) { $header = '

'.$this->header.'

'; @@ -73,6 +79,15 @@ final class AphrontPanelView extends AphrontView { $header = null; } + if ($this->caption !== null) { + $caption = + '
'. + $this->caption. + '
'; + } else { + $caption = null; + } + $buttons = null; if ($this->buttons) { $buttons = @@ -97,7 +112,7 @@ final class AphrontPanelView extends AphrontView { 'class' => implode(' ', $classes), 'id' => $this->id, ), - $buttons.$header.$table); + $buttons.$header.$caption.$table); } } diff --git a/webroot/rsrc/css/aphront/panel-view.css b/webroot/rsrc/css/aphront/panel-view.css index 7f476ddba3..484499dddb 100644 --- a/webroot/rsrc/css/aphront/panel-view.css +++ b/webroot/rsrc/css/aphront/panel-view.css @@ -17,6 +17,13 @@ padding: 2px 0 8px; } +.aphront-panel-view-caption { + font-size: 11px; + color: #666666; + margin-top: -0.75em; + margin-bottom: 0.75em; +} + .aphront-panel-view-buttons { float: right; } diff --git a/webroot/rsrc/css/aphront/side-nav-view.css b/webroot/rsrc/css/aphront/side-nav-view.css index 77835b65b6..f334dd87c0 100644 --- a/webroot/rsrc/css/aphront/side-nav-view.css +++ b/webroot/rsrc/css/aphront/side-nav-view.css @@ -12,15 +12,16 @@ td.aphront-side-nav-content { } th.aphront-side-nav-navigation { - border-right: 1px solid #bbbbbb; + border-right: 1px solid #99c4d7; padding-bottom: 8em; + background: #fbfbff; } th.aphront-side-nav-navigation a, th.aphront-side-nav-navigation span { display: block; margin: 0 0 2px; - min-width: 150px; + min-width: 165px; padding: 3px 8px 3px 24px; font-weight: bold; white-space: nowrap; @@ -30,11 +31,12 @@ th.aphront-side-nav-navigation span { th.aphront-side-nav-navigation span { padding-left: 12px; padding-top: 6px; + color: #333333; } th.aphront-side-nav-navigation a:hover { text-decoration: none; - background: #f3f3f9; + background: #e9e9f6; } th.aphront-side-nav-navigation hr { @@ -46,5 +48,5 @@ th.aphront-side-nav-navigation hr { th.aphront-side-nav-navigation a.aphront-side-nav-selected, th.aphront-side-nav-navigation a.aphront-side-nav-selected:hover { - background: #d8dfea; + background: #d8d8e6; } diff --git a/webroot/rsrc/css/application/directory/phabricator-directory.css b/webroot/rsrc/css/application/directory/phabricator-directory.css index 27ccb828e8..79ccbcc709 100644 --- a/webroot/rsrc/css/application/directory/phabricator-directory.css +++ b/webroot/rsrc/css/application/directory/phabricator-directory.css @@ -5,17 +5,11 @@ .aphront-directory-list { - margin: 1em 3% 8em; + margin: 2em; } -.aphront-directory-category h1 { - border-bottom: 1px solid #cccccc; - margin-bottom: .5em; - padding-bottom: .1em; -} - -.aphront-directory-list h2 { - font-size: 14px; +.aphront-directory-list h1 { + font-size: 16px; font-weight: bold; padding: 0; margin: 0; @@ -27,12 +21,6 @@ padding: .05em .5em .5em; } -.aphront-directory-category { - padding: 10px; - width: 300px; - float: left; -} - -.aphront-directory-group { - padding: 0 .5em 3em; +.aphront-directory-item { + margin: 1em 0; }