1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 06:42:42 +01:00

Make the "Install Dashboard" flow smoother

Summary:
Depends on D20362. Ref T13272. Currently, Dashboards have an "Install Dashboard" flow which is pretty janky and only allows you to install things to the home page.

Instead, allow users to install things to any valid target (home, favorites, portals, projects). This also provides URIs like `dashboard/install/1/home/personal/` which allow you to link users to an "install a dashboard" page; this may or may not get used.

Test Plan: Installed dashboards on home, favorites, projects, and portals.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13272

Differential Revision: https://secure.phabricator.com/D20364
This commit is contained in:
epriestley 2019-04-01 10:25:24 -07:00
parent eea093bec8
commit 12b9224387
17 changed files with 730 additions and 126 deletions

View file

@ -9,7 +9,7 @@ return array(
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => 'a1c2d49b',
'core.pkg.css' => '3b565a84',
'core.pkg.js' => 'a568e834',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
@ -128,7 +128,7 @@ return array(
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'ccd7e4e2',
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'cb758c42',
'rsrc/css/phui/calendar/phui-calendar.css' => 'f11073aa',
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '534f1757',
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => 'fa74cc35',
'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
@ -849,7 +849,7 @@ return array(
'phui-lightbox-css' => '4ebf22da',
'phui-list-view-css' => '470b1adb',
'phui-object-box-css' => 'f434b6be',
'phui-oi-big-ui-css' => '534f1757',
'phui-oi-big-ui-css' => 'fa74cc35',
'phui-oi-color-css' => 'b517bfa0',
'phui-oi-drag-ui-css' => 'da15d3dc',
'phui-oi-flush-ui-css' => '490e2e2e',
@ -1379,9 +1379,6 @@ return array(
'javelin-dom',
'javelin-fx',
),
'534f1757' => array(
'phui-oi-list-view-css',
),
'541f81c3' => array(
'javelin-install',
),
@ -2179,6 +2176,9 @@ return array(
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
'fa74cc35' => array(
'phui-oi-list-view-css',
),
'fdc13e4e' => array(
'javelin-install',
),

View file

@ -2905,6 +2905,7 @@ phutil_register_library_map(array(
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php',
'PhabricatorDashboardApplicationInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php',
'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php',
'PhabricatorDashboardConsoleController' => 'applications/dashboard/controller/PhabricatorDashboardConsoleController.php',
'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php',
@ -2913,13 +2914,17 @@ phutil_register_library_map(array(
'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php',
'PhabricatorDashboardDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardDatasource.php',
'PhabricatorDashboardEditController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php',
'PhabricatorDashboardFavoritesInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php',
'PhabricatorDashboardHomeInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php',
'PhabricatorDashboardIconSet' => 'applications/dashboard/icon/PhabricatorDashboardIconSet.php',
'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php',
'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php',
'PhabricatorDashboardInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php',
'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php',
'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php',
'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php',
'PhabricatorDashboardNgrams' => 'applications/dashboard/storage/PhabricatorDashboardNgrams.php',
'PhabricatorDashboardObjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php',
'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php',
'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php',
'PhabricatorDashboardPanelCoreCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php',
@ -2947,10 +2952,12 @@ phutil_register_library_map(array(
'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php',
'PhabricatorDashboardPortal' => 'applications/dashboard/storage/PhabricatorDashboardPortal.php',
'PhabricatorDashboardPortalController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalController.php',
'PhabricatorDashboardPortalDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php',
'PhabricatorDashboardPortalEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPortalEditConduitAPIMethod.php',
'PhabricatorDashboardPortalEditController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalEditController.php',
'PhabricatorDashboardPortalEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php',
'PhabricatorDashboardPortalEditor' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditor.php',
'PhabricatorDashboardPortalInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php',
'PhabricatorDashboardPortalListController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalListController.php',
'PhabricatorDashboardPortalMenuItem' => 'applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php',
'PhabricatorDashboardPortalNameTransaction' => 'applications/dashboard/xaction/portal/PhabricatorDashboardPortalNameTransaction.php',
@ -2966,6 +2973,7 @@ phutil_register_library_map(array(
'PhabricatorDashboardPortalViewController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php',
'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php',
'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php',
'PhabricatorDashboardProjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php',
'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php',
'PhabricatorDashboardQueryPanelInstallController' => 'applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php',
'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php',
@ -8865,6 +8873,7 @@ phutil_register_library_map(array(
),
'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardApplication' => 'PhabricatorApplication',
'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController',
'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController',
'PhabricatorDashboardController' => 'PhabricatorController',
@ -8873,13 +8882,17 @@ phutil_register_library_map(array(
'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType',
'PhabricatorDashboardDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardEditController' => 'PhabricatorDashboardController',
'PhabricatorDashboardFavoritesInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
'PhabricatorDashboardHomeInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
'PhabricatorDashboardIconSet' => 'PhabricatorIconSet',
'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO',
'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController',
'PhabricatorDashboardInstallWorkflow' => 'Phobject',
'PhabricatorDashboardLayoutConfig' => 'Phobject',
'PhabricatorDashboardListController' => 'PhabricatorDashboardController',
'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorDashboardObjectInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardPanel' => array(
'PhabricatorDashboardDAO',
'PhabricatorApplicationTransactionInterface',
@ -8923,10 +8936,12 @@ phutil_register_library_map(array(
'PhabricatorDestructibleInterface',
),
'PhabricatorDashboardPortalController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPortalDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardPortalEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorDashboardPortalEditController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine',
'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardPortalInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType',
@ -8942,6 +8957,7 @@ phutil_register_library_map(array(
'PhabricatorDashboardPortalViewController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardProfileController' => 'PhabricatorController',
'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDashboardProjectInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController',
'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType',

View file

@ -43,7 +43,10 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
'archive/(?P<id>\d+)/' => 'PhabricatorDashboardArchiveController',
'create/' => 'PhabricatorDashboardEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
'install/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardInstallController',
'install/(?P<id>\d+)/'.
'(?:(?P<workflowKey>[^/]+)/'.
'(?:(?P<modeKey>[^/]+)/)?)?' =>
'PhabricatorDashboardInstallController',
'console/' => 'PhabricatorDashboardConsoleController',
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',

View file

@ -3,6 +3,17 @@
final class PhabricatorDashboardInstallController
extends PhabricatorDashboardController {
private $dashboard;
public function setDashboard(PhabricatorDashboard $dashboard) {
$this->dashboard = $dashboard;
return $this;
}
public function getDashboard() {
return $this->dashboard;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
@ -15,126 +26,50 @@ final class PhabricatorDashboardInstallController
return new Aphront404Response();
}
$this->setDashboard($dashboard);
$cancel_uri = $dashboard->getURI();
$home_app = new PhabricatorHomeApplication();
$workflow_key = $request->getURIData('workflowKey');
$options = array();
$options['home'] = array(
'personal' =>
array(
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
'application' => $home_app,
'name' => pht('Personal Dashboard'),
'value' => 'personal',
'description' => pht('Places this dashboard as a menu item on home '.
'as a personal menu item. It will only be on your personal '.
'home.'),
),
'global' =>
array(
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'application' => $home_app,
'name' => pht('Global Dashboard'),
'value' => 'global',
'description' => pht('Places this dashboard as a menu item on home '.
'as a global menu item. It will be available to all users.'),
),
);
$errors = array();
$v_name = null;
if ($request->isFormPost()) {
$menuitem = new PhabricatorDashboardProfileMenuItem();
$dashboard_phid = $dashboard->getPHID();
$home = new PhabricatorHomeApplication();
$v_name = $request->getStr('name');
$v_home = $request->getStr('home');
if ($v_home) {
$application = $options['home'][$v_home]['application'];
$capability = $options['home'][$v_home]['capability'];
$can_edit_home = PhabricatorPolicyFilter::hasCapability(
$viewer,
$application,
$capability);
if (!$can_edit_home) {
$errors[] = pht(
'You do not have permission to install a dashboard on home.');
}
} else {
$errors[] = pht(
'You must select a destination to install this dashboard.');
}
$v_phid = $viewer->getPHID();
if ($v_home == 'global') {
$v_phid = null;
}
if (!$errors) {
$install = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
$home,
$menuitem,
$v_phid);
$install->setMenuItemProperty('dashboardPHID', $dashboard_phid);
$install->setMenuItemProperty('name', $v_name);
$install->setMenuItemOrder(1);
$xactions = array();
$editor = id(new PhabricatorProfileMenuEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request);
$editor->applyTransactions($install, $xactions);
$view_uri = '/home/menu/view/'.$install->getID().'/';
return id(new AphrontRedirectResponse())->setURI($view_uri);
}
$workflows = PhabricatorDashboardInstallWorkflow::getAllWorkflows();
if (!isset($workflows[$workflow_key])) {
return $this->newWorkflowDialog($dashboard, $workflows);
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Menu Label'))
->setName('name')
->setValue($v_name));
return id(clone $workflows[$workflow_key])
->setRequest($request)
->setViewer($viewer)
->setDashboard($dashboard)
->setMode($request->getURIData('modeKey'))
->handleRequest($request);
}
$radio = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Home Menu'))
->setName('home');
private function newWorkflowDialog(
PhabricatorDashboard $dashboard,
array $workflows) {
$viewer = $this->getViewer();
$cancel_uri = $dashboard->getURI();
foreach ($options['home'] as $type => $option) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$option['application'],
$option['capability']);
if ($can_edit) {
$radio->addButton(
$option['value'],
$option['name'],
$option['description']);
}
$menu = id(new PHUIObjectItemListView())
->setViewer($viewer)
->setFlush(true)
->setBig(true);
foreach ($workflows as $key => $workflow) {
$item = $workflow->getWorkflowMenuItem();
$item_href = urisprintf('install/%d/%s/', $dashboard->getID(), $key);
$item_href = $this->getApplicationURI($item_href);
$item->setHref($item_href);
$menu->addItem($item);
}
$form->appendChild($radio);
return $this->newDialog()
->setTitle(pht('Install Dashboard'))
->setErrors($errors)
->setTitle(pht('Add Dashboard to Menu'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendChild($form->buildLayoutView())
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Install Dashboard'));
->appendChild($menu)
->addCancelButton($cancel_uri);
}
}

View file

@ -83,7 +83,7 @@ final class PhabricatorDashboardViewController
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Install Dashboard'))
->setName(pht('Add Dashboard to Menu'))
->setIcon('fa-wrench')
->setHref($this->getApplicationURI("/install/{$id}/"))
->setWorkflow(true));

View file

@ -0,0 +1,58 @@
<?php
abstract class PhabricatorDashboardApplicationInstallWorkflow
extends PhabricatorDashboardInstallWorkflow {
abstract protected function newApplication();
protected function canInstallToGlobalMenu() {
return PhabricatorPolicyFilter::hasCapability(
$this->getViewer(),
$this->newApplication(),
PhabricatorPolicyCapability::CAN_EDIT);
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$application = $this->newApplication();
$can_global = $this->canInstallToGlobalMenu();
switch ($this->getMode()) {
case 'global':
if (!$can_global) {
return $this->newGlobalPermissionDialog();
} else if ($request->isFormPost()) {
return $this->installDashboard($application, null);
} else {
return $this->newGlobalConfirmDialog();
}
case 'personal':
if ($request->isFormPost()) {
return $this->installDashboard($application, $viewer->getPHID());
} else {
return $this->newPersonalConfirmDialog();
}
}
$global_item = $this->newGlobalMenuItem()
->setDisabled(!$can_global);
$menu = $this->newMenuFromItemMap(
array(
'personal' => $this->newPersonalMenuItem(),
'global' => $global_item,
));
return $this->newApplicationModeDialog()
->appendChild($menu);
}
abstract protected function newGlobalPermissionDialog();
abstract protected function newGlobalConfirmDialog();
abstract protected function newPersonalConfirmDialog();
abstract protected function newPersonalMenuItem();
abstract protected function newGlobalMenuItem();
abstract protected function newApplicationModeDialog();
}

View file

@ -0,0 +1,85 @@
<?php
final class PhabricatorDashboardFavoritesInstallWorkflow
extends PhabricatorDashboardApplicationInstallWorkflow {
const WORKFLOWKEY = 'favorites';
public function getOrder() {
return 4000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Favorites Menu'))
->setImageIcon('fa-bookmark')
->addAttribute(
pht(
'Add this dashboard to the favorites menu in the main '.
'menu bar.'));
}
protected function newProfileEngine() {
return new PhabricatorFavoritesProfileMenuEngine();
}
protected function newApplication() {
return new PhabricatorFavoritesApplication();
}
protected function newApplicationModeDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Favorites Menu'));
}
protected function newPersonalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Personal Favorites'))
->setImageIcon('fa-user')
->addAttribute(
pht(
'Add this dashboard to your list of personal favorite menu items, '.
'visible to only you.'));
}
protected function newGlobalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Global Favorites'))
->setImageIcon('fa-globe')
->addAttribute(
pht(
'Add this dashboard to the global favorites menu, visible to all '.
'users.'));
}
protected function newGlobalPermissionDialog() {
return $this->newDialog()
->setTitle(pht('No Permission'))
->appendParagraph(
pht(
'You do not have permission to install items on the global '.
'favorites menu.'));
}
protected function newGlobalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Global Favorites'))
->appendParagraph(
pht(
'Add dashboard %s as a global menu item in the favorites menu?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Favorites'));
}
protected function newPersonalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Personal Favorites'))
->appendParagraph(
pht(
'Add dashboard %s as a personal menu item in the favorites menu?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Favorites'));
}
}

View file

@ -0,0 +1,83 @@
<?php
final class PhabricatorDashboardHomeInstallWorkflow
extends PhabricatorDashboardApplicationInstallWorkflow {
const WORKFLOWKEY = 'home';
public function getOrder() {
return 1000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Home Page Menu'))
->setImageIcon('fa-home')
->addAttribute(
pht(
'Add this dashboard to the menu on the home page.'));
}
protected function newProfileEngine() {
return new PhabricatorHomeProfileMenuEngine();
}
protected function newApplication() {
return new PhabricatorHomeApplication();
}
protected function newApplicationModeDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Home Menu'));
}
protected function newPersonalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Personal Home Menu'))
->setImageIcon('fa-user')
->addAttribute(
pht(
'Add this dashboard to your list of personal home menu items, '.
'visible to only you.'));
}
protected function newGlobalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Global Home Menu'))
->setImageIcon('fa-globe')
->addAttribute(
pht(
'Add this dashboard to the global home menu, visible to all '.
'users.'));
}
protected function newGlobalPermissionDialog() {
return $this->newDialog()
->setTitle(pht('No Permission'))
->appendParagraph(
pht(
'You do not have permission to install items on the global home '.
'menu.'));
}
protected function newGlobalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Global Home Page'))
->appendParagraph(
pht(
'Add dashboard %s as a global menu item on the home page?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Home'));
}
protected function newPersonalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Personal Home Page'))
->appendParagraph(
pht(
'Add dashboard %s as a personal menu item on your home page?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Home'));
}
}

View file

@ -0,0 +1,143 @@
<?php
abstract class PhabricatorDashboardInstallWorkflow
extends Phobject {
private $request;
private $viewer;
private $dashboard;
private $mode;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
final public function setDashboard(PhabricatorDashboard $dashboard) {
$this->dashboard = $dashboard;
return $this;
}
final public function getDashboard() {
return $this->dashboard;
}
final public function setMode($mode) {
$this->mode = $mode;
return $this;
}
final public function getMode() {
return $this->mode;
}
final public function setRequest(AphrontRequest $request) {
$this->request = $request;
return $this;
}
final public function getRequest() {
return $this->request;
}
final public function getWorkflowKey() {
return $this->getPhobjectClassConstant('WORKFLOWKEY', 32);
}
final public static function getAllWorkflows() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getWorkflowKey')
->setSortMethod('getOrder')
->execute();
}
final public function getWorkflowMenuItem() {
return $this->newWorkflowMenuItem();
}
abstract public function getOrder();
abstract protected function newWorkflowMenuItem();
final protected function newMenuItem() {
return id(new PHUIObjectItemView())
->setClickable(true);
}
abstract public function handleRequest(AphrontRequest $request);
final protected function newDialog() {
$dashboard = $this->getDashboard();
return id(new AphrontDialogView())
->setViewer($this->getViewer())
->setWidth(AphrontDialogView::WIDTH_FORM)
->addCancelButton($dashboard->getURI());
}
final protected function newMenuFromItemMap(array $map) {
$viewer = $this->getViewer();
$dashboard = $this->getDashboard();
$menu = id(new PHUIObjectItemListView())
->setViewer($viewer)
->setFlush(true)
->setBig(true);
foreach ($map as $key => $item) {
$item->setHref(
urisprintf(
'/dashboard/install/%d/%s/%s/',
$dashboard->getID(),
$this->getWorkflowKey(),
$key));
$menu->addItem($item);
}
return $menu;
}
abstract protected function newProfileEngine();
final protected function installDashboard($profile_object, $custom_phid) {
$dashboard = $this->getDashboard();
$engine = $this->newProfileEngine()
->setProfileObject($profile_object);
$request = $this->getRequest();
$viewer = $this->getViewer();
$config = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
$profile_object,
new PhabricatorDashboardProfileMenuItem(),
$custom_phid);
$config->setMenuItemProperty('dashboardPHID', $dashboard->getPHID());
$xactions = array();
$editor = id(new PhabricatorProfileMenuEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request);
$editor->applyTransactions($config, $xactions);
$done_uri = $engine->getItemURI(urisprintf('view/%d/', $config->getID()));
return id(new AphrontRedirectResponse())
->setURI($done_uri);
}
final protected function getDashboardDisplayName() {
$dashboard = $this->getDashboard();
return phutil_tag('strong', array(), $dashboard->getName());
}
}

View file

@ -0,0 +1,99 @@
<?php
abstract class PhabricatorDashboardObjectInstallWorkflow
extends PhabricatorDashboardInstallWorkflow {
abstract protected function newQuery();
abstract protected function newConfirmDialog($object);
abstract protected function newObjectSelectionForm($object);
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$target_identifier = null;
$target_tokens = $request->getArr('target');
if ($target_tokens) {
$target_identifier = head($target_tokens);
}
if (!strlen($target_identifier)) {
$target_identifier = $request->getStr('target');
}
if (!strlen($target_identifier)) {
$target_identifier = $this->getMode();
}
$target = null;
if (strlen($target_identifier)) {
$targets = array();
if (ctype_digit($target_identifier)) {
$targets = $this->newQuery()
->setViewer($viewer)
->withIDs(array((int)$target_identifier))
->execute();
}
if (!$targets) {
$targets = $this->newQuery()
->setViewer($viewer)
->withPHIDs(array($target_identifier))
->execute();
}
if ($targets) {
$target = head($targets);
}
}
if ($target) {
$target_phid = $target->getPHID();
} else {
$target_phid = null;
}
if ($target) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$target,
PhabricatorPolicyCapability::CAN_EDIT);
} else {
$can_edit = null;
}
if ($request->isFormPost() && $target && $can_edit) {
if ($request->getBool('confirm')) {
return $this->installDashboard($target, null);
} else {
return $this->newConfirmDialog($target)
->addHiddenInput('confirm', 1)
->addHiddenInput('target', $target_phid);
}
}
$errors = array();
if (strlen($target_identifier)) {
if (!$target) {
$errors[] = pht('Choose a valid object.');
} else if (!$can_edit) {
$errors[] = pht(
'You do not have permission to edit the selected object. '.
'You can only install dashboards on objects you can edit.');
}
} else if ($request->getBool('pick')) {
$errors[] = pht(
'Choose an object to install this dashboard on.');
}
$form = $this->newObjectSelectionForm($target)
->addHiddenInput('pick', 1);
return $this->newDialog()
->setTitle(pht('Add Dashboard to Project Menu'))
->setErrors($errors)
->appendForm($form)
->addSubmitButton(pht('Continue'));
}
}

View file

@ -0,0 +1,62 @@
<?php
final class PhabricatorDashboardPortalInstallWorkflow
extends PhabricatorDashboardObjectInstallWorkflow {
const WORKFLOWKEY = 'portal';
public function getOrder() {
return 2000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Portal Menu'))
->setImageIcon('fa-compass')
->addAttribute(
pht('Add this dashboard to the menu on a portal.'));
}
protected function newProfileEngine() {
return new PhabricatorDashboardPortalProfileMenuEngine();
}
protected function newQuery() {
return new PhabricatorDashboardPortalQuery();
}
protected function newConfirmDialog($object) {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Portal Menu'))
->appendParagraph(
pht(
'Add the dashboard %s to portal %s?',
$this->getDashboardDisplayName(),
phutil_tag('strong', array(), $object->getName())))
->addSubmitButton(pht('Add to Portal'));
}
protected function newObjectSelectionForm($object) {
$viewer = $this->getViewer();
if ($object) {
$tokenizer_value = array($object->getPHID());
} else {
$tokenizer_value = array();
}
return id(new AphrontFormView())
->setViewer($viewer)
->appendInstructions(
pht(
'Select which portal you want to add the dashboard %s to.',
$this->getDashboardDisplayName()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('target')
->setLimit(1)
->setLabel(pht('Add to Portal'))
->setValue($tokenizer_value)
->setDatasource(new PhabricatorDashboardPortalDatasource()));
}
}

View file

@ -0,0 +1,63 @@
<?php
final class PhabricatorDashboardProjectInstallWorkflow
extends PhabricatorDashboardObjectInstallWorkflow {
const WORKFLOWKEY = 'project';
public function getOrder() {
return 3000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Project Menu'))
->setImageIcon('fa-briefcase')
->addAttribute(
pht('Add this dashboard to the menu for a project.'));
}
protected function newProfileEngine() {
return new PhabricatorProjectProfileMenuEngine();
}
protected function newQuery() {
return new PhabricatorProjectQuery();
}
protected function newConfirmDialog($object) {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Project Menu'))
->appendParagraph(
pht(
'Add the dashboard %s to the menu for project %s?',
$this->getDashboardDisplayName(),
phutil_tag('strong', array(), $object->getName())))
->addSubmitButton(pht('Add to Project'));
}
protected function newObjectSelectionForm($object) {
$viewer = $this->getViewer();
if ($object) {
$tokenizer_value = array($object->getPHID());
} else {
$tokenizer_value = array();
}
return id(new AphrontFormView())
->setViewer($viewer)
->appendInstructions(
pht(
'Select which project menu you want to add the dashboard %s to.',
$this->getDashboardDisplayName()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('target')
->setLimit(1)
->setLabel(pht('Add to Project'))
->setValue($tokenizer_value)
->setDatasource(new PhabricatorProjectDatasource()));
}
}

View file

@ -0,0 +1,47 @@
<?php
final class PhabricatorDashboardPortalDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse Portals');
}
public function getPlaceholderText() {
return pht('Type a portal name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDashboardApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
protected function renderSpecialTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
public function buildResults() {
$query = new PhabricatorDashboardPortalQuery();
// TODO: Actually query by name so this scales past 100 portals.
$portals = $this->executeQuery($query);
$results = array();
foreach ($portals as $portal) {
$result = id(new PhabricatorTypeaheadResult())
->setName($portal->getObjectName().' '.$portal->getName())
->setPHID($portal->getPHID())
->setIcon('fa-compass');
$results[] = $result;
}
return $results;
}
}

View file

@ -165,8 +165,9 @@ final class PhabricatorProjectPointsProfileMenuItem
),
$bar);
$item = $this->newItemView()
->newProgressBar($bar);
$item = $this->newItemView();
$item->newProgressBar($bar);
return array(
$item,

View file

@ -5,7 +5,6 @@ abstract class PhabricatorProfileMenuItem extends Phobject {
private $viewer;
private $engine;
public function getMenuItemTypeIcon() {
return null;
}

View file

@ -299,6 +299,8 @@ final class PHUIObjectItemView extends AphrontTagView {
if ($this->disabled) {
$item_classes[] = 'phui-oi-disabled';
} else {
$item_classes[] = 'phui-oi-enabled';
}
switch ($this->effect) {

View file

@ -70,21 +70,29 @@
}
.phui-oi-list-big .phui-oi-linked-container {
border: 1px solid {$lightblueborder};
border-width: 1px;
border-style: solid;
border-radius: 4px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.035);
}
.phui-oi-list-big .phui-oi-disabled {
border-radius: 4px;
background: {$lightgreybackground};
.phui-oi-list-big .phui-oi-enabled.phui-oi-linked-container {
border-color: {$lightblueborder};
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.05);
}
.phui-oi-list-big .phui-oi-disabled.phui-oi-linked-container {
border-color: {$greybackground};
}
.phui-oi-list-big .phui-oi-disabled .phui-oi-image-icon .phui-icon-view {
color: {$darkgreybackground};
}
.device-desktop .phui-oi-linked-container {
cursor: pointer;
}
.device-desktop .phui-oi-linked-container:hover {
.device-desktop .phui-oi-enabled.phui-oi-linked-container:hover {
background-color: {$hoverblue};
border-color: {$blueborder};
}