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:
parent
0916af5336
commit
941f0ba7ae
11 changed files with 229 additions and 0 deletions
15
resources/sql/autopatches/20140430.dash.2.edge.sql
Normal file
15
resources/sql/autopatches/20140430.dash.2.edge.sql
Normal 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;
|
|
@ -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',
|
||||
|
|
|
@ -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>[^/]+)/)?'
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue