1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 10:12:41 +01:00

Allow panels to appear on dashboards

Summary:
Ref T3583. Adds edges, query relationships, etc. Lots of debugging/temporary UI.

My general intent here is to use edges to track where panels appear, and then put additional data on the dashboard itself to control layout, positioning, etc.

Dashboards don't actually render yet so this is still pretty boring.

Test Plan:
{F149175}

{F149176}

{F149177}

Reviewers: chad, btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T3583

Differential Revision: https://secure.phabricator.com/D8916
This commit is contained in:
epriestley 2014-04-30 14:28:55 -07:00
parent 0916af5336
commit 941f0ba7ae
11 changed files with 229 additions and 0 deletions

View file

@ -0,0 +1,15 @@
CREATE TABLE {$NAMESPACE}_dashboard.edge (
src VARCHAR(64) NOT NULL COLLATE utf8_bin,
type VARCHAR(64) NOT NULL COLLATE utf8_bin,
dst VARCHAR(64) NOT NULL COLLATE utf8_bin,
dateCreated INT UNSIGNED NOT NULL,
seq INT UNSIGNED NOT NULL,
dataID INT UNSIGNED,
PRIMARY KEY (src, type, dst),
KEY (src, type, dateCreated, seq)
) ENGINE=InnoDB, COLLATE utf8_general_ci;
CREATE TABLE {$NAMESPACE}_dashboard.edgedata (
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
data LONGTEXT NOT NULL COLLATE utf8_bin
) ENGINE=InnoDB, COLLATE utf8_general_ci;

View file

@ -1432,6 +1432,7 @@ phutil_register_library_map(array(
'PhabricatorDaemonReference' => 'infrastructure/daemon/control/PhabricatorDaemonReference.php',
'PhabricatorDaemonTaskGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonTaskGarbageCollector.php',
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php',
'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php',
'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php',
@ -4232,6 +4233,7 @@ phutil_register_library_map(array(
0 => 'PhabricatorDashboardDAO',
1 => 'PhabricatorPolicyInterface',
),
'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardController' => 'PhabricatorController',
'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO',
'PhabricatorDashboardEditController' => 'PhabricatorDashboardController',

View file

@ -23,6 +23,7 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication {
'view/(?P<id>\d+)/' => 'PhabricatorDashboardViewController',
'create/' => 'PhabricatorDashboardEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'panel/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'

View file

@ -0,0 +1,94 @@
<?php
final class PhabricatorDashboardAddPanelController
extends PhabricatorDashboardController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$dashboard_uri = $this->getApplicationURI('view/'.$dashboard->getID().'/');
$v_panel = $request->getStr('panel');
$e_panel = true;
$errors = array();
if ($request->isFormPost()) {
if (strlen($v_panel)) {
$panel = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames(array($v_panel))
->withTypes(array(PhabricatorDashboardPHIDTypePanel::TYPECONST))
->executeOne();
if (!$panel) {
$errors[] = pht('No such panel!');
$e_panel = pht('Invalid');
}
} else {
$errors[] = pht('Name a panel to add.');
$e_panel = pht('Required');
}
if (!$errors) {
$xactions = array();
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorEdgeConfig::TYPE_DASHBOARD_HAS_PANEL)
->setNewValue(
array(
'+' => array(
$panel->getPHID() => $panel->getPHID(),
),
));
$editor = id(new PhabricatorDashboardTransactionEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true)
->applyTransactions($dashboard, $xactions);
return id(new AphrontRedirectResponse())->setURI($dashboard_uri);
}
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht('Enter a panel monogram like `W123`.'))
->appendChild(
id(new AphrontFormTextControl())
->setName('panel')
->setLabel(pht('Panel'))
->setValue($v_panel)
->setError($e_panel));
return $this->newDialog()
->setTitle(pht('Add Panel'))
->setErrors($errors)
->appendChild($form->buildLayoutView())
->addCancelButton($dashboard_uri)
->addSubmitButton(pht('Add Panel'));
}
}

View file

@ -124,6 +124,15 @@ final class PhabricatorDashboardPanelViewController
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$dashboard_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$panel->getPHID(),
PhabricatorEdgeConfig::TYPE_PANEL_HAS_DASHBOARD);
$this->loadHandles($dashboard_phids);
$properties->addProperty(
pht('Appears On'),
$this->renderHandlesForPHIDs($dashboard_phids));
return $properties;
}

View file

@ -16,6 +16,7 @@ final class PhabricatorDashboardViewController
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->needPanels(true)
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
@ -77,6 +78,14 @@ final class PhabricatorDashboardViewController
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Add Panel'))
->setIcon('new')
->setHref($this->getApplicationURI("addpanel/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
return $actions;
}
@ -95,6 +104,13 @@ final class PhabricatorDashboardViewController
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$panel_phids = $dashboard->getPanelPHIDs();
$this->loadHandles($panel_phids);
$properties->addProperty(
pht('Panels'),
$this->renderHandlesForPHIDs($panel_phids));
return $properties;
}

View file

@ -8,6 +8,7 @@ final class PhabricatorDashboardPanelTransactionEditor
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorDashboardPanelTransaction::TYPE_NAME;

View file

@ -8,6 +8,7 @@ final class PhabricatorDashboardTransactionEditor
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorDashboardTransaction::TYPE_NAME;
@ -51,6 +52,8 @@ final class PhabricatorDashboardTransactionEditor
case PhabricatorTransactions::TYPE_EDIT_POLICY:
$object->setEditPolicy($xaction->getNewValue());
return;
case PhabricatorTransactions::TYPE_EDGE:
return;
}
return parent::applyCustomInternalTransaction($object, $xaction);
@ -63,6 +66,8 @@ final class PhabricatorDashboardTransactionEditor
switch ($xaction->getTransactionType()) {
case PhabricatorDashboardTransaction::TYPE_NAME:
return;
case PhabricatorTransactions::TYPE_EDGE:
return;
}
return parent::applyCustomExternalTransaction($object, $xaction);

View file

@ -6,6 +6,8 @@ final class PhabricatorDashboardQuery
private $ids;
private $phids;
private $needPanels;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
@ -16,6 +18,11 @@ final class PhabricatorDashboardQuery
return $this;
}
public function needPanels($need_panels) {
$this->needPanels = $need_panels;
return $this;
}
protected function loadPage() {
$table = new PhabricatorDashboard();
$conn_r = $table->establishConnection('r');
@ -31,6 +38,41 @@ final class PhabricatorDashboardQuery
return $table->loadAllFromArray($data);
}
protected function didFilterPage(array $dashboards) {
if ($this->needPanels) {
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($dashboards, 'getPHID'))
->withEdgeTypes(
array(
PhabricatorEdgeConfig::TYPE_DASHBOARD_HAS_PANEL,
));
$edge_query->execute();
$panel_phids = $edge_query->getDestinationPHIDs();
if ($panel_phids) {
$panels = id(new PhabricatorDashboardPanelQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withPHIDs($panel_phids)
->execute();
$panels = mpull($panels, null, 'getPHID');
} else {
$panels = array();
}
foreach ($dashboards as $dashboard) {
$dashboard_phids = $edge_query->getDestinationPHIDs(
array($dashboard->getPHID()));
$dashboard_panels = array_select_keys($panels, $dashboard_phids);
$dashboard->attachPanelPHIDs($dashboard_phids);
$dashboard->attachPanels($dashboard_panels);
}
}
return $dashboards;
}
protected function buildWhereClause($conn_r) {
$where = array();

View file

@ -10,6 +10,9 @@ final class PhabricatorDashboard extends PhabricatorDashboardDAO
protected $viewPolicy;
protected $editPolicy;
private $panelPHIDs = self::ATTACHABLE;
private $panels = self::ATTACHABLE;
public static function initializeNewDashboard(PhabricatorUser $actor) {
return id(new PhabricatorDashboard())
->setName('')
@ -28,6 +31,25 @@ final class PhabricatorDashboard extends PhabricatorDashboardDAO
PhabricatorDashboardPHIDTypeDashboard::TYPECONST);
}
public function attachPanelPHIDs(array $phids) {
$this->panelPHIDs = $phids;
return $this;
}
public function getPanelPHIDs() {
return $this->assertAttached($this->panelPHIDs);
}
public function attachPanels(array $panels) {
assert_instances_of($panels, 'PhabricatorDashboardPanel');
$this->panels = $panels;
return $this;
}
public function getPanels() {
return $this->assertAttached($this->panels);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -69,6 +69,9 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
const TYPE_OBJECT_HAS_COLUMN = 43;
const TYPE_COLUMN_HAS_OBJECT = 44;
const TYPE_DASHBOARD_HAS_PANEL = 45;
const TYPE_PANEL_HAS_DASHBOARD = 46;
const TYPE_TEST_NO_CYCLE = 9000;
const TYPE_PHOB_HAS_ASANATASK = 80001;
@ -153,6 +156,9 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
self::TYPE_OBJECT_HAS_COLUMN => self::TYPE_COLUMN_HAS_OBJECT,
self::TYPE_COLUMN_HAS_OBJECT => self::TYPE_OBJECT_HAS_COLUMN,
self::TYPE_PANEL_HAS_DASHBOARD => self::TYPE_DASHBOARD_HAS_PANEL,
self::TYPE_DASHBOARD_HAS_PANEL => self::TYPE_PANEL_HAS_DASHBOARD,
);
return idx($map, $edge_type);
@ -259,6 +265,10 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
return '%s edited reviewer(s), added %d: %s; removed %d: %s.';
case self::TYPE_TASK_HAS_MOCK:
return '%s edited mock(s), added %d: %s; removed %d: %s.';
case self::TYPE_DASHBOARD_HAS_PANEL:
return '%s edited panel(s), added %d: %s; removed %d: %s.';
case self::TYPE_PANEL_HAS_DASHBOARD:
return '%s edited dashboard(s), added %d: %s; removed %d: %s.';
case self::TYPE_SUBSCRIBED_TO_OBJECT:
case self::TYPE_UNSUBSCRIBED_FROM_OBJECT:
case self::TYPE_FILE_HAS_OBJECT:
@ -329,6 +339,10 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
return '%s added %d reviewer(s): %s.';
case self::TYPE_TASK_HAS_MOCK:
return '%s added %d mock(s): %s.';
case self::TYPE_DASHBOARD_HAS_PANEL:
return '%s added %d panel(s): %s.';
case self::TYPE_PANEL_HAS_DASHBOARD:
return '%s added %d dashboard(s): %s.';
case self::TYPE_SUBSCRIBED_TO_OBJECT:
case self::TYPE_UNSUBSCRIBED_FROM_OBJECT:
case self::TYPE_FILE_HAS_OBJECT:
@ -400,6 +414,10 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
return '%s removed %d reviewer(s): %s.';
case self::TYPE_TASK_HAS_MOCK:
return '%s removed %d mock(s): %s.';
case self::TYPE_DASHBOARD_HAS_PANEL:
return '%s removed %d panel(s): %s.';
case self::TYPE_PANEL_HAS_DASHBOARD:
return '%s removed %d dashboard(s): %s.';
case self::TYPE_SUBSCRIBED_TO_OBJECT:
case self::TYPE_UNSUBSCRIBED_FROM_OBJECT:
case self::TYPE_FILE_HAS_OBJECT:
@ -469,6 +487,10 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
return '%s updated reviewers of %s.';
case self::TYPE_TASK_HAS_MOCK:
return '%s updated mocks of %s.';
case self::TYPE_PANEL_HAS_DASHBOARD:
return '%s updated panels for %s.';
case self::TYPE_PANEL_HAS_DASHBOARD:
return '%s updated dashboards for %s.';
case self::TYPE_SUBSCRIBED_TO_OBJECT:
case self::TYPE_UNSUBSCRIBED_FROM_OBJECT:
case self::TYPE_FILE_HAS_OBJECT: