From 51f2ed498dbff6db75ae1423fc45d7bce3d5d969 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Apr 2019 11:35:34 -0700 Subject: [PATCH] On panel pages, show where panels are used Summary: Depends on D20398. Ref T13272. Fixes T6018. Previously, panels showed "used on dashboards: x, y", but this did not include cases where a panel was used by another container panel (today, a tab panel). Do edge indexing when a dashboard or panel is saved, then pull the edges on the Panel page so we can provide a full list of uses. Test Plan: {F6369289} Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13272, T6018 Differential Revision: https://secure.phabricator.com/D20399 --- resources/celerity/map.php | 6 +-- src/__phutil_library_map__.php | 9 ++++ .../PhabricatorDashboardViewController.php | 2 + ...habricatorDashboardPanelViewController.php | 50 +++++++++++++++++++ ...ricatorDashboardPanelTransactionEditor.php | 4 ++ .../PhabricatorDashboardTransactionEditor.php | 3 ++ ...oardPanelContainerIndexEngineExtension.php | 28 +++++++++++ ...icatorDashboardPanelContainerInterface.php | 12 +++++ .../PhabricatorDashboardPanelType.php | 4 ++ .../PhabricatorDashboardTabsPanelType.php | 22 +++++++- .../PhabricatorDashboardPanelPHIDType.php | 8 +-- .../query/PhabricatorDashboardPanelQuery.php | 12 ++--- .../storage/PhabricatorDashboard.php | 11 +++- .../storage/PhabricatorDashboardPanel.php | 9 +++- ...atorDashboardPanelUsedByObjectEdgeType.php | 16 ++++++ ...icatorObjectUsesDashboardPanelEdgeType.php | 16 ++++++ webroot/rsrc/css/aphront/table-view.css | 3 ++ 17 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 src/applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php create mode 100644 src/applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.php create mode 100644 src/applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php create mode 100644 src/applications/search/edge/PhabricatorObjectUsesDashboardPanelEdgeType.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 1b093a1a9e..0088b09935 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.js' => '020aebcf', - 'core.pkg.css' => '1db0892b', + 'core.pkg.css' => '294e365c', 'core.pkg.js' => '794952ae', 'differential.pkg.css' => '8d8360fb', 'differential.pkg.js' => '67e02996', @@ -30,7 +30,7 @@ return array( 'rsrc/css/aphront/notification.css' => '30240bd2', 'rsrc/css/aphront/panel-view.css' => '46923d46', 'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf', - 'rsrc/css/aphront/table-view.css' => '7dc3a9c2', + 'rsrc/css/aphront/table-view.css' => '5f13a9e4', 'rsrc/css/aphront/tokenizer.css' => 'b52d0668', 'rsrc/css/aphront/tooltip.css' => 'e3f2412f', 'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2', @@ -531,7 +531,7 @@ return array( 'aphront-list-filter-view-css' => 'feb64255', 'aphront-multi-column-view-css' => 'fbc00ba3', 'aphront-panel-view-css' => '46923d46', - 'aphront-table-view-css' => '7dc3a9c2', + 'aphront-table-view-css' => '5f13a9e4', 'aphront-tokenizer-control-css' => 'b52d0668', 'aphront-tooltip-css' => 'e3f2412f', 'aphront-typeahead-control-css' => '8779483d', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4c1e7e5459..712405c4dd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2930,6 +2930,8 @@ phutil_register_library_map(array( 'PhabricatorDashboardObjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php', 'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php', 'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelArchiveController.php', + 'PhabricatorDashboardPanelContainerIndexEngineExtension' => 'applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php', + 'PhabricatorDashboardPanelContainerInterface' => 'applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.php', 'PhabricatorDashboardPanelDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php', 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPanelEditConduitAPIMethod.php', 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php', @@ -2951,6 +2953,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php', 'PhabricatorDashboardPanelTransactionType' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php', 'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php', + 'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardPortal' => 'applications/dashboard/storage/PhabricatorDashboardPortal.php', 'PhabricatorDashboardPortalController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalController.php', @@ -3724,6 +3727,7 @@ phutil_register_library_map(array( 'PhabricatorObjectRemarkupRule' => 'infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php', 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 'PhabricatorObjectStatus' => 'infrastructure/status/PhabricatorObjectStatus.php', + 'PhabricatorObjectUsesDashboardPanelEdgeType' => 'applications/search/edge/PhabricatorObjectUsesDashboardPanelEdgeType.php', 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php', 'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php', @@ -8888,6 +8892,7 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', 'PhabricatorNgramsInterface', + 'PhabricatorDashboardPanelContainerInterface', ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', @@ -8918,8 +8923,10 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', + 'PhabricatorDashboardPanelContainerInterface', ), 'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardPanelContainerIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension', 'PhabricatorDashboardPanelDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController', @@ -8941,6 +8948,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPanelTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorDashboardPanelType' => 'Phobject', + 'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPortal' => array( 'PhabricatorDashboardDAO', @@ -9799,6 +9807,7 @@ phutil_register_library_map(array( 'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorObjectSelectorDialog' => 'Phobject', 'PhabricatorObjectStatus' => 'Phobject', + 'PhabricatorObjectUsesDashboardPanelEdgeType' => 'PhabricatorEdgeType', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource', 'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting', diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php index c7b306504f..77de8df128 100644 --- a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php @@ -172,6 +172,8 @@ final class PhabricatorDashboardViewController } $usage_table = id(new AphrontTableView($rows)) + ->setNoDataString( + pht('This dashboard has not been added to any menus.')) ->setHeaders( array( null, diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php index e2e7727c2d..e06d5716f4 100644 --- a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php +++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php @@ -35,6 +35,8 @@ final class PhabricatorDashboardPanelViewController $header = $this->buildHeaderView($panel); $curtain = $this->buildCurtainView($panel); + $usage_box = $this->newUsageView($panel); + $timeline = $this->buildTransactionTimeline( $panel, new PhabricatorDashboardPanelTransactionQuery()); @@ -57,6 +59,7 @@ final class PhabricatorDashboardPanelViewController ->setCurtain($curtain) ->setMainColumn(array( $rendered_panel, + $usage_box, $timeline, )); @@ -122,4 +125,51 @@ final class PhabricatorDashboardPanelViewController return $curtain; } + private function newUsageView(PhabricatorDashboardPanel $panel) { + $viewer = $this->getViewer(); + + $object_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $panel->getPHID(), + PhabricatorDashboardPanelUsedByObjectEdgeType::EDGECONST); + + if ($object_phids) { + $handles = $viewer->loadHandles($object_phids); + } else { + $handles = array(); + } + + $rows = array(); + foreach ($object_phids as $object_phid) { + $handle = $handles[$object_phid]; + + $icon = $handle->getIcon(); + + $rows[] = array( + id(new PHUIIconView())->setIcon($icon), + $handle->getTypeName(), + $handle->renderLink(), + ); + } + + $usage_table = id(new AphrontTableView($rows)) + ->setNoDataString( + pht( + 'This panel is not used on any dashboard or inside any other '. + 'panel container.')) + ->setColumnClasses( + array( + 'center', + '', + 'pri wide', + )); + + $header_view = id(new PHUIHeaderView()) + ->setHeader(pht('Panel Used By')); + + $usage_box = id(new PHUIObjectBoxView()) + ->setTable($usage_table) + ->setHeader($header_view); + + return $usage_box; + } } diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php index bc7b78c20e..ea03c1ac7d 100644 --- a/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php +++ b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php @@ -21,4 +21,8 @@ final class PhabricatorDashboardPanelTransactionEditor return $types; } + protected function supportsSearch() { + return true; + } + } diff --git a/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php b/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php index 792f6f9aa5..e38ccfdd94 100644 --- a/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php +++ b/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php @@ -178,5 +178,8 @@ final class PhabricatorDashboardTransactionEditor return $errors; } + protected function supportsSearch() { + return true; + } } diff --git a/src/applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php b/src/applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php new file mode 100644 index 0000000000..8fa3cffb53 --- /dev/null +++ b/src/applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php @@ -0,0 +1,28 @@ +getDashboardPanelContainerPanelPHIDs(); + } + +} diff --git a/src/applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.php b/src/applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.php new file mode 100644 index 0000000000..02ad2c2740 --- /dev/null +++ b/src/applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.php @@ -0,0 +1,12 @@ + + */ + public function getDashboardPanelContainerPanelPHIDs(); + +} diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php index 6a8a3cfc7e..8f9134e642 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php @@ -59,4 +59,8 @@ abstract class PhabricatorDashboardPanelType extends Phobject { abstract protected function newEditEngineFields( PhabricatorDashboardPanel $panel); + public function getSubpanelPHIDs(PhabricatorDashboardPanel $panel) { + return array(); + } + } diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php index 3a5618332c..5d203b292f 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php @@ -105,7 +105,7 @@ final class PhabricatorDashboardTabsPanelType $tab_view = id(new PHUIListItemView()) ->setHref('#') - ->setSelected($idx == $selected) + ->setSelected((string)$idx === (string)$selected) ->addSigil('dashboard-tab-panel-tab') ->setMetadata(array('panelKey' => $idx)) ->setName($name); @@ -292,4 +292,24 @@ final class PhabricatorDashboardTabsPanelType )); } + public function getSubpanelPHIDs(PhabricatorDashboardPanel $panel) { + $config = $this->getPanelConfiguration($panel); + + $panel_ids = array(); + foreach ($config as $tab_key => $tab_spec) { + $panel_ids[] = $tab_spec['panelID']; + } + + if ($panel_ids) { + $panels = id(new PhabricatorDashboardPanelQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withIDs($panel_ids) + ->execute(); + } else { + $panels = array(); + } + + return mpull($panels, 'getPHID'); + } + } diff --git a/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php b/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php index 49a5091412..d84db72a25 100644 --- a/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php +++ b/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php @@ -35,9 +35,11 @@ final class PhabricatorDashboardPanelPHIDType extends PhabricatorPHIDType { $name = $panel->getName(); $monogram = $panel->getMonogram(); - $handle->setName($panel->getMonogram()); - $handle->setFullName("{$monogram} {$name}"); - $handle->setURI("/{$monogram}"); + $handle + ->setIcon('fa-window-maximize') + ->setName($name) + ->setFullName("{$monogram} {$name}") + ->setURI($panel->getURI()); if ($panel->getIsArchived()) { $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); diff --git a/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php b/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php index ac72c9ce6f..65f698cec9 100644 --- a/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php +++ b/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php @@ -62,35 +62,35 @@ final class PhabricatorDashboardPanelQuery if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ld)', + 'panel.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'panel.phid IN (%Ls)', $this->phids); } if ($this->archived !== null) { $where[] = qsprintf( $conn, - 'isArchived = %d', + 'panel.isArchived = %d', (int)$this->archived); } if ($this->panelTypes !== null) { $where[] = qsprintf( $conn, - 'panelType IN (%Ls)', + 'panel.panelType IN (%Ls)', $this->panelTypes); } if ($this->authorPHIDs !== null) { $where[] = qsprintf( $conn, - 'authorPHID IN (%Ls)', + 'panel.authorPHID IN (%Ls)', $this->authorPHIDs); } @@ -102,7 +102,7 @@ final class PhabricatorDashboardPanelQuery } protected function getPrimaryTableAlias() { - return 'dashboard_panel'; + return 'panel'; } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboard.php b/src/applications/dashboard/storage/PhabricatorDashboard.php index 09df91e684..9c5120030f 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboard.php +++ b/src/applications/dashboard/storage/PhabricatorDashboard.php @@ -10,7 +10,8 @@ final class PhabricatorDashboard extends PhabricatorDashboardDAO PhabricatorFlaggableInterface, PhabricatorDestructibleInterface, PhabricatorProjectInterface, - PhabricatorNgramsInterface { + PhabricatorNgramsInterface, + PhabricatorDashboardPanelContainerInterface { protected $name; protected $authorPHID; @@ -191,4 +192,12 @@ final class PhabricatorDashboard extends PhabricatorDashboardDAO ); } +/* -( PhabricatorDashboardPanelContainerInterface )------------------------ */ + + public function getDashboardPanelContainerPanelPHIDs() { + return PhabricatorEdgeQuery::loadDestinationPHIDs( + $this->getPHID(), + PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST); + } + } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php index a204a543f5..ef14786c4b 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php @@ -10,7 +10,8 @@ final class PhabricatorDashboardPanel PhabricatorPolicyInterface, PhabricatorFlaggableInterface, PhabricatorDestructibleInterface, - PhabricatorNgramsInterface { + PhabricatorNgramsInterface, + PhabricatorDashboardPanelContainerInterface { protected $name; protected $panelType; @@ -165,4 +166,10 @@ final class PhabricatorDashboardPanel ); } +/* -( PhabricatorDashboardPanelContainerInterface )------------------------ */ + + public function getDashboardPanelContainerPanelPHIDs() { + return $this->requireImplementation()->getSubpanelPHIDs($this); + } + } diff --git a/src/applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php b/src/applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php new file mode 100644 index 0000000000..f811b8b15d --- /dev/null +++ b/src/applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php @@ -0,0 +1,16 @@ +" and "" so that the header widths + are correct if the table has no rows. */ +.aphront-table-view th.wide, .aphront-table-view td.wide { white-space: normal; width: 100%;