private function buildTransactions(PhabricatorDashboardPanel $panel)
 {
     $viewer = $this->getRequest()->getUser();
     $xactions = id(new PhabricatorDashboardPanelTransactionQuery())->setViewer($viewer)->withObjectPHIDs(array($panel->getPHID()))->execute();
     $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer);
     $timeline = id(new PhabricatorApplicationTransactionView())->setUser($viewer)->setShouldTerminate(true)->setObjectPHID($panel->getPHID())->setTransactions($xactions);
     return $timeline;
 }
 public static function addPanelToDashboard(PhabricatorUser $actor, PhabricatorContentSource $content_source, PhabricatorDashboardPanel $panel, PhabricatorDashboard $dashboard, $column)
 {
     $xactions = array();
     $xactions[] = id(new PhabricatorDashboardTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST)->setNewValue(array('+' => array($panel->getPHID() => $panel->getPHID())));
     $layout_config = $dashboard->getLayoutConfigObject();
     $layout_config->setPanelLocation($column, $panel->getPHID());
     $dashboard->setLayoutConfigFromObject($layout_config);
     $editor = id(new PhabricatorDashboardTransactionEditor())->setActor($actor)->setContentSource($content_source)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->applyTransactions($dashboard, $xactions);
 }
 public function renderPanelContent(PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine)
 {
     $text = $panel->getProperty('text', '');
     $oneoff = id(new PhabricatorMarkupOneOff())->setContent($text);
     $field = 'default';
     // NOTE: We're taking extra steps here to prevent creation of a text panel
     // which embeds itself using `{Wnnn}`, recursing indefinitely.
     $parent_key = PhabricatorDashboardRemarkupRule::KEY_PARENT_PANEL_PHIDS;
     $parent_phids = $engine->getParentPanelPHIDs();
     $parent_phids[] = $panel->getPHID();
     $markup_engine = id(new PhabricatorMarkupEngine())->setViewer($viewer)->setContextObject($panel)->setAuxiliaryConfig($parent_key, $parent_phids);
     $text_content = $markup_engine->addObject($oneoff, $field)->process()->getOutput($oneoff, $field);
     return id(new PHUIPropertyListView())->addTextContent($text_content);
 }
 public function renderPanelContent(PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine)
 {
     $config = $panel->getProperty('config');
     if (!is_array($config)) {
         // NOTE: The older version of this panel stored raw JSON.
         $config = phutil_json_decode($config);
     }
     $list = id(new PHUIListView())->setType(PHUIListView::NAVBAR_LIST);
     $selected = 0;
     $node_ids = array();
     foreach ($config as $idx => $tab_spec) {
         $node_ids[$idx] = celerity_generate_unique_node_id();
     }
     foreach ($config as $idx => $tab_spec) {
         $list->addMenuItem(id(new PHUIListItemView())->setHref('#')->setSelected($idx == $selected)->addSigil('dashboard-tab-panel-tab')->setMetadata(array('idx' => $idx))->setName(idx($tab_spec, 'name', pht('Nameless Tab'))));
     }
     $ids = ipull($config, 'panelID');
     if ($ids) {
         $panels = id(new PhabricatorDashboardPanelQuery())->setViewer($viewer)->withIDs($ids)->execute();
     } else {
         $panels = array();
     }
     $parent_phids = $engine->getParentPanelPHIDs();
     $parent_phids[] = $panel->getPHID();
     // TODO: Currently, we'll load all the panels on page load. It would be
     // vaguely nice to load hidden panels only when the user selects them.
     // TODO: Maybe we should persist which panel the user selected, so it
     // remains selected across page loads.
     $content = array();
     $no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE;
     foreach ($config as $idx => $tab_spec) {
         $panel_id = idx($tab_spec, 'panelID');
         $panel = idx($panels, $panel_id);
         if ($panel) {
             $panel_content = id(new PhabricatorDashboardPanelRenderingEngine())->setViewer($viewer)->setEnableAsyncRendering(true)->setParentPanelPHIDs($parent_phids)->setPanel($panel)->setHeaderMode($no_headers)->renderPanel();
         } else {
             $panel_content = pht('(Invalid Panel)');
         }
         $content[] = phutil_tag('div', array('id' => $node_ids[$idx], 'style' => $idx == $selected ? null : 'display: none'), $panel_content);
     }
     Javelin::initBehavior('dashboard-tab-panel');
     return javelin_tag('div', array('sigil' => 'dashboard-tab-panel-container', 'meta' => array('panels' => $node_ids)), array($list, $content));
 }
 /**
  * Detect graph cycles in panels, and deeply nested panels.
  *
  * This method throws if the current rendering stack is too deep or contains
  * a cycle. This can happen if you embed layout panels inside each other,
  * build a big stack of panels, or embed a panel in remarkup inside another
  * panel. Generally, all of this stuff is ridiculous and we just want to
  * shut it down.
  *
  * @param PhabricatorDashboardPanel Panel being rendered.
  * @return void
  */
 private function detectRenderingCycle(PhabricatorDashboardPanel $panel)
 {
     if ($this->parentPanelPHIDs === null) {
         throw new PhutilInvalidStateException('setParentPanelPHIDs');
     }
     $max_depth = 4;
     if (count($this->parentPanelPHIDs) >= $max_depth) {
         throw new Exception(pht('To render more than %s levels of panels nested inside other ' . 'panels, purchase a subscription to Phabricator Gold.', new PhutilNumber($max_depth)));
     }
     if (in_array($panel->getPHID(), $this->parentPanelPHIDs)) {
         throw new Exception(pht('You awake in a twisting maze of mirrors, all alike. ' . 'You are likely to be eaten by a graph cycle. ' . 'Should you escape alive, you resolve to be more careful about ' . 'putting dashboard panels inside themselves.'));
     }
 }