diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ 'names' => array( 'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.js' => '020aebcf', - 'core.pkg.css' => 'a1c2d49b', + 'core.pkg.css' => '3b565a84', 'core.pkg.js' => 'a747b035', 'differential.pkg.css' => '8d8360fb', 'differential.pkg.js' => '67e02996', @@ -128,7 +128,7 @@ '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 @@ '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', @@ -1369,9 +1369,6 @@ 'javelin-dom', 'javelin-fx', ), - '534f1757' => array( - 'phui-oi-list-view-css', - ), '541f81c3' => array( 'javelin-install', ), @@ -2175,6 +2172,9 @@ 'phabricator-keyboard-shortcut', 'conpherence-thread-manager', ), + 'fa74cc35' => array( + 'phui-oi-list-view-css', + ), 'fce5d170' => array( 'javelin-magical-init', 'javelin-util', 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 @@ -2905,6 +2905,7 @@ '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 @@ '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 @@ '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 @@ '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', @@ -8864,6 +8872,7 @@ ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', + 'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow', 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', 'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController', 'PhabricatorDashboardController' => 'PhabricatorController', @@ -8872,13 +8881,17 @@ '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', @@ -8922,10 +8935,12 @@ 'PhabricatorDestructibleInterface', ), 'PhabricatorDashboardPortalController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardPortalDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorDashboardPortalEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorDashboardPortalEditController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine', 'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorDashboardPortalInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow', 'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType', @@ -8941,6 +8956,7 @@ 'PhabricatorDashboardPortalViewController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardProfileController' => 'PhabricatorController', 'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem', + 'PhabricatorDashboardProjectInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType', diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -43,7 +43,10 @@ 'archive/(?P\d+)/' => 'PhabricatorDashboardArchiveController', 'create/' => 'PhabricatorDashboardEditController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', - 'install/(?:(?P\d+)/)?' => 'PhabricatorDashboardInstallController', + 'install/(?P\d+)/'. + '(?:(?P[^/]+)/'. + '(?:(?P[^/]+)/)?)?' => + 'PhabricatorDashboardInstallController', 'console/' => 'PhabricatorDashboardConsoleController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php --- a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php +++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php @@ -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 @@ return new Aphront404Response(); } + $this->setDashboard($dashboard); $cancel_uri = $dashboard->getURI(); - $home_app = new PhabricatorHomeApplication(); - - $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); - } - } + $workflow_key = $request->getURIData('workflowKey'); - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Menu Label')) - ->setName('name') - ->setValue($v_name)); - - $radio = id(new AphrontFormRadioButtonControl()) - ->setLabel(pht('Home Menu')) - ->setName('home'); - - 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']); - } + $workflows = PhabricatorDashboardInstallWorkflow::getAllWorkflows(); + if (!isset($workflows[$workflow_key])) { + return $this->newWorkflowDialog($dashboard, $workflows); } - $form->appendChild($radio); + return id(clone $workflows[$workflow_key]) + ->setRequest($request) + ->setViewer($viewer) + ->setDashboard($dashboard) + ->setMode($request->getURIData('modeKey')) + ->handleRequest($request); + } + + private function newWorkflowDialog( + PhabricatorDashboard $dashboard, + array $workflows) { + $viewer = $this->getViewer(); + $cancel_uri = $dashboard->getURI(); + + $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); + } 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); } } diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php --- a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php @@ -83,7 +83,7 @@ $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)); diff --git a/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php @@ -0,0 +1,58 @@ +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(); + +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php @@ -0,0 +1,85 @@ +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')); + } + + +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php @@ -0,0 +1,83 @@ +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')); + } + +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php @@ -0,0 +1,143 @@ +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()); + } + +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php @@ -0,0 +1,99 @@ +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')); + } +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php @@ -0,0 +1,62 @@ +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())); + } + +} diff --git a/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php @@ -0,0 +1,63 @@ +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())); + } + +} diff --git a/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php b/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php @@ -0,0 +1,47 @@ +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; + } + +} diff --git a/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php @@ -165,8 +165,9 @@ ), $bar); - $item = $this->newItemView() - ->newProgressBar($bar); + $item = $this->newItemView(); + + $item->newProgressBar($bar); return array( $item, diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php --- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php @@ -5,7 +5,6 @@ private $viewer; private $engine; - public function getMenuItemTypeIcon() { return null; } @@ -86,7 +85,12 @@ phutil_describe_type($list))); } - assert_instances_of($list, 'PhabricatorProfileMenuItemView'); + try { + assert_instances_of($list, 'PhabricatorProfileMenuItemView'); + } catch (Exception $ex) { + var_dump(get_class($this)); + var_dump($list); + } foreach ($list as $view) { $view->setMenuItemConfiguration($config); diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -299,6 +299,8 @@ if ($this->disabled) { $item_classes[] = 'phui-oi-disabled'; + } else { + $item_classes[] = 'phui-oi-enabled'; } switch ($this->effect) { diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css --- a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css @@ -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}; }