Skip to content

Commit dc37789

Browse files
author
epriestley
committedJul 1, 2016
Build that thing someone posted a screenshot of on Facebook
Summary: Seemed kinda cool. Test Plan: {F1707244} Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D16210
1 parent 6c7e392 commit dc37789

10 files changed

+450
-225
lines changed
 

‎src/__phutil_library_map__.php

+4
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@
556556
'DifferentialRevisionViewController' => 'applications/differential/controller/DifferentialRevisionViewController.php',
557557
'DifferentialSchemaSpec' => 'applications/differential/storage/DifferentialSchemaSpec.php',
558558
'DifferentialSetDiffPropertyConduitAPIMethod' => 'applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php',
559+
'DifferentialStackGraph' => 'applications/differential/edge/DifferentialStackGraph.php',
559560
'DifferentialStoredCustomField' => 'applications/differential/customfield/DifferentialStoredCustomField.php',
560561
'DifferentialSubscribersField' => 'applications/differential/customfield/DifferentialSubscribersField.php',
561562
'DifferentialSummaryField' => 'applications/differential/customfield/DifferentialSummaryField.php',
@@ -1599,6 +1600,7 @@
15991600
'PHUICurtainExtension' => 'view/extension/PHUICurtainExtension.php',
16001601
'PHUICurtainPanelView' => 'view/layout/PHUICurtainPanelView.php',
16011602
'PHUICurtainView' => 'view/layout/PHUICurtainView.php',
1603+
'PHUIDiffGraphView' => 'infrastructure/diff/view/PHUIDiffGraphView.php',
16021604
'PHUIDiffInlineCommentDetailView' => 'infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php',
16031605
'PHUIDiffInlineCommentEditView' => 'infrastructure/diff/view/PHUIDiffInlineCommentEditView.php',
16041606
'PHUIDiffInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php',
@@ -4928,6 +4930,7 @@
49284930
'DifferentialRevisionViewController' => 'DifferentialController',
49294931
'DifferentialSchemaSpec' => 'PhabricatorConfigSchemaSpec',
49304932
'DifferentialSetDiffPropertyConduitAPIMethod' => 'DifferentialConduitAPIMethod',
4933+
'DifferentialStackGraph' => 'AbstractDirectedGraph',
49314934
'DifferentialStoredCustomField' => 'DifferentialCustomField',
49324935
'DifferentialSubscribersField' => 'DifferentialCoreCustomField',
49334936
'DifferentialSummaryField' => 'DifferentialCoreCustomField',
@@ -6132,6 +6135,7 @@
61326135
'PHUICurtainExtension' => 'Phobject',
61336136
'PHUICurtainPanelView' => 'AphrontTagView',
61346137
'PHUICurtainView' => 'AphrontTagView',
6138+
'PHUIDiffGraphView' => 'Phobject',
61356139
'PHUIDiffInlineCommentDetailView' => 'PHUIDiffInlineCommentView',
61366140
'PHUIDiffInlineCommentEditView' => 'PHUIDiffInlineCommentView',
61376141
'PHUIDiffInlineCommentRowScaffold' => 'AphrontView',

‎src/applications/differential/controller/DifferentialRevisionViewController.php

+160
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,21 @@ public function handleRequest(AphrontRequest $request) {
341341
->setKey('commits')
342342
->appendChild($local_table));
343343

344+
$stack_graph = id(new DifferentialStackGraph())
345+
->setSeedRevision($revision)
346+
->loadGraph();
347+
if (!$stack_graph->isEmpty()) {
348+
$stack_view = $this->renderStackView($revision, $stack_graph);
349+
list($stack_name, $stack_color, $stack_table) = $stack_view;
350+
351+
$tab_group->addTab(
352+
id(new PHUITabView())
353+
->setName($stack_name)
354+
->setKey('stack')
355+
->setColor($stack_color)
356+
->appendChild($stack_table));
357+
}
358+
344359
if ($other_view) {
345360
$tab_group->addTab(
346361
id(new PHUITabView())
@@ -1198,4 +1213,149 @@ private function buildUnitMessagesView(
11981213
}
11991214

12001215

1216+
private function renderStackView(
1217+
DifferentialRevision $current,
1218+
DifferentialStackGraph $graph) {
1219+
1220+
$ancestry = $graph->getParentEdges();
1221+
$viewer = $this->getViewer();
1222+
1223+
$revisions = id(new DifferentialRevisionQuery())
1224+
->setViewer($viewer)
1225+
->withPHIDs(array_keys($ancestry))
1226+
->execute();
1227+
$revisions = mpull($revisions, null, 'getPHID');
1228+
1229+
$order = id(new PhutilDirectedScalarGraph())
1230+
->addNodes($ancestry)
1231+
->getTopographicallySortedNodes();
1232+
1233+
$ancestry = array_select_keys($ancestry, $order);
1234+
1235+
$traces = id(new PHUIDiffGraphView())
1236+
->renderGraph($ancestry);
1237+
1238+
// Load author handles, and also revision handles for any revisions which
1239+
// we failed to load (they might be policy restricted).
1240+
$handle_phids = mpull($revisions, 'getAuthorPHID');
1241+
foreach ($order as $phid) {
1242+
if (empty($revisions[$phid])) {
1243+
$handle_phids[] = $phid;
1244+
}
1245+
}
1246+
$handles = $viewer->loadHandles($handle_phids);
1247+
1248+
$rows = array();
1249+
$rowc = array();
1250+
1251+
$ii = 0;
1252+
$seen = false;
1253+
foreach ($ancestry as $phid => $ignored) {
1254+
$revision = idx($revisions, $phid);
1255+
if ($revision) {
1256+
$status_icon = $revision->getStatusIcon();
1257+
$status_name = $revision->getStatusDisplayName();
1258+
1259+
$status = array(
1260+
id(new PHUIIconView())->setIcon($status_icon),
1261+
' ',
1262+
$status_name,
1263+
);
1264+
1265+
$author = $viewer->renderHandle($revision->getAuthorPHID());
1266+
$title = phutil_tag(
1267+
'a',
1268+
array(
1269+
'href' => $revision->getURI(),
1270+
),
1271+
array(
1272+
$revision->getMonogram(),
1273+
' ',
1274+
$revision->getTitle(),
1275+
));
1276+
} else {
1277+
$status = null;
1278+
$author = null;
1279+
$title = $viewer->renderHandle($phid);
1280+
}
1281+
1282+
$rows[] = array(
1283+
$traces[$ii++],
1284+
$status,
1285+
$author,
1286+
$title,
1287+
);
1288+
1289+
if ($phid == $current->getPHID()) {
1290+
$rowc[] = 'highlighted';
1291+
} else {
1292+
$rowc[] = null;
1293+
}
1294+
}
1295+
1296+
$stack_table = id(new AphrontTableView($rows))
1297+
->setHeaders(
1298+
array(
1299+
null,
1300+
pht('Status'),
1301+
pht('Author'),
1302+
pht('Revision'),
1303+
))
1304+
->setRowClasses($rowc)
1305+
->setColumnClasses(
1306+
array(
1307+
'threads',
1308+
null,
1309+
null,
1310+
'wide',
1311+
));
1312+
1313+
// Count how many revisions this one depends on that are not yet closed.
1314+
$seen = array();
1315+
$look = array($current->getPHID());
1316+
while ($look) {
1317+
$phid = array_pop($look);
1318+
1319+
$parents = idx($ancestry, $phid, array());
1320+
foreach ($parents as $parent) {
1321+
if (isset($seen[$parent])) {
1322+
continue;
1323+
}
1324+
1325+
$seen[$parent] = $parent;
1326+
$look[] = $parent;
1327+
}
1328+
}
1329+
1330+
$blocking_count = 0;
1331+
foreach ($seen as $parent) {
1332+
if ($parent == $current->getPHID()) {
1333+
continue;
1334+
}
1335+
1336+
$revision = idx($revisions, $parent);
1337+
if (!$revision) {
1338+
continue;
1339+
}
1340+
1341+
if ($revision->isClosed()) {
1342+
continue;
1343+
}
1344+
1345+
$blocking_count++;
1346+
}
1347+
1348+
if (!$blocking_count) {
1349+
$stack_name = pht('Stack');
1350+
$stack_color = null;
1351+
} else {
1352+
$stack_name = pht(
1353+
'Stack (%s Open)',
1354+
new PhutilNumber($blocking_count));
1355+
$stack_color = PHUIListItemView::STATUS_FAIL;
1356+
}
1357+
1358+
return array($stack_name, $stack_color, $stack_table);
1359+
}
1360+
12011361
}

‎src/applications/differential/customfield/DifferentialChildRevisionsField.php

-18
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,4 @@ public function getFieldDescription() {
1919
return pht('Lists revisions this one is depended on by.');
2020
}
2121

22-
public function shouldAppearInPropertyView() {
23-
return true;
24-
}
25-
26-
public function renderPropertyViewLabel() {
27-
return $this->getFieldName();
28-
}
29-
30-
public function getRequiredHandlePHIDsForPropertyView() {
31-
return PhabricatorEdgeQuery::loadDestinationPHIDs(
32-
$this->getObject()->getPHID(),
33-
DifferentialRevisionDependedOnByRevisionEdgeType::EDGECONST);
34-
}
35-
36-
public function renderPropertyViewValue(array $handles) {
37-
return $this->renderHandleList($handles);
38-
}
39-
4022
}

‎src/applications/differential/customfield/DifferentialParentRevisionsField.php

-18
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,6 @@ public function getFieldDescription() {
2323
return pht('Lists revisions this one depends on.');
2424
}
2525

26-
public function shouldAppearInPropertyView() {
27-
return true;
28-
}
29-
30-
public function renderPropertyViewLabel() {
31-
return $this->getFieldName();
32-
}
33-
34-
public function getRequiredHandlePHIDsForPropertyView() {
35-
return PhabricatorEdgeQuery::loadDestinationPHIDs(
36-
$this->getObject()->getPHID(),
37-
DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST);
38-
}
39-
40-
public function renderPropertyViewValue(array $handles) {
41-
return $this->renderHandleList($handles);
42-
}
43-
4426
public function getProTips() {
4527
return array(
4628
pht(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
final class DifferentialStackGraph
4+
extends AbstractDirectedGraph {
5+
6+
private $parentEdges = array();
7+
private $childEdges = array();
8+
9+
public function setSeedRevision(DifferentialRevision $revision) {
10+
return $this->addNodes(
11+
array(
12+
'<seed>' => array($revision->getPHID()),
13+
));
14+
}
15+
16+
public function isEmpty() {
17+
return (count($this->getNodes()) <= 2);
18+
}
19+
20+
public function getParentEdges() {
21+
return $this->parentEdges;
22+
}
23+
24+
protected function loadEdges(array $nodes) {
25+
$query = id(new PhabricatorEdgeQuery())
26+
->withSourcePHIDs($nodes)
27+
->withEdgeTypes(
28+
array(
29+
DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST,
30+
DifferentialRevisionDependedOnByRevisionEdgeType::EDGECONST,
31+
));
32+
33+
$query->execute();
34+
35+
$map = array();
36+
foreach ($nodes as $node) {
37+
$parents = $query->getDestinationPHIDs(
38+
array($node),
39+
array(
40+
DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST,
41+
));
42+
43+
$children = $query->getDestinationPHIDs(
44+
array($node),
45+
array(
46+
DifferentialRevisionDependedOnByRevisionEdgeType::EDGECONST,
47+
));
48+
49+
$this->parentEdges[$node] = $parents;
50+
$this->childEdges[$node] = $children;
51+
52+
$map[$node] = array_values(array_fuse($parents) + array_fuse($children));
53+
}
54+
55+
return $map;
56+
}
57+
58+
}

‎src/applications/differential/storage/DifferentialRevision.php

+29
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public function getMonogram() {
136136
return "D{$id}";
137137
}
138138

139+
public function getURI() {
140+
return '/'.$this->getMonogram();
141+
}
142+
139143
public function setTitle($title) {
140144
$this->title = $title;
141145
if (!$this->getID()) {
@@ -426,6 +430,31 @@ public function isClosed() {
426430
return DifferentialRevisionStatus::isClosedStatus($this->getStatus());
427431
}
428432

433+
public function getStatusIcon() {
434+
$map = array(
435+
ArcanistDifferentialRevisionStatus::NEEDS_REVIEW
436+
=> 'fa-code grey',
437+
ArcanistDifferentialRevisionStatus::NEEDS_REVISION
438+
=> 'fa-refresh red',
439+
ArcanistDifferentialRevisionStatus::CHANGES_PLANNED
440+
=> 'fa-headphones red',
441+
ArcanistDifferentialRevisionStatus::ACCEPTED
442+
=> 'fa-check green',
443+
ArcanistDifferentialRevisionStatus::CLOSED
444+
=> 'fa-check-square-o black',
445+
ArcanistDifferentialRevisionStatus::ABANDONED
446+
=> 'fa-plane black',
447+
);
448+
449+
return idx($map, $this->getStatus());
450+
}
451+
452+
public function getStatusDisplayName() {
453+
$status = $this->getStatus();
454+
return ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
455+
$status);
456+
}
457+
429458
public function getFlag(PhabricatorUser $viewer) {
430459
return $this->assertAttachedKey($this->flags, $viewer->getPHID());
431460
}

0 commit comments

Comments
 (0)
Failed to load comments.