Modularize application configuration panels
Summary: Ref T7149. This is a few steps away, but: - Generally, I'd like to reduce the amount of "Config" configuration we have. - One good way to do this is to move it into UIs in Application configuration. We did this with email recently. - I think this was a great change and I'd like to keep moving in this direction. - T7149 touches configuration related to file storage engines. Although I'm not planning to fully move configuration into applications yet, it would be easier to debug and test if I could drop a read-only panel there to show engines. - So, modularize the config stuff so I can add a new panel without hard-coding it. Test Plan: - Added, edited, and deleted application emails. - Viewed non-email application detail pages. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T7149 Differential Revision: https://secure.phabricator.com/D12051
This commit is contained in:
@@ -1269,11 +1269,12 @@ phutil_register_library_map(array(
|
||||
'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php',
|
||||
'PhabricatorApplicationApplicationPHIDType' => 'applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php',
|
||||
'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php',
|
||||
'PhabricatorApplicationConfigurationPanel' => 'applications/meta/panel/PhabricatorApplicationConfigurationPanel.php',
|
||||
'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php',
|
||||
'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php',
|
||||
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
|
||||
'PhabricatorApplicationEditEmailController' => 'applications/meta/controller/PhabricatorApplicationEditEmailController.php',
|
||||
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
|
||||
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
|
||||
'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php',
|
||||
'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php',
|
||||
'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php',
|
||||
@@ -1988,6 +1989,7 @@ phutil_register_library_map(array(
|
||||
'PhabricatorMetaMTAApplicationEmail' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php',
|
||||
'PhabricatorMetaMTAApplicationEmailDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php',
|
||||
'PhabricatorMetaMTAApplicationEmailPHIDType' => 'applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php',
|
||||
'PhabricatorMetaMTAApplicationEmailPanel' => 'applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php',
|
||||
'PhabricatorMetaMTAApplicationEmailQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php',
|
||||
'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php',
|
||||
'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php',
|
||||
@@ -4510,11 +4512,12 @@ phutil_register_library_map(array(
|
||||
'PhabricatorApplication' => 'PhabricatorPolicyInterface',
|
||||
'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorApplicationConfigOptions' => 'Phobject',
|
||||
'PhabricatorApplicationConfigurationPanel' => 'Phobject',
|
||||
'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationEditEmailController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationLaunchView' => 'AphrontTagView',
|
||||
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController',
|
||||
'PhabricatorApplicationStatusView' => 'AphrontView',
|
||||
@@ -5272,6 +5275,7 @@ phutil_register_library_map(array(
|
||||
),
|
||||
'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorMetaMTAApplicationEmailPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorMetaMTAApplicationEmailPanel' => 'PhabricatorApplicationConfigurationPanel',
|
||||
'PhabricatorMetaMTAApplicationEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorMetaMTAController' => 'PhabricatorController',
|
||||
|
||||
@@ -41,10 +41,10 @@ final class PhabricatorApplicationsApplication extends PhabricatorApplication {
|
||||
=> 'PhabricatorApplicationDetailViewController',
|
||||
'edit/(?P<application>\w+)/'
|
||||
=> 'PhabricatorApplicationEditController',
|
||||
'editemail/(?P<application>\w+)/'
|
||||
=> 'PhabricatorApplicationEditEmailController',
|
||||
'(?P<application>\w+)/(?P<action>install|uninstall)/'
|
||||
=> 'PhabricatorApplicationUninstallController',
|
||||
'panel/(?P<application>\w+)/(?P<panel>\w+)/(?P<path>.*)'
|
||||
=> 'PhabricatorApplicationPanelController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ final class PhabricatorApplicationDetailViewController
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
$viewer = $this->getViewer();
|
||||
$application = $request->getURIData('application');
|
||||
|
||||
$selected = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withClasses(array($application))
|
||||
->executeOne();
|
||||
if (!$selected) {
|
||||
@@ -27,7 +27,7 @@ final class PhabricatorApplicationDetailViewController
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setPolicyObject($selected);
|
||||
|
||||
if ($selected->isInstalled()) {
|
||||
@@ -36,17 +36,30 @@ final class PhabricatorApplicationDetailViewController
|
||||
$header->setStatus('fa-ban', 'dark', pht('Uninstalled'));
|
||||
}
|
||||
|
||||
$actions = $this->buildActionView($user, $selected);
|
||||
$actions = $this->buildActionView($viewer, $selected);
|
||||
$properties = $this->buildPropertyView($selected, $actions);
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
|
||||
$configs =
|
||||
PhabricatorApplicationConfigurationPanel::loadAllPanelsForApplication(
|
||||
$selected);
|
||||
|
||||
$panels = array();
|
||||
foreach ($configs as $config) {
|
||||
$config->setViewer($viewer);
|
||||
$config->setApplication($selected);
|
||||
|
||||
$panels[] = $config->buildConfigurationPagePanel();
|
||||
}
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$object_box,
|
||||
$panels,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
@@ -114,26 +127,6 @@ final class PhabricatorApplicationDetailViewController
|
||||
idx($descriptions, $capability));
|
||||
}
|
||||
|
||||
if ($application->supportsEmailIntegration()) {
|
||||
$properties->addSectionHeader(pht('Application Emails'));
|
||||
$properties->addTextContent($application->getAppEmailBlurb());
|
||||
$email_addresses = id(new PhabricatorMetaMTAApplicationEmailQuery())
|
||||
->setViewer($viewer)
|
||||
->withApplicationPHIDs(array($application->getPHID()))
|
||||
->execute();
|
||||
if (empty($email_addresses)) {
|
||||
$properties->addProperty(
|
||||
null,
|
||||
pht('No email addresses configured.'));
|
||||
} else {
|
||||
foreach ($email_addresses as $email_address) {
|
||||
$properties->addProperty(
|
||||
null,
|
||||
$email_address->getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
@@ -168,18 +161,6 @@ final class PhabricatorApplicationDetailViewController
|
||||
->setWorkflow(!$can_edit)
|
||||
->setHref($edit_uri));
|
||||
|
||||
if ($selected->supportsEmailIntegration()) {
|
||||
$edit_email_uri = $this->getApplicationURI(
|
||||
'editemail/'.get_class($selected).'/');
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Application Emails'))
|
||||
->setIcon('fa-envelope')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setHref($edit_email_uri));
|
||||
}
|
||||
|
||||
if ($selected->canUninstall()) {
|
||||
if ($selected->isInstalled()) {
|
||||
$view->addAction(
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorApplicationPanelController
|
||||
extends PhabricatorApplicationsController {
|
||||
|
||||
private $application;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$application = $request->getURIData('application');
|
||||
$panel_key = $request->getURIData('panel');
|
||||
|
||||
$selected = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($viewer)
|
||||
->withClasses(array($application))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$selected) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$panels =
|
||||
PhabricatorApplicationConfigurationPanel::loadAllPanelsForApplication(
|
||||
$selected);
|
||||
if (empty($panels[$panel_key])) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$panel = $panels[$panel_key];
|
||||
|
||||
if (!$panel->shouldShowForApplication($selected)) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$panel->setViewer($viewer);
|
||||
$panel->setApplication($selected);
|
||||
|
||||
$this->application = $selected;
|
||||
|
||||
return $panel->handlePanelRequest($request, $this);
|
||||
}
|
||||
|
||||
public function buildPanelCrumbs(
|
||||
PhabricatorApplicationConfigurationPanel $panel) {
|
||||
$application = $this->application;
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
$view_uri = '/applications/view/'.get_class($application).'/';
|
||||
$crumbs->addTextCrumb($application->getName(), $view_uri);
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
public function buildPanelPage(
|
||||
PhabricatorApplicationConfigurationPanel $panel,
|
||||
$content,
|
||||
array $options) {
|
||||
return $this->buildApplicationPage($content, $options);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
abstract class PhabricatorApplicationConfigurationPanel
|
||||
extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
private $application;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setApplication(PhabricatorApplication $application) {
|
||||
$this->application = $application;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApplication() {
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
public function getPanelURI($path = null) {
|
||||
$app_key = get_class($this->getApplication());
|
||||
$panel_key = $this->getPanelKey();
|
||||
$base = "/applications/panel/{$app_key}/{$panel_key}/";
|
||||
return $base.ltrim($path, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a short, unique string key which identifies this panel.
|
||||
*
|
||||
* This key is used in URIs. Good values might be "email" or "files".
|
||||
*/
|
||||
abstract public function getPanelKey();
|
||||
|
||||
abstract public function shouldShowForApplication(
|
||||
PhabricatorApplication $application);
|
||||
|
||||
abstract public function buildConfigurationPagePanel();
|
||||
abstract public function handlePanelRequest(
|
||||
AphrontRequest $request,
|
||||
PhabricatorController $controller);
|
||||
|
||||
public static function loadAllPanels() {
|
||||
$objects = id(new PhutilSymbolLoader())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->loadObjects();
|
||||
|
||||
$panels = array();
|
||||
foreach ($objects as $object) {
|
||||
$key = $object->getPanelKey();
|
||||
if (empty($panels[$key])) {
|
||||
$panels[$key] = $object;
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Application configuration panels "%s" and "%s" have the same '.
|
||||
'panel key, "%s". Each panel must have a unique key.',
|
||||
get_class($object),
|
||||
get_class($panels[$key]),
|
||||
$key));
|
||||
}
|
||||
}
|
||||
|
||||
return $panels;
|
||||
}
|
||||
|
||||
public static function loadAllPanelsForApplication(
|
||||
PhabricatorApplication $application) {
|
||||
$panels = self::loadAllPanels();
|
||||
|
||||
$application_panels = array();
|
||||
foreach ($panels as $key => $panel) {
|
||||
if (!$panel->shouldShowForApplication($application)) {
|
||||
continue;
|
||||
}
|
||||
$application_panels[$key] = $panel;
|
||||
}
|
||||
|
||||
return $application_panels;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,76 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorApplicationEditEmailController
|
||||
extends PhabricatorApplicationsController {
|
||||
final class PhabricatorMetaMTAApplicationEmailPanel
|
||||
extends PhabricatorApplicationConfigurationPanel {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$application = $request->getURIData('application');
|
||||
public function getPanelKey() {
|
||||
return 'email';
|
||||
}
|
||||
|
||||
$application = id(new PhabricatorApplicationQuery())
|
||||
public function shouldShowForApplication(
|
||||
PhabricatorApplication $application) {
|
||||
return $application->supportsEmailIntegration();
|
||||
}
|
||||
|
||||
public function buildConfigurationPagePanel() {
|
||||
$viewer = $this->getViewer();
|
||||
$application = $this->getApplication();
|
||||
|
||||
$addresses = id(new PhabricatorMetaMTAApplicationEmailQuery())
|
||||
->setViewer($viewer)
|
||||
->withClasses(array($application))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$application) {
|
||||
return new Aphront404Response();
|
||||
->withApplicationPHIDs(array($application->getPHID()))
|
||||
->execute();
|
||||
|
||||
$rows = array();
|
||||
foreach ($addresses as $address) {
|
||||
$rows[] = array(
|
||||
$address->getAddress(),
|
||||
);
|
||||
}
|
||||
|
||||
$title = $application->getName();
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setNoDataString(pht('No email addresses configured.'))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Address'),
|
||||
));
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$application,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Application Emails'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Edit Application Emails'))
|
||||
->setIcon(
|
||||
id(new PHUIIconView())
|
||||
->setIconFont('fa-pencil'))
|
||||
->setHref($this->getPanelURI())
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($table);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
public function handlePanelRequest(
|
||||
AphrontRequest $request,
|
||||
PhabricatorController $controller) {
|
||||
$viewer = $request->getViewer();
|
||||
$application = $this->getApplication();
|
||||
|
||||
$path = $request->getURIData('path');
|
||||
if (strlen($path)) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$uri = $request->getRequestURI();
|
||||
$uri->setQueryParams(array());
|
||||
@@ -106,13 +156,12 @@ final class PhabricatorApplicationEditEmailController
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer);
|
||||
|
||||
$view_uri = $this->getApplicationURI('view/'.get_class($application).'/');
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($application->getName(), $view_uri);
|
||||
$crumbs = $controller->buildPanelCrumbs($this);
|
||||
$crumbs->addTextCrumb(pht('Edit Application Emails'));
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Edit Application Emails: %s', $application->getName()));
|
||||
->setHeader(pht('Edit Application Emails: %s', $application->getName()))
|
||||
->setSubheader($application->getAppEmailBlurb());
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIconFont('fa-plus');
|
||||
@@ -126,13 +175,12 @@ final class PhabricatorApplicationEditEmailController
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($table)
|
||||
->appendChild(
|
||||
id(new PHUIBoxView())
|
||||
->appendChild($application->getAppEmailBlurb())
|
||||
->addPadding(PHUI::PADDING_MEDIUM));
|
||||
->appendChild($table);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$title = $application->getName();
|
||||
|
||||
return $controller->buildPanelPage(
|
||||
$this,
|
||||
array(
|
||||
$crumbs,
|
||||
$object_box,
|
||||
@@ -253,7 +301,10 @@ final class PhabricatorApplicationEditEmailController
|
||||
|
||||
$default_user = $email_object->getConfigValue($default_user_key);
|
||||
if ($default_user) {
|
||||
$default_user_handle = $this->loadViewerHandles(array($default_user));
|
||||
$default_user_handle = id(new PhabricatorHandleQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($default_user))
|
||||
->execute();
|
||||
} else {
|
||||
$default_user_handle = array();
|
||||
}
|
||||
Reference in New Issue
Block a user