Page MenuHomePhabricator

D15007.diff
No OneTemporary

D15007.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2419,6 +2419,7 @@
'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php',
'PhabricatorLegalpadSignaturePolicyRule' => 'applications/legalpad/policyrule/PhabricatorLegalpadSignaturePolicyRule.php',
'PhabricatorLibraryTestCase' => '__tests__/PhabricatorLibraryTestCase.php',
+ 'PhabricatorLinkProfilePanel' => 'applications/search/profilepanel/PhabricatorLinkProfilePanel.php',
'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php',
'PhabricatorLipsumGenerateWorkflow' => 'applications/lipsum/management/PhabricatorLipsumGenerateWorkflow.php',
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
@@ -2826,6 +2827,13 @@
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php',
+ 'PhabricatorProfilePanel' => 'applications/search/profilepanel/PhabricatorProfilePanel.php',
+ 'PhabricatorProfilePanelConfiguration' => 'applications/search/storage/PhabricatorProfilePanelConfiguration.php',
+ 'PhabricatorProfilePanelConfigurationQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationQuery.php',
+ 'PhabricatorProfilePanelConfigurationTransaction' => 'applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php',
+ 'PhabricatorProfilePanelEngine' => 'applications/search/engine/PhabricatorProfilePanelEngine.php',
+ 'PhabricatorProfilePanelInterface' => 'applications/search/interface/PhabricatorProfilePanelInterface.php',
+ 'PhabricatorProfilePanelPHIDType' => 'applications/search/phidtype/PhabricatorProfilePanelPHIDType.php',
'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php',
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
@@ -2856,6 +2864,7 @@
'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php',
'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php',
'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php',
+ 'PhabricatorProjectDetailsProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php',
'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php',
'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php',
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
@@ -2877,6 +2886,7 @@
'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php',
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php',
+ 'PhabricatorProjectMembersProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php',
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
'PhabricatorProjectMilestonesController' => 'applications/project/controller/PhabricatorProjectMilestonesController.php',
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
@@ -2909,6 +2919,7 @@
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
+ 'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php',
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
@@ -6700,6 +6711,7 @@
'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType',
'PhabricatorLegalpadSignaturePolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorLibraryTestCase' => 'PhutilLibraryTestCase',
+ 'PhabricatorLinkProfilePanel' => 'PhabricatorProfilePanel',
'PhabricatorLipsumArtist' => 'Phobject',
'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow',
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
@@ -7171,6 +7183,16 @@
),
'PhabricatorPolicyType' => 'PhabricatorPolicyConstants',
'PhabricatorPonderApplication' => 'PhabricatorApplication',
+ 'PhabricatorProfilePanel' => 'Phobject',
+ 'PhabricatorProfilePanelConfiguration' => array(
+ 'PhabricatorSearchDAO',
+ 'PhabricatorPolicyInterface',
+ 'PhabricatorExtendedPolicyInterface',
+ ),
+ 'PhabricatorProfilePanelConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorProfilePanelConfigurationTransaction' => 'PhabricatorApplicationTransaction',
+ 'PhabricatorProfilePanelEngine' => 'Phobject',
+ 'PhabricatorProfilePanelPHIDType' => 'PhabricatorPHIDType',
'PhabricatorProject' => array(
'PhabricatorProjectDAO',
'PhabricatorApplicationTransactionInterface',
@@ -7182,6 +7204,7 @@
'PhabricatorDestructibleInterface',
'PhabricatorFulltextInterface',
'PhabricatorConduitResultInterface',
+ 'PhabricatorProfilePanelInterface',
),
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
'PhabricatorProjectApplication' => 'PhabricatorApplication',
@@ -7223,6 +7246,7 @@
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField',
+ 'PhabricatorProjectDetailsProfilePanel' => 'PhabricatorProfilePanel',
'PhabricatorProjectEditController' => 'PhabricatorProjectController',
'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine',
'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
@@ -7243,6 +7267,7 @@
'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController',
'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule',
+ 'PhabricatorProjectMembersProfilePanel' => 'PhabricatorProfilePanel',
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
'PhabricatorProjectMilestonesController' => 'PhabricatorProjectController',
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
@@ -7278,6 +7303,7 @@
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel',
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
diff --git a/src/applications/project/controller/PhabricatorProjectBoardController.php b/src/applications/project/controller/PhabricatorProjectBoardController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardController.php
@@ -6,7 +6,7 @@
public function buildIconNavView(PhabricatorProject $project) {
$id = $project->getID();
$nav = parent::buildIconNavView($project);
- $nav->selectFilter("board/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
$nav->addClass('project-board-nav');
return $nav;
}
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -86,6 +86,8 @@
public function buildSideNavView($for_app = false) {
$project = $this->getProject();
+
+
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
@@ -115,65 +117,13 @@
}
public function buildIconNavView(PhabricatorProject $project) {
- $this->setProject($project);
$viewer = $this->getViewer();
- $id = $project->getID();
- $picture = $project->getProfileImageURI();
- $name = $project->getName();
- $columns = id(new PhabricatorProjectColumnQuery())
+ $engine = id(new PhabricatorProfilePanelEngine())
->setViewer($viewer)
- ->withProjectPHIDs(array($project->getPHID()))
- ->execute();
- if ($columns) {
- $board_icon = 'fa-columns';
- } else {
- $board_icon = 'fa-columns grey';
- }
-
- $nav = new AphrontSideNavFilterView();
- $nav->setIconNav(true);
- $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
- $nav->addIcon("profile/{$id}/", $name, null, $picture);
-
- $class = 'PhabricatorManiphestApplication';
- if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
- $phid = $project->getPHID();
- $nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
- $query_uri = urisprintf(
- '/maniphest/?statuses=open()&projects=%s#R',
- $phid);
- $nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
- }
-
- $nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o');
- $nav->addIcon("members/{$id}/", pht('Members'), 'fa-group');
+ ->setProfileObject($project);
- if (false && PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
- if ($project->supportsSubprojects()) {
- $subprojects_icon = 'fa-sitemap';
- } else {
- $subprojects_icon = 'fa-sitemap grey';
- }
-
- $key = PhabricatorProjectIconSet::getMilestoneIconKey();
- $milestones_icon = PhabricatorProjectIconSet::getIconIcon($key);
- if (!$project->supportsMilestones()) {
- $milestones_icon = "{$milestones_icon} grey";
- }
-
- $nav->addIcon(
- "subprojects/{$id}/",
- pht('Subprojects'),
- $subprojects_icon);
-
- $nav->addIcon(
- "milestones/{$id}/",
- pht('Milestones'),
- $milestones_icon);
- }
-
- return $nav;
+ return $engine->buildNavigation();
}
protected function buildApplicationCrumbs() {
diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
--- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php
+++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
@@ -281,7 +281,7 @@
->setForm($upload_form);
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("edit/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
$nav->appendChild($form_box);
$nav->appendChild($upload_box);
diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php
--- a/src/applications/project/controller/PhabricatorProjectFeedController.php
+++ b/src/applications/project/controller/PhabricatorProjectFeedController.php
@@ -34,7 +34,7 @@
->appendChild($feed);
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("feed/{$id}/");
+ $nav->selectFilter('feed');
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Feed'));
diff --git a/src/applications/project/controller/PhabricatorProjectMembersEditController.php b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
--- a/src/applications/project/controller/PhabricatorProjectMembersEditController.php
+++ b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
@@ -96,7 +96,7 @@
$member_list = $this->renderMemberList($project, $handles);
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("members/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_MEMBERS);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Members'));
diff --git a/src/applications/project/controller/PhabricatorProjectMilestonesController.php b/src/applications/project/controller/PhabricatorProjectMilestonesController.php
--- a/src/applications/project/controller/PhabricatorProjectMilestonesController.php
+++ b/src/applications/project/controller/PhabricatorProjectMilestonesController.php
@@ -77,7 +77,7 @@
->renderList());
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("milestones/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_MILESTONES);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Milestones'));
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -44,7 +44,7 @@
$timeline->setShouldTerminate(true);
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("profile/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
$crumbs = $this->buildApplicationCrumbs();
diff --git a/src/applications/project/controller/PhabricatorProjectSubprojectsController.php b/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
--- a/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
+++ b/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
@@ -76,7 +76,7 @@
->renderList());
$nav = $this->buildIconNavView($project);
- $nav->selectFilter("subprojects/{$id}/");
+ $nav->selectFilter(PhabricatorProject::PANEL_SUBPROJECTS);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Subprojects'));
diff --git a/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php
@@ -0,0 +1,31 @@
+<?php
+
+final class PhabricatorProjectDetailsProfilePanel
+ extends PhabricatorProfilePanel {
+
+ const PANELKEY = 'project.details';
+
+ protected function newNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config) {
+
+ $project = $config->getProfileObject();
+
+ $id = $project->getID();
+ $picture = $project->getProfileImageURI();
+ $name = $project->getName();
+
+ $href = "/project/profile/{$id}/";
+
+ $item = id(new PHUIListItemView())
+ ->setRenderNameAsTooltip(true)
+ ->setType(PHUIListItemView::TYPE_ICON_NAV)
+ ->setHref($href)
+ ->setName($name)
+ ->setProfileImage($picture);
+
+ return array(
+ $item,
+ );
+ }
+
+}
diff --git a/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php
@@ -0,0 +1,31 @@
+<?php
+
+final class PhabricatorProjectMembersProfilePanel
+ extends PhabricatorProfilePanel {
+
+ const PANELKEY = 'project.members';
+
+ protected function newNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config) {
+
+ $project = $config->getProfileObject();
+
+ $id = $project->getID();
+
+ $name = pht('Members');
+ $icon = 'fa-group';
+ $href = "/project/members/{$id}/";
+
+ $item = id(new PHUIListItemView())
+ ->setRenderNameAsTooltip(true)
+ ->setType(PHUIListItemView::TYPE_ICON_NAV)
+ ->setHref($href)
+ ->setName($name)
+ ->setIcon($icon);
+
+ return array(
+ $item,
+ );
+ }
+
+}
diff --git a/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php
@@ -0,0 +1,46 @@
+<?php
+
+final class PhabricatorProjectWorkboardProfilePanel
+ extends PhabricatorProfilePanel {
+
+ const PANELKEY = 'project.workboard';
+
+ protected function newNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config) {
+ $viewer = $this->getViewer();
+
+ // Workboards are only available if Maniphest is installed.
+ $class = 'PhabricatorManiphestApplication';
+ if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
+ return array();
+ }
+
+ $project = $config->getProfileObject();
+
+ $columns = id(new PhabricatorProjectColumnQuery())
+ ->setViewer($viewer)
+ ->withProjectPHIDs(array($project->getPHID()))
+ ->execute();
+ if ($columns) {
+ $icon = 'fa-columns';
+ } else {
+ $icon = 'fa-columns grey';
+ }
+
+ $id = $project->getID();
+ $href = "/project/board/{$id}/";
+ $name = pht('Workboard');
+
+ $item = id(new PHUIListItemView())
+ ->setRenderNameAsTooltip(true)
+ ->setType(PHUIListItemView::TYPE_ICON_NAV)
+ ->setHref($href)
+ ->setName($name)
+ ->setIcon($icon);
+
+ return array(
+ $item,
+ );
+ }
+
+}
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -10,7 +10,8 @@
PhabricatorCustomFieldInterface,
PhabricatorDestructibleInterface,
PhabricatorFulltextInterface,
- PhabricatorConduitResultInterface {
+ PhabricatorConduitResultInterface,
+ PhabricatorProfilePanelInterface {
protected $name;
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
@@ -49,6 +50,12 @@
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
+ const PANEL_PROFILE = 'project.profile';
+ const PANEL_WORKBOARD = 'project.workboard';
+ const PANEL_MEMBERS = 'project.members';
+ const PANEL_MILESTONES = 'project.milestones';
+ const PANEL_SUBPROJECTS = 'project.subprojects';
+
public static function initializeNewProject(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
@@ -644,4 +651,47 @@
return array();
}
+
+/* -( PhabricatorProfilePanelInterface )----------------------------------- */
+
+
+ public function getBuiltinProfilePanels() {
+ $panels = array();
+
+ $panels[] = id(new PhabricatorProfilePanelConfiguration())
+ ->setBuiltinKey(self::PANEL_PROFILE)
+ ->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY);
+
+ $panels[] = id(new PhabricatorProfilePanelConfiguration())
+ ->setBuiltinKey(self::PANEL_WORKBOARD)
+ ->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY);
+
+ // TODO: This is temporary.
+ $href = urisprintf(
+ '/maniphest/?statuses=open()&projects=%s#R',
+ $this->getPHID());
+
+ $panels[] = id(new PhabricatorProfilePanelConfiguration())
+ ->setBuiltinKey('tasks')
+ ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)
+ ->setPanelProperty('icon', 'fa-anchor')
+ ->setPanelProperty('name', pht('Open Tasks'))
+ ->setPanelProperty('href', $href);
+
+ // TODO: This is temporary.
+ $id = $this->getID();
+ $panels[] = id(new PhabricatorProfilePanelConfiguration())
+ ->setBuiltinKey('feed')
+ ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)
+ ->setPanelProperty('icon', 'fa-newspaper-o')
+ ->setPanelProperty('name', pht('Feed'))
+ ->setPanelProperty('href', "/project/feed/{$id}/");
+
+ $panels[] = id(new PhabricatorProfilePanelConfiguration())
+ ->setBuiltinKey(self::PANEL_MEMBERS)
+ ->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
+
+ return $panels;
+ }
+
}
diff --git a/src/applications/search/engine/PhabricatorProfilePanelEngine.php b/src/applications/search/engine/PhabricatorProfilePanelEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engine/PhabricatorProfilePanelEngine.php
@@ -0,0 +1,152 @@
+<?php
+
+final class PhabricatorProfilePanelEngine extends Phobject {
+
+ private $viewer;
+ private $profileObject;
+ private $panels;
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function setProfileObject(
+ PhabricatorProfilePanelInterface $profile_object) {
+ $this->profileObject = $profile_object;
+ return $this;
+ }
+
+ public function getProfileObject() {
+ return $this->profileObject;
+ }
+
+ public function buildNavigation() {
+ $nav = id(new AphrontSideNavFilterView())
+ ->setIconNav(true)
+ ->setBaseURI(new PhutilURI('/project/'));
+
+ $panels = $this->getPanels();
+
+ foreach ($panels as $panel) {
+ $items = $panel->buildNavigationMenuItems();
+ foreach ($items as $item) {
+ $this->validateNavigationMenuItem($item);
+ }
+
+ // If the panel produced only a single item which does not otherwise
+ // have a key, try to automatically assign it a reasonable key. This
+ // makes selecting the correct item simpler.
+
+ if (count($items) == 1) {
+ $item = head($items);
+ if ($item->getKey() === null) {
+ $builtin_key = $panel->getBuiltinKey();
+ $panel_phid = $panel->getPHID();
+ if ($builtin_key !== null) {
+ $item->setKey($builtin_key);
+ } else if ($panel_phid !== null) {
+ $item->setKey($panel_phid);
+ }
+ }
+ }
+
+ foreach ($items as $item) {
+ $nav->addMenuItem($item);
+ }
+ }
+
+ $nav->selectFilter(null);
+
+ return $nav;
+ }
+
+ private function getPanels() {
+ if ($this->panels === null) {
+ $this->panels = $this->loadPanels();
+ }
+
+ return $this->panels;
+ }
+
+ private function loadPanels() {
+ $viewer = $this->getViewer();
+
+ $panels = $this->loadBuiltinProfilePanels();
+
+ // TODO: Load persisted panels.
+
+ foreach ($panels as $panel) {
+ $impl = $panel->getPanel();
+
+ $impl->setViewer($viewer);
+ }
+
+ return $panels;
+ }
+
+ private function loadBuiltinProfilePanels() {
+ $object = $this->getProfileObject();
+ $builtins = $object->getBuiltinProfilePanels();
+
+ $panels = PhabricatorProfilePanel::getAllPanels();
+
+ $order = 1;
+ $map = array();
+ foreach ($builtins as $builtin) {
+ $builtin_key = $builtin->getBuiltinKey();
+
+ if (!$builtin_key) {
+ throw new Exception(
+ pht(
+ 'Object produced a builtin panel with no builtin panel key! '.
+ 'Builtin panels must have a unique key.'));
+ }
+
+ if (isset($map[$builtin_key])) {
+ throw new Exception(
+ pht(
+ 'Object produced two panels with the same builtin key ("%s"). '.
+ 'Each panel must have a unique builtin key.',
+ $builtin_key));
+ }
+
+ $panel_key = $builtin->getPanelKey();
+
+ $panel = idx($panels, $panel_key);
+ if (!$panel) {
+ throw new Exception(
+ pht(
+ 'Builtin panel ("%s") specifies a bad panel key ("%s"); there '.
+ 'is no corresponding panel implementation available.',
+ $builtin_key,
+ $panel_key));
+ }
+
+ $builtin
+ ->attachPanel($panel)
+ ->attachProfileObject($object)
+ ->setPanelOrder($order);
+
+ $map[$builtin_key] = $builtin;
+
+ $order++;
+ }
+
+ return $map;
+ }
+
+ private function validateNavigationMenuItem($item) {
+ if (!($item instanceof PHUIListItemView)) {
+ throw new Exception(
+ pht(
+ 'Expected buildNavigationMenuItems() to return a list of '.
+ 'PHUIListItemView objects, but got a surprise.'));
+ }
+ }
+
+}
diff --git a/src/applications/search/interface/PhabricatorProfilePanelInterface.php b/src/applications/search/interface/PhabricatorProfilePanelInterface.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/interface/PhabricatorProfilePanelInterface.php
@@ -0,0 +1,7 @@
+<?php
+
+interface PhabricatorProfilePanelInterface {
+
+ public function getBuiltinProfilePanels();
+
+}
diff --git a/src/applications/search/phidtype/PhabricatorProfilePanelPHIDType.php b/src/applications/search/phidtype/PhabricatorProfilePanelPHIDType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/phidtype/PhabricatorProfilePanelPHIDType.php
@@ -0,0 +1,40 @@
+<?php
+
+final class PhabricatorProfilePanelPHIDType
+ extends PhabricatorPHIDType {
+
+ const TYPECONST = 'PANL';
+
+ public function getTypeName() {
+ return pht('Profile Panel');
+ }
+
+ public function newObject() {
+ return new PhabricatorProfilePanelConfiguration();
+ }
+
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorSearchApplication';
+ }
+
+ protected function buildQueryForObjects(
+ PhabricatorObjectQuery $object_query,
+ array $phids) {
+ return id(new PhabricatorProfilePanelConfigurationQuery())
+ ->withPHIDs($phids);
+ }
+
+ public function loadHandles(
+ PhabricatorHandleQuery $query,
+ array $handles,
+ array $objects) {
+
+ foreach ($handles as $phid => $handle) {
+ $config = $objects[$phid];
+
+ $handle->setName(pht('Profile Panel'));
+ $handle->setURI($config->getURI());
+ }
+ }
+
+}
diff --git a/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php b/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php
@@ -0,0 +1,27 @@
+<?php
+
+final class PhabricatorLinkProfilePanel
+ extends PhabricatorProfilePanel {
+
+ const PANELKEY = 'link';
+
+ protected function newNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config) {
+
+ $icon = $config->getPanelProperty('icon');
+ $name = $config->getPanelProperty('name');
+ $href = $config->getPanelProperty('href');
+
+ $item = id(new PHUIListItemView())
+ ->setRenderNameAsTooltip(true)
+ ->setType(PHUIListItemView::TYPE_ICON_NAV)
+ ->setHref($href)
+ ->setName($name)
+ ->setIcon($icon);
+
+ return array(
+ $item,
+ );
+ }
+
+}
diff --git a/src/applications/search/profilepanel/PhabricatorProfilePanel.php b/src/applications/search/profilepanel/PhabricatorProfilePanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/profilepanel/PhabricatorProfilePanel.php
@@ -0,0 +1,35 @@
+<?php
+
+abstract class PhabricatorProfilePanel extends Phobject {
+
+ private $viewer;
+
+ final public function buildNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config) {
+ return $this->newNavigationMenuItems($config);
+ }
+
+ abstract protected function newNavigationMenuItems(
+ PhabricatorProfilePanelConfiguration $config);
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function getPanelKey() {
+ return $this->getPhobjectClassConstant('PANELKEY');
+ }
+
+ final public static function getAllPanels() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getPanelKey')
+ ->execute();
+ }
+
+}
diff --git a/src/applications/search/query/PhabricatorProfilePanelConfigurationQuery.php b/src/applications/search/query/PhabricatorProfilePanelConfigurationQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/query/PhabricatorProfilePanelConfigurationQuery.php
@@ -0,0 +1,64 @@
+<?php
+
+final class PhabricatorProfilePanelConfigurationQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $phids;
+ private $profileObjectPHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function withProfileObjectPHIDs(array $phids) {
+ $this->profileObjectPHIDs = $phids;
+ return $this;
+ }
+
+ public function newResultObject() {
+ return new PhabricatorProfilePanelConfiguration();
+ }
+
+ protected function loadPage() {
+ return $this->loadStandardPage($this->newResultObject());
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ if ($this->profileObjectPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'profileObjectPHID IN (%Ls)',
+ $this->profileObjectPHIDs);
+ }
+
+ return $where;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorSearchApplication';
+ }
+
+}
diff --git a/src/applications/search/storage/PhabricatorProfilePanelConfiguration.php b/src/applications/search/storage/PhabricatorProfilePanelConfiguration.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/storage/PhabricatorProfilePanelConfiguration.php
@@ -0,0 +1,124 @@
+<?php
+
+final class PhabricatorProfilePanelConfiguration
+ extends PhabricatorSearchDAO
+ implements
+ PhabricatorPolicyInterface,
+ PhabricatorExtendedPolicyInterface {
+
+ protected $profilePHID;
+ protected $panelKey;
+ protected $builtinKey;
+ protected $panelOrder;
+ protected $isDisabled;
+ protected $panelProperties = array();
+
+ private $profileObject = self::ATTACHABLE;
+ private $panel = self::ATTACHABLE;
+
+ public static function initializeNewPanelConfiguration(
+ PhabricatorProfilePanelInterface $profile_object,
+ PhabricatorProfilePanel $panel) {
+
+ return id(new self())
+ ->setProfilePHID($profile_object->getPHID())
+ ->setPanelKey($panel->getPanelKey())
+ ->setIsDisabled(0)
+ ->attachPanel($panel)
+ ->attachProfileObject($profile_object);
+ }
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_SERIALIZATION => array(
+ 'panelProperties' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'panelKey' => 'text64',
+ 'builtinKey' => 'text64',
+ 'panelOrder' => 'uint32',
+ 'isDisabled' => 'bool',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_profile' => array(
+ 'columns' => array('profilePHID', 'panelOrder'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function attachPanel(PhabricatorProfilePanel $panel) {
+ $this->panel = $panel;
+ return $this;
+ }
+
+ public function getPanel() {
+ return $this->assertAttached($this->panel);
+ }
+
+ public function attachProfileObject(
+ PhabricatorProfilePanelInterface $profile_object) {
+ $this->profileObject = $profile_object;
+ return $this;
+ }
+
+ public function getProfileObject() {
+ return $this->assertAttached($this->profileObject);
+ }
+
+ public function buildNavigationMenuItems() {
+ return $this->getPanel()->buildNavigationMenuItems($this);
+ }
+
+ public function setPanelProperty($key, $value) {
+ $this->panelProperties[$key] = $value;
+ return $this;
+ }
+
+ public function getPanelProperty($key, $default = null) {
+ return idx($this->panelProperties, $key, $default);
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+
+ public function getPolicy($capability) {
+ return PhabricatorPolicies::getMostOpenPolicy();
+ }
+
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return $this->getProfileObject()->hasAutomaticCapability(
+ $capability,
+ $viewer);
+ }
+
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
+
+
+/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
+
+
+ public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
+ return array(
+ array(
+ $this->getProfileObject(),
+ $capability,
+ ),
+ );
+ }
+
+}
diff --git a/src/applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php b/src/applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php
@@ -0,0 +1,18 @@
+<?php
+
+final class PhabricatorProfilePanelConfigurationTransaction
+ extends PhabricatorApplicationTransaction {
+
+ public function getApplicationName() {
+ return 'search';
+ }
+
+ public function getApplicationTransactionType() {
+ return PhabricatorProfilePanelPHIDType::TYPECONST;
+ }
+
+ public function getApplicationTransactionCommentObject() {
+ return null;
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 15, 5:26 PM (3 d, 13 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6710544
Default Alt Text
D15007.diff (34 KB)

Event Timeline