Path: blob/master/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php
12242 views
<?php12final class PhabricatorDashboardPanelTabsController3extends PhabricatorDashboardController {45private $contextObject;67private function setContextObject($context_object) {8$this->contextObject = $context_object;9return $this;10}1112private function getContextObject() {13return $this->contextObject;14}1516public function handleRequest(AphrontRequest $request) {17$viewer = $this->getViewer();1819$panel = id(new PhabricatorDashboardPanelQuery())20->setViewer($viewer)21->withIDs(array($request->getURIData('id')))22->requireCapabilities(23array(24PhabricatorPolicyCapability::CAN_VIEW,25PhabricatorPolicyCapability::CAN_EDIT,26))27->executeOne();28if (!$panel) {29return new Aphront404Response();30}3132$tabs_type = id(new PhabricatorDashboardTabsPanelType())33->getPanelTypeKey();3435// This controller may only be used to edit tab panels.36$panel_type = $panel->getPanelType();37if ($panel_type !== $tabs_type) {38return new Aphront404Response();39}4041$op = $request->getURIData('op');42$after = $request->getStr('after');43if (!phutil_nonempty_string($after)) {44$after = null;45}4647$target = $request->getStr('target');48if (!phutil_nonempty_string($target)) {49$target = null;50}5152$impl = $panel->getImplementation();53$config = $impl->getPanelConfiguration($panel);5455$cancel_uri = $panel->getURI();5657if ($after !== null) {58$found = false;59foreach ($config as $key => $spec) {60if ((string)$key === $after) {61$found = true;62break;63}64}6566if (!$found) {67return $this->newDialog()68->setTitle(pht('Adjacent Tab Not Found'))69->appendParagraph(70pht(71'Adjacent tab ("%s") was not found on this panel. It may have '.72'been removed.',73$after))74->addCancelButton($cancel_uri);75}76}7778if ($target !== null) {79$found = false;80foreach ($config as $key => $spec) {81if ((string)$key === $target) {82$found = true;83break;84}85}8687if (!$found) {88return $this->newDialog()89->setTitle(pht('Target Tab Not Found'))90->appendParagraph(91pht(92'Target tab ("%s") was not found on this panel. It may have '.93'been removed.',94$target))95->addCancelButton($cancel_uri);96}97}9899// Tab panels may be edited from the panel page, or from the context of100// a dashboard. If we're editing from a dashboard, we want to redirect101// back to the dashboard after making changes.102103$context_phid = $request->getStr('contextPHID');104$context = null;105if (phutil_nonempty_string($context_phid)) {106$context = id(new PhabricatorObjectQuery())107->setViewer($viewer)108->withPHIDs(array($context_phid))109->executeOne();110if (!$context) {111return new Aphront404Response();112}113114switch (phid_get_type($context_phid)) {115case PhabricatorDashboardDashboardPHIDType::TYPECONST:116$cancel_uri = $context->getURI();117break;118case PhabricatorDashboardPanelPHIDType::TYPECONST:119$cancel_uri = $context->getURI();120break;121default:122return $this->newDialog()123->setTitle(pht('Context Object Unsupported'))124->appendParagraph(125pht(126'Context object ("%s") has unsupported type. Panels should '.127'be rendered from the context of a dashboard or another '.128'panel.',129$context_phid))130->addCancelButton($cancel_uri);131}132133$this->setContextObject($context);134}135136switch ($op) {137case 'add':138return $this->handleAddOperation($panel, $after, $cancel_uri);139case 'remove':140return $this->handleRemoveOperation($panel, $target, $cancel_uri);141case 'move':142return $this->handleMoveOperation($panel, $target, $after, $cancel_uri);143case 'rename':144return $this->handleRenameOperation($panel, $target, $cancel_uri);145}146}147148private function handleAddOperation(149PhabricatorDashboardPanel $panel,150$after,151$cancel_uri) {152$request = $this->getRequest();153$viewer = $this->getViewer();154155$panel_phid = null;156$errors = array();157if ($request->isFormPost()) {158$panel_phid = $request->getArr('panelPHID');159$panel_phid = head($panel_phid);160161$add_panel = id(new PhabricatorDashboardPanelQuery())162->setViewer($viewer)163->withPHIDs(array($panel_phid))164->executeOne();165if (!$add_panel) {166$errors[] = pht('You must select a valid panel.');167}168169if (!$errors) {170$add_panel_config = array(171'name' => null,172'panelID' => $add_panel->getID(),173);174$add_panel_key = Filesystem::readRandomCharacters(12);175176$impl = $panel->getImplementation();177$old_config = $impl->getPanelConfiguration($panel);178$new_config = array();179if ($after === null) {180$new_config = $old_config;181$new_config[] = $add_panel_config;182} else {183foreach ($old_config as $key => $value) {184$new_config[$key] = $value;185if ((string)$key === $after) {186$new_config[$add_panel_key] = $add_panel_config;187}188}189}190191$xactions = array();192193$xactions[] = $panel->getApplicationTransactionTemplate()194->setTransactionType(195PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)196->setNewValue($new_config);197198$editor = id(new PhabricatorDashboardPanelTransactionEditor())199->setContentSourceFromRequest($request)200->setActor($viewer)201->setContinueOnNoEffect(true)202->setContinueOnMissingFields(true);203204$editor->applyTransactions($panel, $xactions);205206return id(new AphrontRedirectResponse())->setURI($cancel_uri);207}208}209210if ($panel_phid) {211$v_panel = array($panel_phid);212} else {213$v_panel = array();214}215216$form = id(new AphrontFormView())217->setViewer($viewer)218->appendControl(219id(new AphrontFormTokenizerControl())220->setDatasource(new PhabricatorDashboardPanelDatasource())221->setLimit(1)222->setName('panelPHID')223->setLabel(pht('Panel'))224->setValue($v_panel));225226return $this->newEditDialog()227->setTitle(pht('Choose Dashboard Panel'))228->setErrors($errors)229->addHiddenInput('after', $after)230->appendForm($form)231->addCancelButton($cancel_uri)232->addSubmitButton(pht('Add Panel'));233}234235private function handleRemoveOperation(236PhabricatorDashboardPanel $panel,237$target,238$cancel_uri) {239$request = $this->getRequest();240$viewer = $this->getViewer();241242$panel_phid = null;243$errors = array();244if ($request->isFormPost()) {245$impl = $panel->getImplementation();246$old_config = $impl->getPanelConfiguration($panel);247248$new_config = $this->removePanel($old_config, $target);249$this->writePanelConfig($panel, $new_config);250251return id(new AphrontRedirectResponse())->setURI($cancel_uri);252}253254return $this->newEditDialog()255->setTitle(pht('Remove tab?'))256->addHiddenInput('target', $target)257->appendParagraph(pht('Really remove this tab?'))258->addCancelButton($cancel_uri)259->addSubmitButton(pht('Remove Tab'));260}261262private function handleRenameOperation(263PhabricatorDashboardPanel $panel,264$target,265$cancel_uri) {266$request = $this->getRequest();267$viewer = $this->getViewer();268269$impl = $panel->getImplementation();270$old_config = $impl->getPanelConfiguration($panel);271272$spec = $old_config[$target];273$name = idx($spec, 'name');274275if ($request->isFormPost()) {276$name = $request->getStr('name');277278$new_config = $this->renamePanel($old_config, $target, $name);279$this->writePanelConfig($panel, $new_config);280281return id(new AphrontRedirectResponse())->setURI($cancel_uri);282}283284$form = id(new AphrontFormView())285->setViewer($viewer)286->appendControl(287id(new AphrontFormTextControl())288->setValue($name)289->setName('name')290->setLabel(pht('Tab Name')));291292return $this->newEditDialog()293->setTitle(pht('Rename Panel'))294->addHiddenInput('target', $target)295->appendForm($form)296->addCancelButton($cancel_uri)297->addSubmitButton(pht('Rename Tab'));298}299300private function handleMoveOperation(301PhabricatorDashboardPanel $panel,302$target,303$after,304$cancel_uri) {305$request = $this->getRequest();306$viewer = $this->getViewer();307308$move = $request->getStr('move');309310$impl = $panel->getImplementation();311$old_config = $impl->getPanelConfiguration($panel);312313$is_next = ($move === 'next');314if ($target === $after) {315return $this->newDialog()316->setTitle(pht('Impossible!'))317->appendParagraph(318pht(319'You can not move a tab relative to itself.'))320->addCancelButton($cancel_uri);321} else if ($is_next && ((string)last_key($old_config) === $target)) {322return $this->newDialog()323->setTitle(pht('Impossible!'))324->appendParagraph(325pht(326'This is already the last tab. It can not move any farther to '.327'the right.'))328->addCancelButton($cancel_uri);329} else if ((string)head_key($old_config) === $target) {330return $this->newDialog()331->setTitle(pht('Impossible!'))332->appendParagraph(333pht(334'This is already the first tab. It can not move any farther to '.335'the left.'))336->addCancelButton($cancel_uri);337}338339if ($request->hasCSRF()) {340$new_config = array();341foreach ($old_config as $old_key => $old_spec) {342$old_key = (string)$old_key;343344$is_after = ($old_key === $after);345346if (!$is_after) {347if ($old_key === $target) {348continue;349}350}351352if ($is_after && !$is_next) {353$new_config[$target] = $old_config[$target];354}355356$new_config[$old_key] = $old_spec;357358if ($is_after && $is_next) {359$new_config[$target] = $old_config[$target];360}361}362363$this->writePanelConfig($panel, $new_config);364365return id(new AphrontRedirectResponse())->setURI($cancel_uri);366}367368if ($is_next) {369$prompt = pht('Move this tab to the right?');370} else {371$prompt = pht('Move this tab to the left?');372}373374return $this->newEditDialog()375->setTitle(pht('Move Tab'))376->addHiddenInput('target', $target)377->addHiddenInput('after', $after)378->addHiddenInput('move', $move)379->appendParagraph($prompt)380->addCancelButton($cancel_uri)381->addSubmitButton(pht('Move Tab'));382}383384private function writePanelConfig(385PhabricatorDashboardPanel $panel,386array $config) {387$request = $this->getRequest();388$viewer = $this->getViewer();389390$xactions = array();391392$xactions[] = $panel->getApplicationTransactionTemplate()393->setTransactionType(394PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)395->setNewValue($config);396397$editor = id(new PhabricatorDashboardPanelTransactionEditor())398->setContentSourceFromRequest($request)399->setActor($viewer)400->setContinueOnNoEffect(true)401->setContinueOnMissingFields(true);402403return $editor->applyTransactions($panel, $xactions);404}405406private function removePanel(array $config, $target) {407$result = array();408409foreach ($config as $key => $panel_spec) {410if ((string)$key === $target) {411continue;412}413$result[$key] = $panel_spec;414}415416return $result;417}418419private function renamePanel(array $config, $target, $name) {420$config[$target]['name'] = $name;421return $config;422}423424protected function newEditDialog() {425$dialog = $this->newDialog()426->setWidth(AphrontDialogView::WIDTH_FORM);427428$context = $this->getContextObject();429if ($context) {430$dialog->addHiddenInput('contextPHID', $context->getPHID());431}432433return $dialog;434}435436}437438439