@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 DiffusionRepositoryBasicsManagementPanel
4 extends DiffusionRepositoryManagementPanel {
5
6 const PANELKEY = 'basics';
7
8 public function getManagementPanelLabel() {
9 return pht('Basics');
10 }
11
12 public function getManagementPanelOrder() {
13 return 100;
14 }
15
16 public function getManagementPanelIcon() {
17 return 'fa-code';
18 }
19
20 protected function getEditEngineFieldKeys() {
21 return array(
22 'name',
23 'callsign',
24 'shortName',
25 'description',
26 'projectPHIDs',
27 );
28 }
29
30 public function buildManagementPanelCurtain() {
31 $repository = $this->getRepository();
32 $viewer = $this->getViewer();
33
34 $action_list = $this->newActionList();
35
36 $can_edit = PhabricatorPolicyFilter::hasCapability(
37 $viewer,
38 $repository,
39 PhabricatorPolicyCapability::CAN_EDIT);
40
41 $edit_uri = $this->getEditPageURI();
42 $activate_uri = $repository->getPathURI('edit/activate/');
43 $delete_uri = $repository->getPathURI('edit/delete/');
44 $encoding_uri = $this->getEditPageURI('encoding');
45 $dangerous_uri = $repository->getPathURI('edit/dangerous/');
46 $enormous_uri = $repository->getPathURI('edit/enormous/');
47 $update_uri = $repository->getPathURI('edit/update/');
48 $publish_uri = $repository->getPathURI('edit/publish/');
49
50 if ($repository->isTracked()) {
51 $activate_icon = 'fa-ban';
52 $activate_label = pht('Deactivate Repository');
53 } else {
54 $activate_icon = 'fa-check';
55 $activate_label = pht('Activate Repository');
56 }
57
58 if (!$repository->isPublishingDisabled()) {
59 $publish_icon = 'fa-ban';
60 $publish_label = pht('Disable Publishing');
61 } else {
62 $publish_icon = 'fa-check';
63 $publish_label = pht('Enable Publishing');
64 }
65
66 $should_dangerous = $repository->shouldAllowDangerousChanges();
67 if ($should_dangerous) {
68 $dangerous_icon = 'fa-shield';
69 $dangerous_name = pht('Prevent Dangerous Changes');
70 $can_dangerous = $can_edit;
71 } else {
72 $dangerous_icon = 'fa-exclamation-triangle';
73 $dangerous_name = pht('Allow Dangerous Changes');
74 $can_dangerous = ($can_edit && $repository->canAllowDangerousChanges());
75 }
76
77 $should_enormous = $repository->shouldAllowEnormousChanges();
78 if ($should_enormous) {
79 $enormous_icon = 'fa-shield';
80 $enormous_name = pht('Prevent Enormous Changes');
81 $can_enormous = $can_edit;
82 } else {
83 $enormous_icon = 'fa-exclamation-triangle';
84 $enormous_name = pht('Allow Enormous Changes');
85 $can_enormous = ($can_edit && $repository->canAllowEnormousChanges());
86 }
87
88 $action_list->addAction(
89 id(new PhabricatorActionView())
90 ->setName(pht('Edit Basic Information'))
91 ->setHref($edit_uri)
92 ->setIcon('fa-pencil')
93 ->setDisabled(!$can_edit)
94 ->setWorkflow(!$can_edit));
95
96 $action_list->addAction(
97 id(new PhabricatorActionView())
98 ->setName(pht('Edit Text Encoding'))
99 ->setIcon('fa-text-width')
100 ->setHref($encoding_uri)
101 ->setDisabled(!$can_edit)
102 ->setWorkflow(!$can_edit));
103
104 $action_list->addAction(
105 id(new PhabricatorActionView())
106 ->setName($dangerous_name)
107 ->setHref($dangerous_uri)
108 ->setIcon($dangerous_icon)
109 ->setDisabled(!$can_dangerous)
110 ->setWorkflow(true));
111
112 $action_list->addAction(
113 id(new PhabricatorActionView())
114 ->setName($enormous_name)
115 ->setHref($enormous_uri)
116 ->setIcon($enormous_icon)
117 ->setDisabled(!$can_enormous)
118 ->setWorkflow(true));
119
120 $action_list->addAction(
121 id(new PhabricatorActionView())
122 ->setType(PhabricatorActionView::TYPE_DIVIDER));
123
124 $action_list->addAction(
125 id(new PhabricatorActionView())
126 ->setName($activate_label)
127 ->setHref($activate_uri)
128 ->setIcon($activate_icon)
129 ->setDisabled(!$can_edit)
130 ->setWorkflow(true));
131
132 $action_list->addAction(
133 id(new PhabricatorActionView())
134 ->setName($publish_label)
135 ->setHref($publish_uri)
136 ->setIcon($publish_icon)
137 ->setDisabled(!$can_edit)
138 ->setWorkflow(true));
139
140 $action_list->addAction(
141 id(new PhabricatorActionView())
142 ->setName(pht('Update Now'))
143 ->setHref($update_uri)
144 ->setIcon('fa-refresh')
145 ->setWorkflow(true)
146 ->setDisabled(!$can_edit));
147
148 $action_list->addAction(
149 id(new PhabricatorActionView())
150 ->setType(PhabricatorActionView::TYPE_DIVIDER));
151
152 $action_list->addAction(
153 id(new PhabricatorActionView())
154 ->setName(pht('Delete Repository'))
155 ->setHref($delete_uri)
156 ->setIcon('fa-times')
157 ->setWorkflow(true)
158 ->setDisabled(!$can_edit));
159
160 return $this->newCurtainView()
161 ->setActionList($action_list);
162 }
163
164 public function buildManagementPanelContent() {
165 $basics = $this->buildBasics();
166 $basics = $this->newBox(pht('Properties'), $basics);
167
168 $repository = $this->getRepository();
169
170 $state = $this->buildStateView($repository);
171
172 $is_new = $repository->isNewlyInitialized();
173 $info_view = null;
174 if ($is_new) {
175 $messages = array();
176
177 $messages[] = pht(
178 'This newly created repository is not active yet. Configure policies, '.
179 'options, and URIs. When ready, %s the repository.',
180 phutil_tag('strong', array(), pht('Activate')));
181
182 if ($repository->isHosted()) {
183 $messages[] = pht(
184 'If activated now, this repository will become a new hosted '.
185 'repository. To observe an existing repository instead, configure '.
186 'it in the %s panel.',
187 phutil_tag('strong', array(), pht('URIs')));
188 } else {
189 $messages[] = pht(
190 'If activated now, this repository will observe an existing remote '.
191 'repository and begin importing changes.');
192 }
193
194 $info_view = id(new PHUIInfoView())
195 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
196 ->setErrors($messages);
197 }
198
199 $description = $this->buildDescription();
200 if ($description) {
201 $description = $this->newBox(pht('Description'), $description);
202 }
203 $status = $this->buildStatus();
204
205 return array($info_view, $state, $basics, $description, $status);
206 }
207
208 private function buildBasics() {
209 $repository = $this->getRepository();
210 $viewer = $this->getViewer();
211
212 $view = id(new PHUIPropertyListView())
213 ->setViewer($viewer);
214
215 $name = $repository->getName();
216 $view->addProperty(pht('Name'), $name);
217
218 $type = PhabricatorRepositoryType::getNameForRepositoryType(
219 $repository->getVersionControlSystem());
220 $view->addProperty(pht('Type'), $type);
221
222 $callsign = $repository->getCallsign();
223 if (!phutil_nonempty_string($callsign)) {
224 $callsign = phutil_tag('em', array(), pht('No Callsign'));
225 }
226 $view->addProperty(pht('Callsign'), $callsign);
227
228 $short_name = $repository->getRepositorySlug();
229 if ($short_name === null) {
230 $short_name = phutil_tag('em', array(), pht('No Short Name'));
231 }
232 $view->addProperty(pht('Short Name'), $short_name);
233
234 $encoding = $repository->getDetail('encoding');
235 if (!$encoding) {
236 $encoding = phutil_tag('em', array(), pht('Use Default (UTF-8)'));
237 }
238 $view->addProperty(pht('Encoding'), $encoding);
239
240 $can_dangerous = $repository->canAllowDangerousChanges();
241 if (!$can_dangerous) {
242 $dangerous = phutil_tag('em', array(), pht('Not Preventable'));
243 } else {
244 $should_dangerous = $repository->shouldAllowDangerousChanges();
245 if ($should_dangerous) {
246 $dangerous = pht('Allowed');
247 } else {
248 $dangerous = pht('Not Allowed');
249 }
250 }
251
252 $view->addProperty(pht('Dangerous Changes'), $dangerous);
253
254 $can_enormous = $repository->canAllowEnormousChanges();
255 if (!$can_enormous) {
256 $enormous = phutil_tag('em', array(), pht('Not Preventable'));
257 } else {
258 $should_enormous = $repository->shouldAllowEnormousChanges();
259 if ($should_enormous) {
260 $enormous = pht('Allowed');
261 } else {
262 $enormous = pht('Not Allowed');
263 }
264 }
265
266 $view->addProperty(pht('Enormous Changes'), $enormous);
267
268 return $view;
269 }
270
271
272 private function buildDescription() {
273 $repository = $this->getRepository();
274 $viewer = $this->getViewer();
275
276 $description = $repository->getDetail('description');
277
278 $view = id(new PHUIPropertyListView())
279 ->setViewer($viewer);
280 if (!strlen($description)) {
281 return null;
282 } else {
283 $description = new PHUIRemarkupView($viewer, $description);
284 }
285 $view->addTextContent($description);
286
287 return $view;
288 }
289
290 private function buildStatus() {
291 $repository = $this->getRepository();
292 $viewer = $this->getViewer();
293
294 $view = id(new PHUIPropertyListView())
295 ->setViewer($viewer);
296
297 $view->addProperty(
298 pht('Update Frequency'),
299 $this->buildRepositoryUpdateInterval($repository));
300
301 $messages = $this->loadStatusMessages($repository);
302
303 $status = $this->buildRepositoryStatus($repository, $messages);
304 $raw_error = $this->buildRepositoryRawError($repository, $messages);
305
306 $view->addProperty(pht('Status'), $status);
307 if ($raw_error) {
308 $view->addSectionHeader(pht('Raw Error'));
309 $view->addTextContent($raw_error);
310 }
311
312 return $this->newBox(pht('Working Copy Status'), $view);
313 }
314
315 private function buildRepositoryUpdateInterval(
316 PhabricatorRepository $repository) {
317
318 $smart_wait = $repository->loadUpdateInterval();
319
320 $doc_href = PhabricatorEnv::getDoclink(
321 'Diffusion User Guide: Repository Updates');
322
323 return array(
324 phutil_format_relative_time_detailed($smart_wait),
325 " \xC2\xB7 ",
326 phutil_tag(
327 'a',
328 array(
329 'href' => $doc_href,
330 'target' => '_blank',
331 ),
332 pht('Learn More')),
333 );
334 }
335
336 private function buildRepositoryStatus(
337 PhabricatorRepository $repository,
338 array $messages) {
339
340 $viewer = $this->getViewer();
341 $is_cluster = $repository->getAlmanacServicePHID();
342
343 $view = new PHUIStatusListView();
344
345 if ($repository->isTracked()) {
346 $view->addItem(
347 id(new PHUIStatusItemView())
348 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
349 ->setTarget(pht('Repository Active')));
350 } else {
351 $view->addItem(
352 id(new PHUIStatusItemView())
353 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')
354 ->setTarget(pht('Repository Inactive'))
355 ->setNote(
356 pht('Activate this repository to begin or resume import.')));
357 return $view;
358 }
359
360 $binaries = array();
361 $svnlook_check = false;
362 switch ($repository->getVersionControlSystem()) {
363 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
364 $binaries[] = 'git';
365 break;
366 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
367 $binaries[] = 'svn';
368 break;
369 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
370 $binaries[] = 'hg';
371 break;
372 }
373
374 if ($repository->isHosted()) {
375 $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;
376 $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;
377 $can_http = $repository->canServeProtocol($proto_http, false) ||
378 $repository->canServeProtocol($proto_https, false);
379
380 if ($can_http) {
381 switch ($repository->getVersionControlSystem()) {
382 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
383 $binaries[] = 'git-http-backend';
384 break;
385 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
386 $binaries[] = 'svnserve';
387 $binaries[] = 'svnadmin';
388 $binaries[] = 'svnlook';
389 $svnlook_check = true;
390 break;
391 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
392 $binaries[] = 'hg';
393 break;
394 }
395 }
396
397
398 $proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;
399 $can_ssh = $repository->canServeProtocol($proto_ssh, false);
400
401 if ($can_ssh) {
402 switch ($repository->getVersionControlSystem()) {
403 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
404 $binaries[] = 'git-receive-pack';
405 $binaries[] = 'git-upload-pack';
406 break;
407 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
408 $binaries[] = 'svnserve';
409 $binaries[] = 'svnadmin';
410 $binaries[] = 'svnlook';
411 $svnlook_check = true;
412 break;
413 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
414 $binaries[] = 'hg';
415 break;
416 }
417 }
418 }
419
420 $binaries = array_unique($binaries);
421 if (!$is_cluster) {
422 // We're only checking for binaries if we aren't running with a cluster
423 // configuration. In theory, we could check for binaries on the
424 // repository host machine, but we'd need to make this more complicated
425 // to do that.
426
427 foreach ($binaries as $binary) {
428 $where = Filesystem::resolveBinary($binary);
429 if (!$where) {
430 $view->addItem(
431 id(new PHUIStatusItemView())
432 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
433 ->setTarget(
434 pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
435 ->setNote(pht(
436 "Unable to find this binary in the webserver's PATH. You may ".
437 "need to configure %s.",
438 $this->getEnvConfigLink())));
439 } else {
440 $view->addItem(
441 id(new PHUIStatusItemView())
442 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
443 ->setTarget(
444 pht('Found Binary %s', phutil_tag('tt', array(), $binary)))
445 ->setNote(phutil_tag('tt', array(), $where)));
446 }
447 }
448
449 // This gets checked generically above. However, for svn commit hooks, we
450 // need this to be in environment.append-paths because subversion strips
451 // PATH.
452 if ($svnlook_check) {
453 $where = Filesystem::resolveBinary('svnlook');
454 if ($where) {
455 $path = substr($where, 0, strlen($where) - strlen('svnlook'));
456 $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths');
457 $in_path = false;
458 foreach ($dirs as $dir) {
459 if (Filesystem::isDescendant($path, $dir)) {
460 $in_path = true;
461 break;
462 }
463 }
464 if (!$in_path) {
465 $view->addItem(
466 id(new PHUIStatusItemView())
467 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
468 ->setTarget(
469 pht('Commit Hooks: %s', phutil_tag('tt', array(), $binary)))
470 ->setNote(
471 pht(
472 'The directory containing the "svnlook" binary is not '.
473 'listed in "environment.append-paths", so commit hooks '.
474 '(which execute with an empty "PATH") will not be able to '.
475 'find "svnlook". Add `%s` to %s.',
476 $path,
477 $this->getEnvConfigLink())));
478 }
479 }
480 }
481 }
482
483 $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd');
484
485 $daemon_instructions = pht(
486 'Use %s to start daemons. See %s.',
487 phutil_tag('tt', array(), 'bin/phd start'),
488 phutil_tag(
489 'a',
490 array(
491 'href' => $doc_href,
492 ),
493 pht('Managing Daemons with phd')));
494
495
496 $pull_daemon = id(new PhabricatorDaemonLogQuery())
497 ->setViewer(PhabricatorUser::getOmnipotentUser())
498 ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
499 ->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))
500 ->setLimit(1)
501 ->execute();
502
503 if ($pull_daemon) {
504
505 // TODO: In a cluster environment, we need a daemon on this repository's
506 // host, specifically, and we aren't checking for that right now. This
507 // is a reasonable proxy for things being more-or-less correctly set up,
508 // though.
509
510 $view->addItem(
511 id(new PHUIStatusItemView())
512 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
513 ->setTarget(pht('Pull Daemon Running')));
514 } else {
515 $view->addItem(
516 id(new PHUIStatusItemView())
517 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
518 ->setTarget(pht('Pull Daemon Not Running'))
519 ->setNote($daemon_instructions));
520 }
521
522
523 $task_daemon = id(new PhabricatorDaemonLogQuery())
524 ->setViewer(PhabricatorUser::getOmnipotentUser())
525 ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
526 ->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
527 ->setLimit(1)
528 ->execute();
529 if ($task_daemon) {
530 $view->addItem(
531 id(new PHUIStatusItemView())
532 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
533 ->setTarget(pht('Task Daemon Running')));
534 } else {
535 $view->addItem(
536 id(new PHUIStatusItemView())
537 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
538 ->setTarget(pht('Task Daemon Not Running'))
539 ->setNote($daemon_instructions));
540 }
541
542
543 if ($is_cluster) {
544 // Just omit this status check for now in cluster environments. We
545 // could make a service call and pull it from the repository host
546 // eventually.
547 } else if ($repository->usesLocalWorkingCopy()) {
548 $local_parent = dirname($repository->getLocalPath());
549 if (Filesystem::pathExists($local_parent)) {
550 $view->addItem(
551 id(new PHUIStatusItemView())
552 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
553 ->setTarget(pht('Storage Directory OK'))
554 ->setNote(phutil_tag('tt', array(), $local_parent)));
555 } else {
556 $view->addItem(
557 id(new PHUIStatusItemView())
558 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
559 ->setTarget(pht('No Storage Directory'))
560 ->setNote(
561 pht(
562 'Storage directory %s does not exist, or is not readable by '.
563 'the webserver. Create this directory or make it readable.',
564 phutil_tag('tt', array(), $local_parent))));
565 return $view;
566 }
567
568 $local_path = $repository->getLocalPath();
569 $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
570 if ($message) {
571 switch ($message->getStatusCode()) {
572 case PhabricatorRepositoryStatusMessage::CODE_ERROR:
573 $view->addItem(
574 id(new PHUIStatusItemView())
575 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
576 ->setTarget(pht('Initialization Error'))
577 ->setNote($message->getParameter('message')));
578 return $view;
579 case PhabricatorRepositoryStatusMessage::CODE_OKAY:
580 if (Filesystem::pathExists($local_path)) {
581 $view->addItem(
582 id(new PHUIStatusItemView())
583 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
584 ->setTarget(pht('Working Copy OK'))
585 ->setNote(phutil_tag('tt', array(), $local_path)));
586 } else {
587 $view->addItem(
588 id(new PHUIStatusItemView())
589 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
590 ->setTarget(pht('Working Copy Error'))
591 ->setNote(
592 pht(
593 'Working copy %s has been deleted, or is not '.
594 'readable by the webserver. Make this directory '.
595 'readable. If it has been deleted, the daemons should '.
596 'restore it automatically.',
597 phutil_tag('tt', array(), $local_path))));
598 return $view;
599 }
600 break;
601 default:
602 $view->addItem(
603 id(new PHUIStatusItemView())
604 ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
605 ->setTarget(pht('Initializing Working Copy'))
606 ->setNote(pht('Daemons are initializing the working copy.')));
607 return $view;
608 }
609 } else {
610 $view->addItem(
611 id(new PHUIStatusItemView())
612 ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
613 ->setTarget(pht('No Working Copy Yet'))
614 ->setNote(
615 pht('Waiting for daemons to build a working copy.')));
616 return $view;
617 }
618 }
619
620 $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
621 if ($message) {
622 switch ($message->getStatusCode()) {
623 case PhabricatorRepositoryStatusMessage::CODE_ERROR:
624 $message = $message->getParameter('message');
625
626 $suggestion = null;
627 if (preg_match('/Permission denied \(publickey\)./', $message)) {
628 $suggestion = pht(
629 'Public Key Error: This error usually indicates that the '.
630 'keypair you have configured does not have permission to '.
631 'access the repository.');
632 }
633
634 $view->addItem(
635 id(new PHUIStatusItemView())
636 ->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
637 ->setTarget(pht('Update Error'))
638 ->setNote($suggestion));
639 return $view;
640 case PhabricatorRepositoryStatusMessage::CODE_OKAY:
641 $ago = (PhabricatorTime::getNow() - $message->getEpoch());
642 $view->addItem(
643 id(new PHUIStatusItemView())
644 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
645 ->setTarget(pht('Updates OK'))
646 ->setNote(
647 pht(
648 'Last updated %s (%s ago).',
649 phabricator_datetime($message->getEpoch(), $viewer),
650 phutil_format_relative_time_detailed($ago))));
651 break;
652 }
653 } else {
654 $view->addItem(
655 id(new PHUIStatusItemView())
656 ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
657 ->setTarget(pht('Waiting For Update'))
658 ->setNote(
659 pht('Waiting for daemons to read updates.')));
660 }
661
662 if ($repository->isImporting()) {
663 $ratio = $repository->loadImportProgress();
664 $percentage = sprintf('%.2f%%', 100 * $ratio);
665
666 $view->addItem(
667 id(new PHUIStatusItemView())
668 ->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
669 ->setTarget(pht('Importing'))
670 ->setNote(
671 pht('%s Complete', $percentage)));
672 } else {
673 $view->addItem(
674 id(new PHUIStatusItemView())
675 ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
676 ->setTarget(pht('Fully Imported')));
677 }
678
679 if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
680 $view->addItem(
681 id(new PHUIStatusItemView())
682 ->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')
683 ->setTarget(pht('Prioritized'))
684 ->setNote(pht('This repository will be updated soon!')));
685 }
686
687 return $view;
688 }
689
690 private function buildRepositoryRawError(
691 PhabricatorRepository $repository,
692 array $messages) {
693 $viewer = $this->getViewer();
694
695 $can_edit = PhabricatorPolicyFilter::hasCapability(
696 $viewer,
697 $repository,
698 PhabricatorPolicyCapability::CAN_EDIT);
699
700 $raw_error = null;
701
702 $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
703 if ($message) {
704 switch ($message->getStatusCode()) {
705 case PhabricatorRepositoryStatusMessage::CODE_ERROR:
706 $raw_error = $message->getParameter('message');
707 break;
708 }
709 }
710
711 if ($raw_error !== null) {
712 if (!$can_edit) {
713 $raw_message = pht(
714 'You must be able to edit a repository to see raw error messages '.
715 'because they sometimes disclose sensitive information.');
716 $raw_message = phutil_tag('em', array(), $raw_message);
717 } else {
718 $raw_message = phutil_escape_html_newlines($raw_error);
719 }
720 } else {
721 $raw_message = null;
722 }
723
724 return $raw_message;
725 }
726
727 private function loadStatusMessages(PhabricatorRepository $repository) {
728 $messages = id(new PhabricatorRepositoryStatusMessage())
729 ->loadAllWhere('repositoryID = %d', $repository->getID());
730 $messages = mpull($messages, null, 'getStatusType');
731
732 return $messages;
733 }
734
735 private function getEnvConfigLink() {
736 $config_href = '/config/edit/environment.append-paths/';
737 return phutil_tag(
738 'a',
739 array(
740 'href' => $config_href,
741 ),
742 'environment.append-paths');
743 }
744
745 private function buildStateView(PhabricatorRepository $repository) {
746 $viewer = $this->getViewer();
747 $is_new = $repository->isNewlyInitialized();
748
749 $view = id(new PHUIPropertyListView())
750 ->setViewer($viewer);
751
752 if (!$repository->isTracked()) {
753 if ($is_new) {
754 $active_icon = 'fa-ban';
755 $active_color = 'yellow';
756 $active_label = pht('Not Activated Yet');
757 $active_note = pht('Complete Setup and Activate Repository');
758 } else {
759 $active_icon = 'fa-times';
760 $active_color = 'red';
761 $active_label = pht('Not Active');
762 $active_note = pht('Repository Disabled');
763 }
764 } else if ($repository->isImporting()) {
765 $active_icon = 'fa-hourglass';
766 $active_color = 'yellow';
767 $active_label = pht('Importing...');
768 $active_note = null;
769 } else {
770 $active_icon = 'fa-check';
771 $active_color = 'green';
772 $active_label = pht('Repository Active');
773 $active_note = null;
774 }
775
776 $active_view = id(new PHUIStatusListView())
777 ->addItem(
778 id(new PHUIStatusItemView())
779 ->setIcon($active_icon, $active_color)
780 ->setTarget($active_label)
781 ->setNote($active_note));
782
783 if ($repository->isPublishingDisabled()) {
784 $publishing_icon = 'fa-times';
785 $publishing_color = 'red';
786 $publishing_label = pht('Not Publishing');
787 $publishing_note = pht('Publishing Disabled');
788 } else if (!$repository->isTracked()) {
789 $publishing_icon = 'fa-ban';
790 $publishing_color = 'yellow';
791 $publishing_label = pht('Not Publishing');
792 if ($is_new) {
793 $publishing_note = pht('Repository Not Active Yet');
794 } else {
795 $publishing_note = pht('Repository Inactive');
796 }
797 } else if ($repository->isImporting()) {
798 $publishing_icon = 'fa-ban';
799 $publishing_color = 'yellow';
800 $publishing_label = pht('Not Publishing');
801 $publishing_note = pht('Repository Importing');
802 } else {
803 $publishing_icon = 'fa-check';
804 $publishing_color = 'green';
805 $publishing_label = pht('Publishing Active');
806 $publishing_note = null;
807 }
808
809 $publishing_view = id(new PHUIStatusListView())
810 ->addItem(
811 id(new PHUIStatusItemView())
812 ->setIcon($publishing_icon, $publishing_color)
813 ->setTarget($publishing_label)
814 ->setNote($publishing_note));
815
816 $view->addProperty(pht('Active'), $active_view);
817 $view->addProperty(pht('Publishing'), $publishing_view);
818
819 return $this->newBox(pht('State'), $view);
820 }
821
822}