public function renderPanelContent(PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { $class = $panel->getProperty('class'); $engine = PhabricatorApplicationSearchEngine::getEngineByClassName($class); if (!$engine) { throw new Exception(pht('The application search engine "%s" is not known to Phabricator!', $class)); } $engine->setViewer($viewer); $engine->setContext(PhabricatorApplicationSearchEngine::CONTEXT_PANEL); $key = $panel->getProperty('key'); if ($engine->isBuiltinQuery($key)) { $saved = $engine->buildSavedQueryFromBuiltin($key); } else { $saved = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withEngineClassNames(array($class))->withQueryKeys(array($key))->executeOne(); } if (!$saved) { throw new Exception(pht('Query "%s" is unknown to application search engine "%s"!', $key, $class)); } $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); if ($panel->getProperty('limit')) { $limit = (int) $panel->getProperty('limit'); if ($pager->getPageSize() !== 0xffff) { $pager->setPageSize($limit); } } $results = $engine->executeQuery($query, $pager); return $engine->renderResults($results, $saved); }
protected function loadPage() { $table = new PhabricatorDashboardPanel(); $conn_r = $table->establishConnection('r'); $data = queryfx_all($conn_r, 'SELECT * FROM %T %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); return $table->loadAllFromArray($data); }
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); }
private function getSearchEngine(PhabricatorDashboardPanel $panel) { $class = $panel->getProperty('class'); $engine = PhabricatorApplicationSearchEngine::getEngineByClassName($class); if (!$engine) { throw new Exception(pht('The application search engine "%s" is not known to Phabricator!', $class)); } if (!$engine->canUseInPanelContext()) { throw new Exception(pht('Application search engines of class "%s" can not be used to build ' . 'dashboard panels.', $class)); } return $engine; }
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); }
private function buildCurtainView(PhabricatorDashboardPanel $panel) { $viewer = $this->getViewer(); $id = $panel->getID(); $curtain = $this->newCurtainView($panel); $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $panel, PhabricatorPolicyCapability::CAN_EDIT); $curtain->addAction(id(new PhabricatorActionView())->setName(pht('Edit Panel'))->setIcon('fa-pencil')->setHref($this->getApplicationURI("panel/edit/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(!$can_edit)); if (!$panel->getIsArchived()) { $archive_text = pht('Archive Panel'); $archive_icon = 'fa-ban'; } else { $archive_text = pht('Activate Panel'); $archive_icon = 'fa-check'; } $curtain->addAction(id(new PhabricatorActionView())->setName($archive_text)->setIcon($archive_icon)->setHref($this->getApplicationURI("panel/archive/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(true)); return $curtain; }
private function buildActionView(PhabricatorDashboardPanel $panel) { $viewer = $this->getRequest()->getUser(); $id = $panel->getID(); $actions = id(new PhabricatorActionListView())->setObjectURI('/' . $panel->getMonogram())->setUser($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $panel, PhabricatorPolicyCapability::CAN_EDIT); $actions->addAction(id(new PhabricatorActionView())->setName(pht('Edit Panel'))->setIcon('fa-pencil')->setHref($this->getApplicationURI("panel/edit/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(!$can_edit)); if (!$panel->getIsArchived()) { $archive_text = pht('Archive Panel'); $archive_icon = 'fa-ban'; } else { $archive_text = pht('Activate Panel'); $archive_icon = 'fa-check'; } $actions->addAction(id(new PhabricatorActionView())->setName($archive_text)->setIcon($archive_icon)->setHref($this->getApplicationURI("panel/archive/{$id}/"))->setDisabled(!$can_edit)->setWorkflow(true)); $actions->addAction(id(new PhabricatorActionView())->setName(pht('View Standalone'))->setIcon('fa-eye')->setHref($this->getApplicationURI("panel/render/{$id}/"))); return $actions; }
protected function newEditableObject() { $viewer = $this->getViewer(); $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer); if ($this->panelType) { $panel->setPanelType($this->panelType); } return $panel; }
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)); }
private function newPanel(AphrontRequest $request, PhabricatorUser $viewer, $type, $name, array $properties) { $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer)->setPanelType($type)->setProperties($properties); $xactions = array(); $xactions[] = id(new PhabricatorDashboardPanelTransaction())->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)->setNewValue($name); $editor = id(new PhabricatorDashboardPanelTransactionEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->applyTransactions($panel, $xactions); return $panel; }
private function copyPanel(AphrontRequest $request, PhabricatorDashboard $dashboard, PhabricatorDashboardPanel $panel) { $viewer = $request->getUser(); $copy = PhabricatorDashboardPanel::initializeNewPanel($viewer); $copy = PhabricatorDashboardPanel::copyPanel($copy, $panel); $copy->openTransaction(); $copy->save(); // TODO: This should record a transaction on the panel copy, too. $xactions = array(); $xactions[] = id(new PhabricatorDashboardTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST)->setNewValue(array('+' => array($copy->getPHID() => $copy->getPHID()), '-' => array($panel->getPHID() => $panel->getPHID()))); $layout_config = $dashboard->getLayoutConfigObject(); $layout_config->replacePanel($panel->getPHID(), $copy->getPHID()); $dashboard->setLayoutConfigFromObject($layout_config); $dashboard->save(); $editor = id(new PhabricatorDashboardTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->applyTransactions($dashboard, $xactions); $copy->saveTransaction(); return $copy; }
/** * 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.')); } }
public function renderPanelContent(PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { $text = $panel->getProperty('text', ''); $text_content = PhabricatorMarkupEngine::renderOneObject(id(new PhabricatorMarkupOneOff())->setContent($text), 'default', $viewer); return id(new PHUIPropertyListView())->addTextContent($text_content); }