Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14050219
D15007.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
34 KB
Referenced Files
None
Subscribers
None
D15007.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D15007: Begin modularizing profile panel/link construction
Attached
Detach File
Event Timeline
Log In to Comment