@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class PHUIDiffTableOfContentsItemView extends AphrontView {
4
5 private $changeset;
6 private $isVisible = true;
7 private $anchor;
8 private $coverage;
9 private $coverageID;
10 private $context;
11 private $packages;
12
13 public function setChangeset(DifferentialChangeset $changeset) {
14 $this->changeset = $changeset;
15 return $this;
16 }
17
18 public function getChangeset() {
19 return $this->changeset;
20 }
21
22 public function setIsVisible($is_visible) {
23 $this->isVisible = $is_visible;
24 return $this;
25 }
26
27 public function getIsVisible() {
28 return $this->isVisible;
29 }
30
31 public function setAnchor($anchor) {
32 $this->anchor = $anchor;
33 return $this;
34 }
35
36 public function getAnchor() {
37 return $this->anchor;
38 }
39
40 public function setCoverage($coverage) {
41 $this->coverage = $coverage;
42 return $this;
43 }
44
45 /**
46 * Get the Coverage, expressed as a string, each letter with this meaning:
47 * N: Not Executable, C: Covered, U: Uncovered.
48 * @return string|null
49 */
50 public function getCoverage() {
51 return $this->coverage;
52 }
53
54 public function setCoverageID($coverage_id) {
55 $this->coverageID = $coverage_id;
56 return $this;
57 }
58
59 public function getCoverageID() {
60 return $this->coverageID;
61 }
62
63 public function setContext($context) {
64 $this->context = $context;
65 return $this;
66 }
67
68 public function getContext() {
69 return $this->context;
70 }
71
72 /**
73 * @param array<PhabricatorOwnersPackage> $packages
74 */
75 public function setPackages(array $packages) {
76 assert_instances_of($packages, PhabricatorOwnersPackage::class);
77 $this->packages = mpull($packages, null, 'getPHID');
78 return $this;
79 }
80
81 public function getPackages() {
82 return $this->packages;
83 }
84
85 public function render() {
86 $changeset = $this->getChangeset();
87
88 $cells = array();
89
90 $cells[] = $this->getContext();
91
92 $cells[] = $changeset->newFileTreeIcon();
93
94 $link = $this->renderChangesetLink();
95 $lines = $this->renderChangesetLines();
96 $meta = $this->renderChangesetMetadata();
97
98 $cells[] = array(
99 $link,
100 $lines,
101 $meta,
102 );
103
104 $cells[] = $this->renderCoverage();
105 $cells[] = $this->renderModifiedCoverage();
106
107 $cells[] = $this->renderPackages();
108
109 return $cells;
110 }
111
112 public function newLink() {
113 $anchor = $this->getAnchor();
114
115 $changeset = $this->getChangeset();
116 $name = $changeset->getDisplayFilename();
117 $name = basename($name);
118
119 return javelin_tag(
120 'a',
121 array(
122 'href' => '#'.$anchor,
123 'sigil' => 'differential-load',
124 'meta' => array(
125 'id' => 'diff-'.$anchor,
126 ),
127 ),
128 $name);
129 }
130
131 public function renderChangesetLines() {
132 $changeset = $this->getChangeset();
133
134 if ($changeset->getIsLowImportanceChangeset()) {
135 return null;
136 }
137
138 $line_count = $changeset->getAffectedLineCount();
139 if (!$line_count) {
140 return null;
141 }
142
143 return pht('%s line(s)', new PhutilNumber($line_count));
144 }
145
146 public function renderCoverage() {
147 $not_applicable = '-';
148
149 $coverage = $this->getCoverage();
150 if (!phutil_nonempty_string($coverage)) {
151 return $not_applicable;
152 }
153
154 $covered = substr_count($coverage, 'C');
155 $not_covered = substr_count($coverage, 'U');
156
157 if (!$not_covered && !$covered) {
158 return $not_applicable;
159 }
160
161 return sprintf('%d%%', 100 * ($covered / ($covered + $not_covered)));
162 }
163
164 public function renderModifiedCoverage() {
165 $not_applicable = '-';
166
167 $coverage = $this->getCoverage();
168 if (!phutil_nonempty_string($coverage)) {
169 return $not_applicable;
170 }
171
172 if ($this->getIsVisible()) {
173 $label = pht('Loading...');
174 } else {
175 $label = pht('?');
176 }
177
178 return phutil_tag(
179 'div',
180 array(
181 'id' => $this->getCoverageID(),
182 'class' => 'differential-mcoverage-loading',
183 ),
184 $label);
185 }
186
187 private function renderChangesetMetadata() {
188 $changeset = $this->getChangeset();
189 $type = $changeset->getChangeType();
190
191 $meta = array();
192 if (DifferentialChangeType::isOldLocationChangeType($type)) {
193 $away = $changeset->getAwayPaths();
194 if (count($away) > 1) {
195 if ($type == DifferentialChangeType::TYPE_MULTICOPY) {
196 $meta[] = pht('Deleted after being copied to multiple locations:');
197 } else {
198 $meta[] = pht('Copied to multiple locations:');
199 }
200 foreach ($away as $path) {
201 $meta[] = $path;
202 }
203 } else {
204 if ($type == DifferentialChangeType::TYPE_MOVE_AWAY) {
205 // This case is handled when we render the path.
206 } else {
207 $meta[] = pht('Copied to %s', head($away));
208 }
209 }
210 } else if ($type == DifferentialChangeType::TYPE_COPY_HERE) {
211 $meta[] = pht('Copied from %s', $changeset->getOldFile());
212 }
213
214 if (!$meta) {
215 return null;
216 }
217
218 $meta = phutil_implode_html(phutil_tag('br'), $meta);
219
220 return phutil_tag(
221 'div',
222 array(
223 'class' => 'differential-toc-meta',
224 ),
225 $meta);
226 }
227
228 public function renderPackages() {
229 $packages = $this->getPackages();
230
231 if (!$packages) {
232 return null;
233 }
234
235 $viewer = $this->getViewer();
236 $package_phids = mpull($packages, 'getPHID');
237
238 return $viewer->renderHandleList($package_phids)
239 ->setGlyphLimit(48);
240 }
241
242}