Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/config/controller/PhabricatorConfigAllController.php b/src/applications/config/controller/PhabricatorConfigAllController.php
index 3a19eff006..7452b29e21 100644
--- a/src/applications/config/controller/PhabricatorConfigAllController.php
+++ b/src/applications/config/controller/PhabricatorConfigAllController.php
@@ -1,78 +1,77 @@
<?php
final class PhabricatorConfigAllController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$db_values = id(new PhabricatorConfigEntry())
->loadAllWhere('namespace = %s', 'default');
$db_values = mpull($db_values, null, 'getConfigKey');
$rows = array();
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
ksort($options);
foreach ($options as $option) {
$key = $option->getKey();
if ($option->getHidden()) {
$value = phutil_tag('em', array(), pht('Hidden'));
} else {
$value = PhabricatorEnv::getEnvConfig($key);
$value = PhabricatorConfigJSON::prettyPrintJSON($value);
}
$db_value = idx($db_values, $key);
$rows[] = array(
phutil_tag(
'a',
array(
'href' => $this->getApplicationURI('edit/'.$key.'/'),
),
$key),
$value,
$db_value && !$db_value->getIsDeleted() ? pht('Customized') : '',
);
}
$table = id(new AphrontTableView($rows))
->setColumnClasses(
array(
'',
'wide',
))
->setHeaders(
array(
pht('Key'),
pht('Value'),
pht('Customized'),
));
$title = pht('Current Settings');
$header = $this->buildHeaderView($title);
$nav = $this->buildSideNavView();
$nav->selectFilter('all/');
$view = $this->buildConfigBoxView(
pht('All Settings'),
$table);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($view);
+ ->setFooter($view);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigApplicationController.php b/src/applications/config/controller/PhabricatorConfigApplicationController.php
index b4f60982e7..a6b8cd38c6 100644
--- a/src/applications/config/controller/PhabricatorConfigApplicationController.php
+++ b/src/applications/config/controller/PhabricatorConfigApplicationController.php
@@ -1,58 +1,57 @@
<?php
final class PhabricatorConfigApplicationController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$nav = $this->buildSideNavView();
$nav->selectFilter('application/');
$groups = PhabricatorApplicationConfigOptions::loadAll();
$apps_list = $this->buildConfigOptionsList($groups, 'apps');
$apps_list = $this->buildConfigBoxView(pht('Applications'), $apps_list);
$title = pht('Application Settings');
$header = $this->buildHeaderView($title);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($apps_list);
+ ->setFooter($apps_list);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildConfigOptionsList(array $groups, $type) {
assert_instances_of($groups, 'PhabricatorApplicationConfigOptions');
$list = new PHUIObjectItemListView();
$list->setBig(true);
$groups = msort($groups, 'getName');
foreach ($groups as $group) {
if ($group->getGroup() == $type) {
$icon = id(new PHUIIconView())
->setIcon($group->getIcon())
->setBackground('bg-violet');
$item = id(new PHUIObjectItemView())
->setHeader($group->getName())
->setHref('/config/group/'.$group->getKey().'/')
->addAttribute($group->getDescription())
->setImageIcon($icon);
$list->addItem($item);
}
}
return $list;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php
index a23ab1f9c1..36642657c9 100644
--- a/src/applications/config/controller/PhabricatorConfigCacheController.php
+++ b/src/applications/config/controller/PhabricatorConfigCacheController.php
@@ -1,177 +1,176 @@
<?php
final class PhabricatorConfigCacheController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$nav = $this->buildSideNavView();
$nav->selectFilter('cache/');
$purge_button = id(new PHUIButtonView())
->setText(pht('Purge Caches'))
->setHref('/config/cache/purge/')
->setTag('a')
->setWorkflow(true)
->setIcon('fa-exclamation-triangle');
$title = pht('Cache Status');
$header = $this->buildHeaderView($title, $purge_button);
$code_box = $this->renderCodeBox();
$data_box = $this->renderDataBox();
$page = array(
$code_box,
$data_box,
);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($page);
+ ->setFooter($page);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function renderCodeBox() {
$cache = PhabricatorOpcodeCacheSpec::getActiveCacheSpec();
$properties = id(new PHUIPropertyListView());
$this->renderCommonProperties($properties, $cache);
return $this->buildConfigBoxView(pht('Opcode Cache'), $properties);
}
private function renderDataBox() {
$cache = PhabricatorDataCacheSpec::getActiveCacheSpec();
$properties = id(new PHUIPropertyListView());
$this->renderCommonProperties($properties, $cache);
$table = null;
if ($cache->getName() !== null) {
$total_memory = $cache->getTotalMemory();
$summary = $cache->getCacheSummary();
$summary = isort($summary, 'total');
$summary = array_reverse($summary, true);
$rows = array();
foreach ($summary as $key => $info) {
$rows[] = array(
$key,
pht('%s', new PhutilNumber($info['count'])),
phutil_format_bytes($info['max']),
phutil_format_bytes($info['total']),
sprintf('%.1f%%', (100 * ($info['total'] / $total_memory))),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Pattern'),
pht('Count'),
pht('Largest'),
pht('Total'),
pht('Usage'),
))
->setColumnClasses(
array(
'wide',
'n',
'n',
'n',
'n',
));
}
$properties = $this->buildConfigBoxView(pht('Data Cache'), $properties);
$table = $this->buildConfigBoxView(pht('Cache Storage'), $table);
return array($properties, $table);
}
private function renderCommonProperties(
PHUIPropertyListView $properties,
PhabricatorCacheSpec $cache) {
if ($cache->getName() !== null) {
$name = $this->renderYes($cache->getName());
} else {
$name = $this->renderNo(pht('None'));
}
$properties->addProperty(pht('Cache'), $name);
if ($cache->getIsEnabled()) {
$enabled = $this->renderYes(pht('Enabled'));
} else {
$enabled = $this->renderNo(pht('Not Enabled'));
}
$properties->addProperty(pht('Enabled'), $enabled);
$version = $cache->getVersion();
if ($version) {
$properties->addProperty(pht('Version'), $this->renderInfo($version));
}
if ($cache->getName() === null) {
return;
}
$mem_total = $cache->getTotalMemory();
$mem_used = $cache->getUsedMemory();
if ($mem_total) {
$percent = 100 * ($mem_used / $mem_total);
$properties->addProperty(
pht('Memory Usage'),
pht(
'%s of %s',
phutil_tag('strong', array(), sprintf('%.1f%%', $percent)),
phutil_format_bytes($mem_total)));
}
$entry_count = $cache->getEntryCount();
if ($entry_count !== null) {
$properties->addProperty(
pht('Cache Entries'),
pht('%s', new PhutilNumber($entry_count)));
}
}
private function renderYes($info) {
return array(
id(new PHUIIconView())->setIcon('fa-check', 'green'),
' ',
$info,
);
}
private function renderNo($info) {
return array(
id(new PHUIIconView())->setIcon('fa-times-circle', 'red'),
' ',
$info,
);
}
private function renderInfo($info) {
return array(
id(new PHUIIconView())->setIcon('fa-info-circle', 'grey'),
' ',
$info,
);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php
index 43e5a15b9d..417fa9d3a1 100644
--- a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php
+++ b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php
@@ -1,242 +1,241 @@
<?php
final class PhabricatorConfigClusterDatabasesController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$nav = $this->buildSideNavView();
$nav->selectFilter('cluster/databases/');
$title = pht('Cluster Database Status');
$doc_href = PhabricatorEnv::getDoclink('Cluster: Databases');
$button = id(new PHUIButtonView())
->setIcon('fa-book')
->setHref($doc_href)
->setTag('a')
->setText(pht('Documentation'));
$header = $this->buildHeaderView($title, $button);
$database_status = $this->buildClusterDatabaseStatus();
$status = $this->buildConfigBoxView(pht('Status'), $database_status);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($status);
+ ->setFooter($status);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildClusterDatabaseStatus() {
$viewer = $this->getViewer();
$databases = PhabricatorDatabaseRef::queryAll();
$connection_map = PhabricatorDatabaseRef::getConnectionStatusMap();
$replica_map = PhabricatorDatabaseRef::getReplicaStatusMap();
Javelin::initBehavior('phabricator-tooltips');
$rows = array();
foreach ($databases as $database) {
$messages = array();
if ($database->getIsMaster()) {
$role_icon = id(new PHUIIconView())
->setIcon('fa-database sky')
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => pht('Master'),
));
} else {
$role_icon = id(new PHUIIconView())
->setIcon('fa-download')
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => pht('Replica'),
));
}
if ($database->getDisabled()) {
$conn_icon = 'fa-times';
$conn_color = 'grey';
$conn_label = pht('Disabled');
} else {
$status = $database->getConnectionStatus();
$info = idx($connection_map, $status, array());
$conn_icon = idx($info, 'icon');
$conn_color = idx($info, 'color');
$conn_label = idx($info, 'label');
if ($status === PhabricatorDatabaseRef::STATUS_OKAY) {
$latency = $database->getConnectionLatency();
$latency = (int)(1000000 * $latency);
$conn_label = pht('%s us', new PhutilNumber($latency));
}
}
$connection = array(
id(new PHUIIconView())->setIcon("{$conn_icon} {$conn_color}"),
' ',
$conn_label,
);
if ($database->getDisabled()) {
$replica_icon = 'fa-times';
$replica_color = 'grey';
$replica_label = pht('Disabled');
} else {
$status = $database->getReplicaStatus();
$info = idx($replica_map, $status, array());
$replica_icon = idx($info, 'icon');
$replica_color = idx($info, 'color');
$replica_label = idx($info, 'label');
if ($database->getIsMaster()) {
if ($status === PhabricatorDatabaseRef::REPLICATION_OKAY) {
$replica_icon = 'fa-database';
}
} else {
switch ($status) {
case PhabricatorDatabaseRef::REPLICATION_OKAY:
case PhabricatorDatabaseRef::REPLICATION_SLOW:
$delay = $database->getReplicaDelay();
if ($delay) {
$replica_label = pht('%ss Behind', new PhutilNumber($delay));
} else {
$replica_label = pht('Up to Date');
}
break;
}
}
}
$replication = array(
id(new PHUIIconView())->setIcon("{$replica_icon} {$replica_color}"),
' ',
$replica_label,
);
$health = $database->getHealthRecord();
$health_up = $health->getUpEventCount();
$health_down = $health->getDownEventCount();
if ($health->getIsHealthy()) {
$health_icon = id(new PHUIIconView())
->setIcon('fa-plus green');
} else {
$health_icon = id(new PHUIIconView())
->setIcon('fa-times red');
$messages[] = pht(
'UNHEALTHY: This database has failed recent health checks. Traffic '.
'will not be sent to it until it recovers.');
}
$health_count = pht(
'%s / %s',
new PhutilNumber($health_up),
new PhutilNumber($health_up + $health_down));
$health_status = array(
$health_icon,
' ',
$health_count,
);
$conn_message = $database->getConnectionMessage();
if ($conn_message) {
$messages[] = $conn_message;
}
$replica_message = $database->getReplicaMessage();
if ($replica_message) {
$messages[] = $replica_message;
}
$messages = phutil_implode_html(phutil_tag('br'), $messages);
$partition = null;
if ($database->getIsMaster()) {
if ($database->getIsDefaultPartition()) {
$partition = id(new PHUIIconView())
->setIcon('fa-circle sky')
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => pht('Default Partition'),
));
} else {
$map = $database->getApplicationMap();
if ($map) {
$list = implode(', ', $map);
} else {
$list = pht('Empty');
}
$partition = id(new PHUIIconView())
->setIcon('fa-adjust sky')
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => pht('Partition: %s', $list),
));
}
}
$rows[] = array(
$role_icon,
$partition,
$database->getHost(),
$database->getPort(),
$database->getUser(),
$connection,
$replication,
$health_status,
$messages,
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(
pht('Phabricator is not configured in cluster mode.'))
->setHeaders(
array(
null,
null,
pht('Host'),
pht('Port'),
pht('User'),
pht('Connection'),
pht('Replication'),
pht('Health'),
pht('Messages'),
))
->setColumnClasses(
array(
null,
null,
null,
null,
null,
null,
null,
null,
'wide',
));
return $table;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php
index 443b51a903..e9f64d411a 100644
--- a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php
+++ b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php
@@ -1,176 +1,175 @@
<?php
final class PhabricatorConfigClusterNotificationsController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$nav = $this->buildSideNavView();
$nav->selectFilter('cluster/notifications/');
$title = pht('Cluster Notifications');
$doc_href = PhabricatorEnv::getDoclink('Cluster: Notifications');
$button = id(new PHUIButtonView())
->setIcon('fa-book')
->setHref($doc_href)
->setTag('a')
->setText(pht('Documentation'));
$header = $this->buildHeaderView($title, $button);
$notification_status = $this->buildClusterNotificationStatus();
$status = $this->buildConfigBoxView(
pht('Notifications Status'),
$notification_status);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($status);
+ ->setFooter($status);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildClusterNotificationStatus() {
$viewer = $this->getViewer();
$servers = PhabricatorNotificationServerRef::newRefs();
Javelin::initBehavior('phabricator-tooltips');
$rows = array();
foreach ($servers as $server) {
if ($server->isAdminServer()) {
$type_icon = 'fa-database sky';
$type_tip = pht('Admin Server');
} else {
$type_icon = 'fa-bell sky';
$type_tip = pht('Client Server');
}
$type_icon = id(new PHUIIconView())
->setIcon($type_icon)
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => $type_tip,
));
$messages = array();
$details = array();
if ($server->isAdminServer()) {
try {
$details = $server->loadServerStatus();
$status_icon = 'fa-exchange green';
$status_label = pht('Version %s', idx($details, 'version'));
} catch (Exception $ex) {
$status_icon = 'fa-times red';
$status_label = pht('Connection Error');
$messages[] = $ex->getMessage();
}
} else {
try {
$server->testClient();
$status_icon = 'fa-exchange green';
$status_label = pht('Connected');
} catch (Exception $ex) {
$status_icon = 'fa-times red';
$status_label = pht('Connection Error');
$messages[] = $ex->getMessage();
}
}
if ($details) {
$uptime = idx($details, 'uptime');
$uptime = $uptime / 1000;
$uptime = phutil_format_relative_time_detailed($uptime);
$clients = pht(
'%s Active / %s Total',
new PhutilNumber(idx($details, 'clients.active')),
new PhutilNumber(idx($details, 'clients.total')));
$stats = pht(
'%s In / %s Out',
new PhutilNumber(idx($details, 'messages.in')),
new PhutilNumber(idx($details, 'messages.out')));
if (idx($details, 'history.size')) {
$history = pht(
'%s Held / %sms',
new PhutilNumber(idx($details, 'history.size')),
new PhutilNumber(idx($details, 'history.age')));
} else {
$history = pht('No Messages');
}
} else {
$uptime = null;
$clients = null;
$stats = null;
$history = null;
}
$status_view = array(
id(new PHUIIconView())->setIcon($status_icon),
' ',
$status_label,
);
$messages = phutil_implode_html(phutil_tag('br'), $messages);
$rows[] = array(
$type_icon,
$server->getProtocol(),
$server->getHost(),
$server->getPort(),
$status_view,
$uptime,
$clients,
$stats,
$history,
$messages,
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(
pht('No notification servers are configured.'))
->setHeaders(
array(
null,
pht('Proto'),
pht('Host'),
pht('Port'),
pht('Status'),
pht('Uptime'),
pht('Clients'),
pht('Messages'),
pht('History'),
null,
))
->setColumnClasses(
array(
null,
null,
null,
null,
null,
null,
null,
null,
null,
'wide',
));
return $table;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php
index 471c4cedf0..eb83a28a2a 100644
--- a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php
+++ b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php
@@ -1,420 +1,420 @@
<?php
final class PhabricatorConfigClusterRepositoriesController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$nav = $this->buildSideNavView();
$nav->selectFilter('cluster/repositories/');
$title = pht('Cluster Repository Status');
$doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories');
$button = id(new PHUIButtonView())
->setIcon('fa-book')
->setHref($doc_href)
->setTag('a')
->setText(pht('Documentation'));
$header = $this->buildHeaderView($title, $button);
$repository_status = $this->buildClusterRepositoryStatus();
$repo_status = $this->buildConfigBoxView(
pht('Repository Status'), $repository_status);
$repository_errors = $this->buildClusterRepositoryErrors();
$repo_errors = $this->buildConfigBoxView(
pht('Repository Errors'), $repository_errors);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn(array(
- $repo_status,
- $repo_errors,
- ));
+ ->setFooter(
+ array(
+ $repo_status,
+ $repo_errors,
+ ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildClusterRepositoryStatus() {
$viewer = $this->getViewer();
Javelin::initBehavior('phabricator-tooltips');
$all_services = id(new AlmanacServiceQuery())
->setViewer($viewer)
->withServiceTypes(
array(
AlmanacClusterRepositoryServiceType::SERVICETYPE,
))
->needBindings(true)
->needProperties(true)
->execute();
$all_services = mpull($all_services, null, 'getPHID');
$all_repositories = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withTypes(
array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
))
->execute();
$all_repositories = mpull($all_repositories, null, 'getPHID');
$all_versions = id(new PhabricatorRepositoryWorkingCopyVersion())
->loadAll();
$all_devices = $this->getDevices($all_services, false);
$all_active_devices = $this->getDevices($all_services, true);
$leader_versions = $this->getLeaderVersionsByRepository(
$all_repositories,
$all_versions,
$all_active_devices);
$push_times = $this->loadLeaderPushTimes($leader_versions);
$repository_groups = mgroup($all_repositories, 'getAlmanacServicePHID');
$repository_versions = mgroup($all_versions, 'getRepositoryPHID');
$rows = array();
foreach ($all_services as $service) {
$service_phid = $service->getPHID();
if ($service->getAlmanacPropertyValue('closed')) {
$status_icon = 'fa-folder';
$status_tip = pht('Closed');
} else {
$status_icon = 'fa-folder-open green';
$status_tip = pht('Open');
}
$status_icon = id(new PHUIIconView())
->setIcon($status_icon)
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => $status_tip,
));
$devices = idx($all_devices, $service_phid, array());
$active_devices = idx($all_active_devices, $service_phid, array());
$device_icon = 'fa-server green';
$device_label = pht(
'%s Active',
phutil_count($active_devices));
$device_status = array(
id(new PHUIIconView())->setIcon($device_icon),
' ',
$device_label,
);
$repositories = idx($repository_groups, $service_phid, array());
$repository_status = pht(
'%s',
phutil_count($repositories));
$no_leader = array();
$full_sync = array();
$partial_sync = array();
$no_sync = array();
$lag = array();
// Threshold in seconds before we start complaining that repositories
// are not synchronized when there is only one leader.
$threshold = phutil_units('5 minutes in seconds');
$messages = array();
foreach ($repositories as $repository) {
$repository_phid = $repository->getPHID();
$leader_version = idx($leader_versions, $repository_phid);
if ($leader_version === null) {
$no_leader[] = $repository;
$messages[] = pht(
'Repository %s has an ambiguous leader.',
$viewer->renderHandle($repository_phid)->render());
continue;
}
$versions = idx($repository_versions, $repository_phid, array());
// Filter out any versions for devices which are no longer active.
foreach ($versions as $key => $version) {
$version_device_phid = $version->getDevicePHID();
if (empty($active_devices[$version_device_phid])) {
unset($versions[$key]);
}
}
$leaders = 0;
foreach ($versions as $version) {
if ($version->getRepositoryVersion() == $leader_version) {
$leaders++;
}
}
if ($leaders == count($active_devices)) {
$full_sync[] = $repository;
} else {
$push_epoch = idx($push_times, $repository_phid);
if ($push_epoch) {
$duration = (PhabricatorTime::getNow() - $push_epoch);
$lag[] = $duration;
} else {
$duration = null;
}
if ($leaders >= 2 || ($duration && ($duration < $threshold))) {
$partial_sync[] = $repository;
} else {
$no_sync[] = $repository;
if ($push_epoch) {
$messages[] = pht(
'Repository %s has unreplicated changes (for %s).',
$viewer->renderHandle($repository_phid)->render(),
phutil_format_relative_time($duration));
} else {
$messages[] = pht(
'Repository %s has unreplicated changes.',
$viewer->renderHandle($repository_phid)->render());
}
}
}
}
$with_lag = false;
if ($no_leader) {
$replication_icon = 'fa-times red';
$replication_label = pht('Ambiguous Leader');
} else if ($no_sync) {
$replication_icon = 'fa-refresh yellow';
$replication_label = pht('Unsynchronized');
$with_lag = true;
} else if ($partial_sync) {
$replication_icon = 'fa-refresh green';
$replication_label = pht('Partial');
$with_lag = true;
} else if ($full_sync) {
$replication_icon = 'fa-check green';
$replication_label = pht('Synchronized');
} else {
$replication_icon = 'fa-times grey';
$replication_label = pht('No Repositories');
}
if ($with_lag && $lag) {
$lag_status = phutil_format_relative_time(max($lag));
$lag_status = pht(' (%s)', $lag_status);
} else {
$lag_status = null;
}
$replication_status = array(
id(new PHUIIconView())->setIcon($replication_icon),
' ',
$replication_label,
$lag_status,
);
$messages = phutil_implode_html(phutil_tag('br'), $messages);
$rows[] = array(
$status_icon,
$viewer->renderHandle($service->getPHID()),
$device_status,
$repository_status,
$replication_status,
$messages,
);
}
return id(new AphrontTableView($rows))
->setNoDataString(
pht('No repository cluster services are configured.'))
->setHeaders(
array(
null,
pht('Service'),
pht('Devices'),
pht('Repos'),
pht('Sync'),
pht('Messages'),
))
->setColumnClasses(
array(
null,
'pri',
null,
null,
null,
'wide',
));
}
private function getDevices(
array $all_services,
$only_active) {
$devices = array();
foreach ($all_services as $service) {
$map = array();
foreach ($service->getBindings() as $binding) {
if ($only_active && $binding->getIsDisabled()) {
continue;
}
$device = $binding->getDevice();
$device_phid = $device->getPHID();
$map[$device_phid] = $device;
}
$devices[$service->getPHID()] = $map;
}
return $devices;
}
private function getLeaderVersionsByRepository(
array $all_repositories,
array $all_versions,
array $active_devices) {
$version_map = mgroup($all_versions, 'getRepositoryPHID');
$result = array();
foreach ($all_repositories as $repository_phid => $repository) {
$service_phid = $repository->getAlmanacServicePHID();
if (!$service_phid) {
continue;
}
$devices = idx($active_devices, $service_phid);
if (!$devices) {
continue;
}
$versions = idx($version_map, $repository_phid, array());
$versions = mpull($versions, null, 'getDevicePHID');
$versions = array_select_keys($versions, array_keys($devices));
if (!$versions) {
continue;
}
$leader = (int)max(mpull($versions, 'getRepositoryVersion'));
$result[$repository_phid] = $leader;
}
return $result;
}
private function loadLeaderPushTimes(array $leader_versions) {
$viewer = $this->getViewer();
if (!$leader_versions) {
return array();
}
$events = id(new PhabricatorRepositoryPushEventQuery())
->setViewer($viewer)
->withIDs($leader_versions)
->execute();
$events = mpull($events, null, 'getID');
$result = array();
foreach ($leader_versions as $key => $version) {
$event = idx($events, $version);
if (!$event) {
continue;
}
$result[$key] = $event->getEpoch();
}
return $result;
}
private function buildClusterRepositoryErrors() {
$viewer = $this->getViewer();
$messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere(
'statusCode IN (%Ls)',
array(
PhabricatorRepositoryStatusMessage::CODE_ERROR,
));
$repository_ids = mpull($messages, 'getRepositoryID');
if ($repository_ids) {
// NOTE: We're bypassing policies when loading repositories because we
// want to show errors exist even if the viewer can't see the repository.
// We use handles to describe the repository below, so the viewer won't
// actually be able to see any particulars if they can't see the
// repository.
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIDs($repository_ids)
->execute();
$repositories = mpull($repositories, null, 'getID');
}
$rows = array();
foreach ($messages as $message) {
$repository = idx($repositories, $message->getRepositoryID());
if (!$repository) {
continue;
}
if (!$repository->isTracked()) {
continue;
}
$icon = id(new PHUIIconView())
->setIcon('fa-exclamation-triangle red');
$rows[] = array(
$icon,
$viewer->renderHandle($repository->getPHID()),
phutil_tag(
'a',
array(
'href' => $repository->getPathURI('manage/status/'),
),
$message->getStatusTypeName()),
);
}
return id(new AphrontTableView($rows))
->setNoDataString(
pht('No active repositories have outstanding errors.'))
->setHeaders(
array(
null,
pht('Repository'),
pht('Error'),
))
->setColumnClasses(
array(
null,
'pri',
'wide',
));
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php
index cd00ef73a0..55caeb1cad 100644
--- a/src/applications/config/controller/PhabricatorConfigClusterSearchController.php
+++ b/src/applications/config/controller/PhabricatorConfigClusterSearchController.php
@@ -1,127 +1,126 @@
<?php
final class PhabricatorConfigClusterSearchController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$nav = $this->buildSideNavView();
$nav->selectFilter('cluster/search/');
$title = pht('Cluster Search');
$doc_href = PhabricatorEnv::getDoclink('Cluster: Search');
$button = id(new PHUIButtonView())
->setIcon('fa-book')
->setHref($doc_href)
->setTag('a')
->setText(pht('Documentation'));
$header = $this->buildHeaderView($title, $button);
$search_status = $this->buildClusterSearchStatus();
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($search_status);
+ ->setFooter($search_status);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildClusterSearchStatus() {
$viewer = $this->getViewer();
$services = PhabricatorSearchService::getAllServices();
Javelin::initBehavior('phabricator-tooltips');
$view = array();
foreach ($services as $service) {
$view[] = $this->renderStatusView($service);
}
return $view;
}
private function renderStatusView($service) {
$head = array_merge(
array(pht('Type')),
array_keys($service->getStatusViewColumns()),
array(pht('Status')));
$rows = array();
$status_map = PhabricatorSearchService::getConnectionStatusMap();
$stats = false;
$stats_view = false;
foreach ($service->getHosts() as $host) {
try {
$status = $host->getConnectionStatus();
$status = idx($status_map, $status, array());
} catch (Exception $ex) {
$status['icon'] = 'fa-times';
$status['label'] = pht('Connection Error');
$status['color'] = 'red';
$host->didHealthCheck(false);
}
if (!$stats_view) {
try {
$stats = $host->getEngine()->getIndexStats($host);
$stats_view = $this->renderIndexStats($stats);
} catch (Exception $e) {
$stats_view = false;
}
}
$type_icon = 'fa-search sky';
$type_tip = $host->getDisplayName();
$type_icon = id(new PHUIIconView())
->setIcon($type_icon);
$status_view = array(
id(new PHUIIconView())->setIcon($status['icon'].' '.$status['color']),
' ',
$status['label'],
);
$row = array(array($type_icon, ' ', $type_tip));
$row = array_merge($row, array_values(
$host->getStatusViewColumns()));
$row[] = $status_view;
$rows[] = $row;
}
$table = id(new AphrontTableView($rows))
->setNoDataString(pht('No search servers are configured.'))
->setHeaders($head);
$view = $this->buildConfigBoxView(pht('Search Servers'), $table);
$stats = null;
if ($stats_view->hasAnyProperties()) {
$stats = $this->buildConfigBoxView(
pht('%s Stats', $service->getDisplayName()),
$stats_view);
}
return array($stats, $view);
}
private function renderIndexStats($stats) {
$view = id(new PHUIPropertyListView());
if ($stats !== false) {
foreach ($stats as $label => $val) {
$view->addProperty($label, $val);
}
}
return $view;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigController.php b/src/applications/config/controller/PhabricatorConfigController.php
index ad5ea6cd27..1b6a5af8b5 100644
--- a/src/applications/config/controller/PhabricatorConfigController.php
+++ b/src/applications/config/controller/PhabricatorConfigController.php
@@ -1,95 +1,93 @@
<?php
abstract class PhabricatorConfigController extends PhabricatorController {
public function shouldRequireAdmin() {
return true;
}
public function buildSideNavView($filter = null, $for_app = false) {
-
-
$guide_href = new PhutilURI('/guides/');
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
$nav->addFilter('/',
pht('Core Settings'), null, 'fa-gear');
$nav->addFilter('application/',
pht('Application Settings'), null, 'fa-globe');
$nav->addFilter('history/',
pht('Settings History'), null, 'fa-history');
$nav->addFilter('version/',
pht('Version Information'), null, 'fa-download');
$nav->addFilter('all/',
pht('All Settings'), null, 'fa-list-ul');
$nav->addLabel(pht('Setup'));
$nav->addFilter('issue/',
pht('Setup Issues'), null, 'fa-warning');
$nav->addFilter(null,
pht('Installation Guide'), $guide_href, 'fa-book');
$nav->addLabel(pht('Database'));
$nav->addFilter('database/',
pht('Database Status'), null, 'fa-heartbeat');
$nav->addFilter('dbissue/',
pht('Database Issues'), null, 'fa-exclamation-circle');
$nav->addLabel(pht('Cache'));
$nav->addFilter('cache/',
pht('Cache Status'), null, 'fa-home');
$nav->addLabel(pht('Cluster'));
$nav->addFilter('cluster/databases/',
pht('Database Servers'), null, 'fa-database');
$nav->addFilter('cluster/notifications/',
pht('Notification Servers'), null, 'fa-bell-o');
$nav->addFilter('cluster/repositories/',
pht('Repository Servers'), null, 'fa-code');
$nav->addFilter('cluster/search/',
pht('Search Servers'), null, 'fa-search');
$nav->addLabel(pht('Modules'));
$modules = PhabricatorConfigModule::getAllModules();
foreach ($modules as $key => $module) {
$nav->addFilter('module/'.$key.'/',
$module->getModuleName(), null, 'fa-puzzle-piece');
}
return $nav;
}
public function buildApplicationMenu() {
return $this->buildSideNavView(null, true)->getMenu();
}
public function buildHeaderView($text, $action = null) {
$viewer = $this->getViewer();
$file = PhabricatorFile::loadBuiltin($viewer, 'projects/v3/manage.png');
$image = $file->getBestURI($file);
$header = id(new PHUIHeaderView())
->setHeader($text)
->setProfileHeader(true)
->setImage($image);
if ($action) {
$header->addActionLink($action);
}
return $header;
}
public function buildConfigBoxView($title, $content, $action = null) {
$header = id(new PHUIHeaderView())
->setHeader($title);
if ($action) {
$header->addActionItem($action);
}
$view = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($content)
->setBackground(PHUIObjectBoxView::WHITE_CONFIG);
return $view;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php
index 708a708043..fa6bcab5e6 100644
--- a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php
+++ b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php
@@ -1,180 +1,179 @@
<?php
final class PhabricatorConfigDatabaseIssueController
extends PhabricatorConfigDatabaseController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$query = new PhabricatorConfigSchemaQuery();
$actual = $query->loadActualSchemata();
$expect = $query->loadExpectedSchemata();
$comp_servers = $query->buildComparisonSchemata($expect, $actual);
// Collect all open issues.
$issues = array();
foreach ($comp_servers as $ref_name => $comp) {
foreach ($comp->getDatabases() as $database_name => $database) {
foreach ($database->getLocalIssues() as $issue) {
$issues[] = array(
$ref_name,
$database_name,
null,
null,
null,
$issue,
);
}
foreach ($database->getTables() as $table_name => $table) {
foreach ($table->getLocalIssues() as $issue) {
$issues[] = array(
$ref_name,
$database_name,
$table_name,
null,
null,
$issue,
);
}
foreach ($table->getColumns() as $column_name => $column) {
foreach ($column->getLocalIssues() as $issue) {
$issues[] = array(
$ref_name,
$database_name,
$table_name,
'column',
$column_name,
$issue,
);
}
}
foreach ($table->getKeys() as $key_name => $key) {
foreach ($key->getLocalIssues() as $issue) {
$issues[] = array(
$ref_name,
$database_name,
$table_name,
'key',
$key_name,
$issue,
);
}
}
}
}
}
// Sort all open issues so that the most severe issues appear first.
$order = array();
$counts = array();
foreach ($issues as $key => $issue) {
$const = $issue[5];
$status = PhabricatorConfigStorageSchema::getIssueStatus($const);
$severity = PhabricatorConfigStorageSchema::getStatusSeverity($status);
$order[$key] = sprintf(
'~%d~%s%s%s',
9 - $severity,
$issue[1],
$issue[2],
$issue[4]);
if (empty($counts[$status])) {
$counts[$status] = 0;
}
$counts[$status]++;
}
asort($order);
$issues = array_select_keys($issues, array_keys($order));
// Render the issues.
$rows = array();
foreach ($issues as $issue) {
$const = $issue[5];
$uri = $this->getApplicationURI('/database/'.$issue[0].'/'.$issue[1].'/');
$database_link = phutil_tag(
'a',
array(
'href' => $uri,
),
$issue[1]);
$rows[] = array(
$this->renderIcon(
PhabricatorConfigStorageSchema::getIssueStatus($const)),
$issue[0],
$database_link,
$issue[2],
$issue[3],
$issue[4],
PhabricatorConfigStorageSchema::getIssueDescription($const),
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(
pht('No databases have any issues.'))
->setHeaders(
array(
null,
pht('Server'),
pht('Database'),
pht('Table'),
pht('Type'),
pht('Column/Key'),
pht('Issue'),
))
->setColumnClasses(
array(
null,
null,
null,
null,
null,
null,
'wide',
));
$errors = array();
if (isset($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])) {
$errors[] = pht(
'Detected %s serious issue(s) with the schemata.',
new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_FAIL]));
}
if (isset($counts[PhabricatorConfigStorageSchema::STATUS_WARN])) {
$errors[] = pht(
'Detected %s warning(s) with the schemata.',
new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_WARN]));
}
$title = pht('Database Issues');
$header = $this->buildHeaderView($title);
$nav = $this->buildSideNavView();
$nav->selectFilter('dbissue/');
$view = $this->buildConfigBoxView(pht('Issues'), $table);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($view);
+ ->setFooter($view);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php
index 760317ae80..6831a048d5 100644
--- a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php
+++ b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php
@@ -1,865 +1,864 @@
<?php
final class PhabricatorConfigDatabaseStatusController
extends PhabricatorConfigDatabaseController {
private $database;
private $table;
private $column;
private $key;
private $ref;
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$this->database = $request->getURIData('database');
$this->table = $request->getURIData('table');
$this->column = $request->getURIData('column');
$this->key = $request->getURIData('key');
$this->ref = $request->getURIData('ref');
$query = new PhabricatorConfigSchemaQuery();
$actual = $query->loadActualSchemata();
$expect = $query->loadExpectedSchemata();
$comp = $query->buildComparisonSchemata($expect, $actual);
if ($this->ref !== null) {
$server_actual = idx($actual, $this->ref);
if (!$server_actual) {
return new Aphront404Response();
}
$server_comparison = $comp[$this->ref];
$server_expect = $expect[$this->ref];
if ($this->column) {
return $this->renderColumn(
$server_comparison,
$server_expect,
$server_actual,
$this->database,
$this->table,
$this->column);
} else if ($this->key) {
return $this->renderKey(
$server_comparison,
$server_expect,
$server_actual,
$this->database,
$this->table,
$this->key);
} else if ($this->table) {
return $this->renderTable(
$server_comparison,
$server_expect,
$server_actual,
$this->database,
$this->table);
} else if ($this->database) {
return $this->renderDatabase(
$server_comparison,
$server_expect,
$server_actual,
$this->database);
}
}
return $this->renderServers(
$comp,
$expect,
$actual);
}
private function buildResponse($title, $body) {
$nav = $this->buildSideNavView();
$nav->selectFilter('database/');
if (!$title) {
$title = pht('Database Status');
}
$ref = $this->ref;
$database = $this->database;
$table = $this->table;
$column = $this->column;
$key = $this->key;
$links = array();
$links[] = array(
pht('Database Status'),
'database/',
);
if ($database) {
$links[] = array(
$database,
"database/{$ref}/{$database}/",
);
}
if ($table) {
$links[] = array(
$table,
"database/{$ref}/{$database}/{$table}/",
);
}
if ($column) {
$links[] = array(
$column,
"database/{$ref}/{$database}/{$table}/col/{$column}/",
);
}
if ($key) {
$links[] = array(
$key,
"database/{$ref}/{$database}/{$table}/key/{$key}/",
);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->setBorder(true);
$last_key = last_key($links);
foreach ($links as $link_key => $link) {
list($name, $href) = $link;
if ($link_key == $last_key) {
$crumbs->addTextCrumb($name);
} else {
$crumbs->addTextCrumb($name, $this->getApplicationURI($href));
}
}
$doc_link = PhabricatorEnv::getDoclink('Managing Storage Adjustments');
$button = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-book')
->setHref($doc_link)
->setText(pht('Documentation'));
$header = $this->buildHeaderView($title, $button);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($body);
+ ->setFooter($body);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function renderServers(
array $comp_servers,
array $expect_servers,
array $actual_servers) {
$charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET;
$collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION;
$rows = array();
foreach ($comp_servers as $ref_key => $comp) {
$actual = $actual_servers[$ref_key];
$expect = $expect_servers[$ref_key];
foreach ($comp->getDatabases() as $database_name => $database) {
$actual_database = $actual->getDatabase($database_name);
if ($actual_database) {
$charset = $actual_database->getCharacterSet();
$collation = $actual_database->getCollation();
} else {
$charset = null;
$collation = null;
}
$status = $database->getStatus();
$issues = $database->getIssues();
$uri = $this->getURI(
array(
'ref' => $ref_key,
'database' => $database_name,
));
$rows[] = array(
$this->renderIcon($status),
$ref_key,
phutil_tag(
'a',
array(
'href' => $uri,
),
$database_name),
$this->renderAttr($charset, $database->hasIssue($charset_issue)),
$this->renderAttr($collation, $database->hasIssue($collation_issue)),
);
}
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Server'),
pht('Database'),
pht('Charset'),
pht('Collation'),
))
->setColumnClasses(
array(
null,
null,
'wide pri',
null,
null,
));
$title = pht('Database Status');
$properties = $this->buildProperties(
array(
),
$comp->getIssues());
$properties = $this->buildConfigBoxView(pht('Properties'), $properties);
$table = $this->buildConfigBoxView(pht('Database'), $table);
return $this->buildResponse($title, array($properties, $table));
}
private function renderDatabase(
PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
PhabricatorConfigServerSchema $actual,
$database_name) {
$collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION;
$database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
$rows = array();
foreach ($database->getTables() as $table_name => $table) {
$status = $table->getStatus();
$uri = $this->getURI(
array(
'table' => $table_name,
));
$rows[] = array(
$this->renderIcon($status),
phutil_tag(
'a',
array(
'href' => $uri,
),
$table_name),
$this->renderAttr(
$table->getCollation(),
$table->hasIssue($collation_issue)),
$table->getPersistenceTypeDisplayName(),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Table'),
pht('Collation'),
pht('Persistence'),
))
->setColumnClasses(
array(
null,
'wide pri',
null,
null,
));
$title = $database_name;
$actual_database = $actual->getDatabase($database_name);
if ($actual_database) {
$actual_charset = $actual_database->getCharacterSet();
$actual_collation = $actual_database->getCollation();
} else {
$actual_charset = null;
$actual_collation = null;
}
$expect_database = $expect->getDatabase($database_name);
if ($expect_database) {
$expect_charset = $expect_database->getCharacterSet();
$expect_collation = $expect_database->getCollation();
} else {
$expect_charset = null;
$expect_collation = null;
}
$properties = $this->buildProperties(
array(
array(
pht('Server'),
$this->ref,
),
array(
pht('Character Set'),
$actual_charset,
),
array(
pht('Expected Character Set'),
$expect_charset,
),
array(
pht('Collation'),
$actual_collation,
),
array(
pht('Expected Collation'),
$expect_collation,
),
),
$database->getIssues());
$properties = $this->buildConfigBoxView(pht('Properties'), $properties);
$table = $this->buildConfigBoxView(pht('Database'), $table);
return $this->buildResponse($title, array($properties, $table));
}
private function renderTable(
PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
PhabricatorConfigServerSchema $actual,
$database_name,
$table_name) {
$type_issue = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE;
$charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET;
$collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION;
$nullable_issue = PhabricatorConfigStorageSchema::ISSUE_NULLABLE;
$unique_issue = PhabricatorConfigStorageSchema::ISSUE_UNIQUE;
$columns_issue = PhabricatorConfigStorageSchema::ISSUE_KEYCOLUMNS;
$longkey_issue = PhabricatorConfigStorageSchema::ISSUE_LONGKEY;
$auto_issue = PhabricatorConfigStorageSchema::ISSUE_AUTOINCREMENT;
$database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
$table = $database->getTable($table_name);
if (!$table) {
return new Aphront404Response();
}
$actual_database = $actual->getDatabase($database_name);
$actual_table = null;
if ($actual_database) {
$actual_table = $actual_database->getTable($table_name);
}
$expect_database = $expect->getDatabase($database_name);
$expect_table = null;
if ($expect_database) {
$expect_table = $expect_database->getTable($table_name);
}
$rows = array();
foreach ($table->getColumns() as $column_name => $column) {
$expect_column = null;
if ($expect_table) {
$expect_column = $expect_table->getColumn($column_name);
}
$status = $column->getStatus();
$data_type = null;
if ($expect_column) {
$data_type = $expect_column->getDataType();
}
$uri = $this->getURI(
array(
'column' => $column_name,
));
$rows[] = array(
$this->renderIcon($status),
phutil_tag(
'a',
array(
'href' => $uri,
),
$column_name),
$data_type,
$this->renderAttr(
$column->getColumnType(),
$column->hasIssue($type_issue)),
$this->renderAttr(
$this->renderBoolean($column->getNullable()),
$column->hasIssue($nullable_issue)),
$this->renderAttr(
$this->renderBoolean($column->getAutoIncrement()),
$column->hasIssue($auto_issue)),
$this->renderAttr(
$column->getCharacterSet(),
$column->hasIssue($charset_issue)),
$this->renderAttr(
$column->getCollation(),
$column->hasIssue($collation_issue)),
);
}
$table_view = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Column'),
pht('Data Type'),
pht('Column Type'),
pht('Nullable'),
pht('Autoincrement'),
pht('Character Set'),
pht('Collation'),
))
->setColumnClasses(
array(
null,
'wide pri',
null,
null,
null,
null,
null,
));
$key_rows = array();
foreach ($table->getKeys() as $key_name => $key) {
$expect_key = null;
if ($expect_table) {
$expect_key = $expect_table->getKey($key_name);
}
$status = $key->getStatus();
$size = 0;
foreach ($key->getColumnNames() as $column_spec) {
list($column_name, $prefix) = $key->getKeyColumnAndPrefix($column_spec);
$column = $table->getColumn($column_name);
if (!$column) {
$size = 0;
break;
}
$size += $column->getKeyByteLength($prefix);
}
$size_formatted = null;
if ($size) {
$size_formatted = $this->renderAttr(
$size,
$key->hasIssue($longkey_issue));
}
$uri = $this->getURI(
array(
'key' => $key_name,
));
$key_rows[] = array(
$this->renderIcon($status),
phutil_tag(
'a',
array(
'href' => $uri,
),
$key_name),
$this->renderAttr(
implode(', ', $key->getColumnNames()),
$key->hasIssue($columns_issue)),
$this->renderAttr(
$this->renderBoolean($key->getUnique()),
$key->hasIssue($unique_issue)),
$size_formatted,
);
}
$keys_view = id(new AphrontTableView($key_rows))
->setHeaders(
array(
null,
pht('Key'),
pht('Columns'),
pht('Unique'),
pht('Size'),
))
->setColumnClasses(
array(
null,
'wide pri',
null,
null,
null,
));
$title = pht('%s.%s', $database_name, $table_name);
if ($actual_table) {
$actual_collation = $actual_table->getCollation();
} else {
$actual_collation = null;
}
if ($expect_table) {
$expect_collation = $expect_table->getCollation();
} else {
$expect_collation = null;
}
$properties = $this->buildProperties(
array(
array(
pht('Server'),
$this->ref,
),
array(
pht('Collation'),
$actual_collation,
),
array(
pht('Expected Collation'),
$expect_collation,
),
),
$table->getIssues());
$box_header = pht('%s.%s', $database_name, $table_name);
$properties = $this->buildConfigBoxView(pht('Properties'), $properties);
$table = $this->buildConfigBoxView(pht('Database'), $table_view);
$keys = $this->buildConfigBoxView(pht('Keys'), $keys_view);
return $this->buildResponse(
$title, array($properties, $table, $keys));
}
private function renderColumn(
PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
PhabricatorConfigServerSchema $actual,
$database_name,
$table_name,
$column_name) {
$database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
$table = $database->getTable($table_name);
if (!$table) {
return new Aphront404Response();
}
$column = $table->getColumn($column_name);
if (!$column) {
return new Aphront404Response();
}
$actual_database = $actual->getDatabase($database_name);
$actual_table = null;
$actual_column = null;
if ($actual_database) {
$actual_table = $actual_database->getTable($table_name);
if ($actual_table) {
$actual_column = $actual_table->getColumn($column_name);
}
}
$expect_database = $expect->getDatabase($database_name);
$expect_table = null;
$expect_column = null;
if ($expect_database) {
$expect_table = $expect_database->getTable($table_name);
if ($expect_table) {
$expect_column = $expect_table->getColumn($column_name);
}
}
if ($actual_column) {
$actual_coltype = $actual_column->getColumnType();
$actual_charset = $actual_column->getCharacterSet();
$actual_collation = $actual_column->getCollation();
$actual_nullable = $actual_column->getNullable();
$actual_auto = $actual_column->getAutoIncrement();
} else {
$actual_coltype = null;
$actual_charset = null;
$actual_collation = null;
$actual_nullable = null;
$actual_auto = null;
}
if ($expect_column) {
$data_type = $expect_column->getDataType();
$expect_coltype = $expect_column->getColumnType();
$expect_charset = $expect_column->getCharacterSet();
$expect_collation = $expect_column->getCollation();
$expect_nullable = $expect_column->getNullable();
$expect_auto = $expect_column->getAutoIncrement();
} else {
$data_type = null;
$expect_coltype = null;
$expect_charset = null;
$expect_collation = null;
$expect_nullable = null;
$expect_auto = null;
}
$title = pht(
'%s.%s.%s',
$database_name,
$table_name,
$column_name);
$properties = $this->buildProperties(
array(
array(
pht('Server'),
$this->ref,
),
array(
pht('Data Type'),
$data_type,
),
array(
pht('Column Type'),
$actual_coltype,
),
array(
pht('Expected Column Type'),
$expect_coltype,
),
array(
pht('Character Set'),
$actual_charset,
),
array(
pht('Expected Character Set'),
$expect_charset,
),
array(
pht('Collation'),
$actual_collation,
),
array(
pht('Expected Collation'),
$expect_collation,
),
array(
pht('Nullable'),
$this->renderBoolean($actual_nullable),
),
array(
pht('Expected Nullable'),
$this->renderBoolean($expect_nullable),
),
array(
pht('Autoincrement'),
$this->renderBoolean($actual_auto),
),
array(
pht('Expected Autoincrement'),
$this->renderBoolean($expect_auto),
),
),
$column->getIssues());
$properties = $this->buildConfigBoxView(pht('Properties'), $properties);
return $this->buildResponse($title, $properties);
}
private function renderKey(
PhabricatorConfigServerSchema $comp,
PhabricatorConfigServerSchema $expect,
PhabricatorConfigServerSchema $actual,
$database_name,
$table_name,
$key_name) {
$database = $comp->getDatabase($database_name);
if (!$database) {
return new Aphront404Response();
}
$table = $database->getTable($table_name);
if (!$table) {
return new Aphront404Response();
}
$key = $table->getKey($key_name);
if (!$key) {
return new Aphront404Response();
}
$actual_database = $actual->getDatabase($database_name);
$actual_table = null;
$actual_key = null;
if ($actual_database) {
$actual_table = $actual_database->getTable($table_name);
if ($actual_table) {
$actual_key = $actual_table->getKey($key_name);
}
}
$expect_database = $expect->getDatabase($database_name);
$expect_table = null;
$expect_key = null;
if ($expect_database) {
$expect_table = $expect_database->getTable($table_name);
if ($expect_table) {
$expect_key = $expect_table->getKey($key_name);
}
}
if ($actual_key) {
$actual_columns = $actual_key->getColumnNames();
$actual_unique = $actual_key->getUnique();
} else {
$actual_columns = array();
$actual_unique = null;
}
if ($expect_key) {
$expect_columns = $expect_key->getColumnNames();
$expect_unique = $expect_key->getUnique();
} else {
$expect_columns = array();
$expect_unique = null;
}
$title = pht(
'%s.%s (%s)',
$database_name,
$table_name,
$key_name);
$properties = $this->buildProperties(
array(
array(
pht('Server'),
$this->ref,
),
array(
pht('Unique'),
$this->renderBoolean($actual_unique),
),
array(
pht('Expected Unique'),
$this->renderBoolean($expect_unique),
),
array(
pht('Columns'),
implode(', ', $actual_columns),
),
array(
pht('Expected Columns'),
implode(', ', $expect_columns),
),
),
$key->getIssues());
$properties = $this->buildConfigBoxView(pht('Properties'), $properties);
return $this->buildResponse($title, $properties);
}
private function buildProperties(array $properties, array $issues) {
$view = id(new PHUIPropertyListView())
->setUser($this->getRequest()->getUser());
foreach ($properties as $property) {
list($key, $value) = $property;
$view->addProperty($key, $value);
}
$status_view = new PHUIStatusListView();
if (!$issues) {
$status_view->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
->setTarget(pht('No Schema Issues')));
} else {
foreach ($issues as $issue) {
$note = PhabricatorConfigStorageSchema::getIssueDescription($issue);
$status = PhabricatorConfigStorageSchema::getIssueStatus($issue);
switch ($status) {
case PhabricatorConfigStorageSchema::STATUS_WARN:
$icon = PHUIStatusItemView::ICON_WARNING;
$color = 'yellow';
break;
case PhabricatorConfigStorageSchema::STATUS_FAIL:
default:
$icon = PHUIStatusItemView::ICON_REJECT;
$color = 'red';
break;
}
$item = id(new PHUIStatusItemView())
->setTarget(PhabricatorConfigStorageSchema::getIssueName($issue))
->setIcon($icon, $color)
->setNote($note);
$status_view->addItem($item);
}
}
$view->addProperty(pht('Schema Status'), $status_view);
return phutil_tag_div('config-page-property', $view);
}
private function getURI(array $properties) {
$defaults = array(
'ref' => $this->ref,
'database' => $this->database,
'table' => $this->table,
'column' => $this->column,
'key' => $this->key,
);
$properties = $properties + $defaults;
$properties = array_select_keys($properties, array_keys($defaults));
$parts = array();
foreach ($properties as $key => $property) {
if (!strlen($property)) {
continue;
}
if ($key == 'column') {
$parts[] = 'col';
} else if ($key == 'key') {
$parts[] = 'key';
}
$parts[] = $property;
}
if ($parts) {
$parts = implode('/', $parts).'/';
} else {
$parts = null;
}
return $this->getApplicationURI('/database/'.$parts);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigEditController.php b/src/applications/config/controller/PhabricatorConfigEditController.php
index 224705e181..381b54e046 100644
--- a/src/applications/config/controller/PhabricatorConfigEditController.php
+++ b/src/applications/config/controller/PhabricatorConfigEditController.php
@@ -1,491 +1,491 @@
<?php
final class PhabricatorConfigEditController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$key = $request->getURIData('key');
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
if (empty($options[$key])) {
$ancient = PhabricatorExtraConfigSetupCheck::getAncientConfig();
if (isset($ancient[$key])) {
$desc = pht(
"This configuration has been removed. You can safely delete ".
"it.\n\n%s",
$ancient[$key]);
} else {
$desc = pht(
'This configuration option is unknown. It may be misspelled, '.
'or have existed in a previous version of Phabricator.');
}
// This may be a dead config entry, which existed in the past but no
// longer exists. Allow it to be edited so it can be reviewed and
// deleted.
$option = id(new PhabricatorConfigOption())
->setKey($key)
->setType('wild')
->setDefault(null)
->setDescription($desc);
$group = null;
$group_uri = $this->getApplicationURI();
} else {
$option = $options[$key];
$group = $option->getGroup();
$group_uri = $this->getApplicationURI('group/'.$group->getKey().'/');
}
$issue = $request->getStr('issue');
if ($issue) {
// If the user came here from an open setup issue, send them back.
$done_uri = $this->getApplicationURI('issue/'.$issue.'/');
} else {
$done_uri = $group_uri;
}
// Check if the config key is already stored in the database.
// Grab the value if it is.
$config_entry = id(new PhabricatorConfigEntry())
->loadOneWhere(
'configKey = %s AND namespace = %s',
$key,
'default');
if (!$config_entry) {
$config_entry = id(new PhabricatorConfigEntry())
->setConfigKey($key)
->setNamespace('default')
->setIsDeleted(true);
$config_entry->setPHID($config_entry->generatePHID());
}
$e_value = null;
$errors = array();
if ($request->isFormPost() && !$option->getLocked()) {
$result = $this->readRequest(
$option,
$request);
list($e_value, $value_errors, $display_value, $xaction) = $result;
$errors = array_merge($errors, $value_errors);
if (!$errors) {
$editor = id(new PhabricatorConfigEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request);
try {
$editor->applyTransactions($config_entry, array($xaction));
return id(new AphrontRedirectResponse())->setURI($done_uri);
} catch (PhabricatorConfigValidationException $ex) {
$e_value = pht('Invalid');
$errors[] = $ex->getMessage();
}
}
} else {
if ($config_entry->getIsDeleted()) {
$display_value = null;
} else {
$display_value = $this->getDisplayValue(
$option,
$config_entry,
$config_entry->getValue());
}
}
$form = id(new AphrontFormView())
->setEncType('multipart/form-data');
$error_view = null;
if ($errors) {
$error_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_ERROR)
->setErrors($errors);
}
$doc_href = PhabricatorEnv::getDoclink(
'Configuration Guide: Locked and Hidden Configuration');
$doc_link = phutil_tag(
'a',
array(
'href' => $doc_href,
'target' => '_blank',
),
pht('Learn more about locked and hidden options.'));
$status_items = array();
$tag = null;
if ($option->getHidden()) {
$tag = id(new PHUITagView())
->setName(pht('Hidden'))
->setColor(PHUITagView::COLOR_GREY)
->setBorder(PHUITagView::BORDER_NONE)
->setType(PHUITagView::TYPE_SHADE);
$message = pht(
'This configuration is hidden and can not be edited or viewed from '.
'the web interface.');
$status_items[] = id(new PHUIInfoView())
->appendChild(array($message, ' ', $doc_link));
} else if ($option->getLocked()) {
$tag = id(new PHUITagView())
->setName(pht('Locked'))
->setColor(PHUITagView::COLOR_RED)
->setBorder(PHUITagView::BORDER_NONE)
->setType(PHUITagView::TYPE_SHADE);
$message = $option->getLockedMessage();
$status_items[] = id(new PHUIInfoView())
->appendChild(array($message, ' ', $doc_link));
}
if ($option->getHidden() || $option->getLocked()) {
$controls = array();
} else {
$controls = $this->renderControls(
$option,
$display_value,
$e_value);
}
$form
->setUser($viewer)
->addHiddenInput('issue', $request->getStr('issue'));
$description = $option->newDescriptionRemarkupView($viewer);
if ($description) {
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Description'))
->setValue($description));
}
if ($group) {
$extra = $group->renderContextualDescription(
$option,
$request);
if ($extra !== null) {
$form->appendChild(
id(new AphrontFormMarkupControl())
->setValue($extra));
}
}
foreach ($controls as $control) {
$form->appendControl($control);
}
if (!$option->getLocked()) {
$form->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($done_uri)
->setValue(pht('Save Config Entry')));
}
$current_config = null;
if (!$option->getHidden()) {
$current_config = $this->renderDefaults($option, $config_entry);
$current_config = $this->buildConfigBoxView(
pht('Current Configuration'),
$current_config);
}
$examples = $this->renderExamples($option);
if ($examples) {
$examples = $this->buildConfigBoxView(
pht('Examples'),
$examples);
}
$title = $key;
$box_header = array();
if ($group) {
$box_header[] = phutil_tag(
'a',
array(
'href' => $group_uri,
),
$group->getName());
$box_header[] = " \xC2\xBB ";
}
$box_header[] = $key;
$crumbs = $this->buildApplicationCrumbs();
if ($group) {
$crumbs->addTextCrumb($group->getName(), $group_uri);
}
$crumbs->addTextCrumb($key, '/config/edit/'.$key);
$crumbs->setBorder(true);
$form_box = $this->buildConfigBoxView($box_header, $form, $tag);
$timeline = $this->buildTransactionTimeline(
$config_entry,
new PhabricatorConfigTransactionQuery());
$timeline->setShouldTerminate(true);
$nav = $this->buildSideNavView();
$nav->selectFilter($group_uri);
$header = $this->buildHeaderView($title);
$view = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn(array(
+ ->setFooter(
+ array(
$error_view,
$form_box,
$status_items,
$examples,
$current_config,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($view);
}
private function readRequest(
PhabricatorConfigOption $option,
AphrontRequest $request) {
$type = $option->newOptionType();
if ($type) {
$is_set = $type->isValuePresentInRequest($option, $request);
if ($is_set) {
$value = $type->readValueFromRequest($option, $request);
$errors = array();
try {
$canonical_value = $type->newValueFromRequestValue(
$option,
$value);
$type->validateStoredValue($option, $canonical_value);
$xaction = $type->newTransaction($option, $canonical_value);
} catch (PhabricatorConfigValidationException $ex) {
$errors[] = $ex->getMessage();
$xaction = null;
} catch (Exception $ex) {
// NOTE: Some older validators throw bare exceptions. Purely in good
// taste, it would be nice to convert these at some point.
$errors[] = $ex->getMessage();
$xaction = null;
}
return array(
$errors ? pht('Invalid') : null,
$errors,
$value,
$xaction,
);
} else {
$delete_xaction = id(new PhabricatorConfigTransaction())
->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT)
->setNewValue(
array(
'deleted' => true,
'value' => null,
));
return array(
null,
array(),
null,
$delete_xaction,
);
}
}
// TODO: If we missed on the new `PhabricatorConfigType` map, fall back
// to the old semi-modular, semi-hacky way of doing things.
$xaction = new PhabricatorConfigTransaction();
$xaction->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT);
$e_value = null;
$errors = array();
if ($option->isCustomType()) {
$info = $option->getCustomObject()->readRequest($option, $request);
list($e_value, $errors, $set_value, $value) = $info;
} else {
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
if (!$errors) {
$xaction->setNewValue(
array(
'deleted' => false,
'value' => $set_value,
));
} else {
$xaction = null;
}
return array($e_value, $errors, $value, $xaction);
}
private function getDisplayValue(
PhabricatorConfigOption $option,
PhabricatorConfigEntry $entry,
$value) {
$type = $option->newOptionType();
if ($type) {
return $type->newDisplayValue($option, $value);
}
if ($option->isCustomType()) {
return $option->getCustomObject()->getDisplayValue(
$option,
$entry,
$value);
}
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
private function renderControls(
PhabricatorConfigOption $option,
$display_value,
$e_value) {
$type = $option->newOptionType();
if ($type) {
return $type->newControls(
$option,
$display_value,
$e_value);
}
if ($option->isCustomType()) {
$controls = $option->getCustomObject()->renderControls(
$option,
$display_value,
$e_value);
} else {
throw new Exception(
pht(
'Unknown configuration option type "%s".',
$option->getType()));
}
return $controls;
}
private function renderExamples(PhabricatorConfigOption $option) {
$examples = $option->getExamples();
if (!$examples) {
return null;
}
$table = array();
$table[] = phutil_tag('tr', array('class' => 'column-labels'), array(
phutil_tag('th', array(), pht('Example')),
phutil_tag('th', array(), pht('Value')),
));
foreach ($examples as $example) {
list($value, $description) = $example;
if ($value === null) {
$value = phutil_tag('em', array(), pht('(empty)'));
} else {
if (is_array($value)) {
$value = implode("\n", $value);
}
}
$table[] = phutil_tag('tr', array('class' => 'column-labels'), array(
phutil_tag('th', array(), $description),
phutil_tag('td', array(), $value),
));
}
require_celerity_resource('config-options-css');
return phutil_tag(
'table',
array(
'class' => 'config-option-table',
'cellspacing' => '0',
'cellpadding' => '0',
),
$table);
}
private function renderDefaults(
PhabricatorConfigOption $option,
PhabricatorConfigEntry $entry) {
$stack = PhabricatorEnv::getConfigSourceStack();
$stack = $stack->getStack();
$table = array();
$table[] = phutil_tag('tr', array('class' => 'column-labels'), array(
phutil_tag('th', array(), pht('Source')),
phutil_tag('th', array(), pht('Value')),
));
$is_effective_value = true;
foreach ($stack as $key => $source) {
$row_classes = array(
'column-labels',
);
$value = $source->getKeys(
array(
$option->getKey(),
));
if (!array_key_exists($option->getKey(), $value)) {
$value = phutil_tag('em', array(), pht('(No Value Configured)'));
} else {
$value = $this->getDisplayValue(
$option,
$entry,
$value[$option->getKey()]);
if ($is_effective_value) {
$is_effective_value = false;
$row_classes[] = 'config-options-effective-value';
}
}
$table[] = phutil_tag(
'tr',
array(
'class' => implode(' ', $row_classes),
),
array(
phutil_tag('th', array(), $source->getName()),
phutil_tag('td', array(), $value),
));
}
require_celerity_resource('config-options-css');
return phutil_tag(
'table',
array(
'class' => 'config-option-table',
'cellspacing' => '0',
'cellpadding' => '0',
),
$table);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigGroupController.php b/src/applications/config/controller/PhabricatorConfigGroupController.php
index 7a3f77dfea..f981c1c1a1 100644
--- a/src/applications/config/controller/PhabricatorConfigGroupController.php
+++ b/src/applications/config/controller/PhabricatorConfigGroupController.php
@@ -1,113 +1,112 @@
<?php
final class PhabricatorConfigGroupController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$group_key = $request->getURIData('key');
$groups = PhabricatorApplicationConfigOptions::loadAll();
$options = idx($groups, $group_key);
if (!$options) {
return new Aphront404Response();
}
$group_uri = PhabricatorConfigGroupConstants::getGroupFullURI(
$options->getGroup());
$group_name = PhabricatorConfigGroupConstants::getGroupShortName(
$options->getGroup());
$nav = $this->buildSideNavView();
$nav->selectFilter($group_uri);
$title = pht('%s Configuration', $options->getName());
$header = $this->buildHeaderView($title);
$list = $this->buildOptionList($options->getOptions());
$group_url = phutil_tag('a', array('href' => $group_uri), $group_name);
$box_header = pht("%s \xC2\xBB %s", $group_url, $options->getName());
$view = $this->buildConfigBoxView($box_header, $list);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($group_name, $group_uri)
->addTextCrumb($options->getName())
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($view);
+ ->setFooter($view);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildOptionList(array $options) {
assert_instances_of($options, 'PhabricatorConfigOption');
require_celerity_resource('config-options-css');
$db_values = array();
if ($options) {
$db_values = id(new PhabricatorConfigEntry())->loadAllWhere(
'configKey IN (%Ls) AND namespace = %s',
mpull($options, 'getKey'),
'default');
$db_values = mpull($db_values, null, 'getConfigKey');
}
$list = new PHUIObjectItemListView();
$list->setBig(true);
foreach ($options as $option) {
$summary = $option->getSummary();
$item = id(new PHUIObjectItemView())
->setHeader($option->getKey())
->setHref('/config/edit/'.$option->getKey().'/')
->addAttribute($summary);
$color = null;
$db_value = idx($db_values, $option->getKey());
if ($db_value && !$db_value->getIsDeleted()) {
$item->setEffect('visited');
$color = 'violet';
}
if ($option->getHidden()) {
$item->setStatusIcon('fa-eye-slash grey', pht('Hidden'));
$item->setDisabled(true);
} else if ($option->getLocked()) {
$item->setStatusIcon('fa-lock '.$color, pht('Locked'));
} else if ($color) {
$item->setStatusIcon('fa-pencil '.$color, pht('Editable'));
} else {
$item->setStatusIcon('fa-pencil-square-o '.$color, pht('Editable'));
}
if (!$option->getHidden()) {
$current_value = PhabricatorEnv::getEnvConfig($option->getKey());
$current_value = PhabricatorConfigJSON::prettyPrintJSON(
$current_value);
$current_value = phutil_tag(
'div',
array(
'class' => 'config-options-current-value '.$color,
),
array(
$current_value,
));
$item->setSideColumn($current_value);
}
$list->addItem($item);
}
return $list;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigHistoryController.php b/src/applications/config/controller/PhabricatorConfigHistoryController.php
index 9157ecb8bb..495102b6a2 100644
--- a/src/applications/config/controller/PhabricatorConfigHistoryController.php
+++ b/src/applications/config/controller/PhabricatorConfigHistoryController.php
@@ -1,49 +1,48 @@
<?php
final class PhabricatorConfigHistoryController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$xactions = id(new PhabricatorConfigTransactionQuery())
->setViewer($viewer)
->needComments(true)
->execute();
$object = new PhabricatorConfigEntry();
$xaction = $object->getApplicationTransactionTemplate();
$timeline = id(new PhabricatorApplicationTransactionView())
->setViewer($viewer)
->setTransactions($xactions)
->setRenderAsFeed(true)
->setObjectPHID(PhabricatorPHIDConstants::PHID_VOID);
$timeline->setShouldTerminate(true);
$title = pht('Settings History');
$header = $this->buildHeaderView($title);
$nav = $this->buildSideNavView();
$nav->selectFilter('history/');
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($timeline);
+ ->setFooter($timeline);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigIssueListController.php b/src/applications/config/controller/PhabricatorConfigIssueListController.php
index 0ca94abe04..6518ccec97 100644
--- a/src/applications/config/controller/PhabricatorConfigIssueListController.php
+++ b/src/applications/config/controller/PhabricatorConfigIssueListController.php
@@ -1,115 +1,114 @@
<?php
final class PhabricatorConfigIssueListController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$nav = $this->buildSideNavView();
$nav->selectFilter('issue/');
$engine = new PhabricatorSetupEngine();
$response = $engine->execute();
if ($response) {
return $response;
}
$issues = $engine->getIssues();
$important = $this->buildIssueList(
$issues,
PhabricatorSetupCheck::GROUP_IMPORTANT,
'fa-warning');
$php = $this->buildIssueList(
$issues,
PhabricatorSetupCheck::GROUP_PHP,
'fa-code');
$mysql = $this->buildIssueList(
$issues,
PhabricatorSetupCheck::GROUP_MYSQL,
'fa-database');
$other = $this->buildIssueList(
$issues,
PhabricatorSetupCheck::GROUP_OTHER,
'fa-question-circle');
$title = pht('Setup Issues');
$header = $this->buildHeaderView($title);
if (!$issues) {
$issue_list = id(new PHUIInfoView())
->setTitle(pht('No Issues'))
->appendChild(
pht('Your install has no current setup issues to resolve.'))
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
} else {
$issue_list = array(
$important,
$php,
$mysql,
$other,
);
$issue_list = $this->buildConfigBoxView(pht('Issues'), $issue_list);
}
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($issue_list);
+ ->setFooter($issue_list);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildIssueList(array $issues, $group, $fonticon) {
assert_instances_of($issues, 'PhabricatorSetupIssue');
$list = new PHUIObjectItemListView();
$list->setBig(true);
$ignored_items = array();
$items = 0;
foreach ($issues as $issue) {
if ($issue->getGroup() == $group) {
$items++;
$href = $this->getApplicationURI('/issue/'.$issue->getIssueKey().'/');
$item = id(new PHUIObjectItemView())
->setHeader($issue->getName())
->setHref($href)
->addAttribute($issue->getSummary());
if (!$issue->getIsIgnored()) {
$icon = id(new PHUIIconView())
->setIcon($fonticon)
->setBackground('bg-sky');
$item->setImageIcon($icon);
$list->addItem($item);
} else {
$icon = id(new PHUIIconView())
->setIcon('fa-eye-slash')
->setBackground('bg-grey');
$item->setDisabled(true);
$item->setImageIcon($icon);
$ignored_items[] = $item;
}
}
}
foreach ($ignored_items as $item) {
$list->addItem($item);
}
if ($items == 0) {
return null;
} else {
return $list;
}
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigIssueViewController.php b/src/applications/config/controller/PhabricatorConfigIssueViewController.php
index 29c9078413..2967169e38 100644
--- a/src/applications/config/controller/PhabricatorConfigIssueViewController.php
+++ b/src/applications/config/controller/PhabricatorConfigIssueViewController.php
@@ -1,76 +1,75 @@
<?php
final class PhabricatorConfigIssueViewController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$issue_key = $request->getURIData('key');
$engine = new PhabricatorSetupEngine();
$response = $engine->execute();
if ($response) {
return $response;
}
$issues = $engine->getIssues();
$nav = $this->buildSideNavView();
$nav->selectFilter('issue/');
if (empty($issues[$issue_key])) {
$content = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->setTitle(pht('Issue Resolved'))
->appendChild(pht('This setup issue has been resolved. '))
->appendChild(
phutil_tag(
'a',
array(
'href' => $this->getApplicationURI('issue/'),
),
pht('Return to Open Issue List')));
$title = pht('Resolved Issue');
} else {
$issue = $issues[$issue_key];
$content = $this->renderIssue($issue);
$title = $issue->getShortName();
}
$header = $this->buildHeaderView($title);
$crumbs = $this
->buildApplicationCrumbs()
->setBorder(true)
->addTextCrumb(pht('Setup Issues'), $this->getApplicationURI('issue/'))
->addTextCrumb($title, $request->getRequestURI())
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($content);
+ ->setFooter($content);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function renderIssue(PhabricatorSetupIssue $issue) {
require_celerity_resource('setup-issue-css');
$view = new PhabricatorSetupIssueView();
$view->setIssue($issue);
$container = phutil_tag(
'div',
array(
'class' => 'setup-issue-background',
),
$view->render());
return $container;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigListController.php b/src/applications/config/controller/PhabricatorConfigListController.php
index 1a136ea416..38a0afc328 100644
--- a/src/applications/config/controller/PhabricatorConfigListController.php
+++ b/src/applications/config/controller/PhabricatorConfigListController.php
@@ -1,58 +1,57 @@
<?php
final class PhabricatorConfigListController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$nav = $this->buildSideNavView();
$nav->selectFilter('/');
$groups = PhabricatorApplicationConfigOptions::loadAll();
$core_list = $this->buildConfigOptionsList($groups, 'core');
$core_list = $this->buildConfigBoxView(pht('Core'), $core_list);
$title = pht('Core Settings');
$header = $this->buildHeaderView($title);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($core_list);
+ ->setFooter($core_list);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
private function buildConfigOptionsList(array $groups, $type) {
assert_instances_of($groups, 'PhabricatorApplicationConfigOptions');
$list = new PHUIObjectItemListView();
$list->setBig(true);
$groups = msort($groups, 'getName');
foreach ($groups as $group) {
if ($group->getGroup() == $type) {
$icon = id(new PHUIIconView())
->setIcon($group->getIcon())
->setBackground('bg-blue');
$item = id(new PHUIObjectItemView())
->setHeader($group->getName())
->setHref('/config/group/'.$group->getKey().'/')
->addAttribute($group->getDescription())
->setImageIcon($icon);
$list->addItem($item);
}
}
return $list;
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigModuleController.php b/src/applications/config/controller/PhabricatorConfigModuleController.php
index 63cc5b3843..fe919c57e4 100644
--- a/src/applications/config/controller/PhabricatorConfigModuleController.php
+++ b/src/applications/config/controller/PhabricatorConfigModuleController.php
@@ -1,41 +1,40 @@
<?php
final class PhabricatorConfigModuleController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$key = $request->getURIData('module');
$all_modules = PhabricatorConfigModule::getAllModules();
if (empty($all_modules[$key])) {
return new Aphront404Response();
}
$module = $all_modules[$key];
$content = $module->renderModuleStatus($request);
$title = $module->getModuleName();
$nav = $this->buildSideNavView();
$nav->selectFilter('module/'.$key.'/');
$header = $this->buildHeaderView($title);
$view = $this->buildConfigBoxView($title, $content);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($view);
+ ->setFooter($view);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigVersionController.php b/src/applications/config/controller/PhabricatorConfigVersionController.php
index a9571a1f85..153d363062 100644
--- a/src/applications/config/controller/PhabricatorConfigVersionController.php
+++ b/src/applications/config/controller/PhabricatorConfigVersionController.php
@@ -1,244 +1,242 @@
<?php
final class PhabricatorConfigVersionController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$title = pht('Version Information');
$versions = $this->renderModuleStatus($viewer);
$nav = $this->buildSideNavView();
$nav->selectFilter('version/');
$header = $this->buildHeaderView($title);
$view = $this->buildConfigBoxView(
pht('Installed Versions'),
$versions);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($title)
->setBorder(true);
$content = id(new PHUITwoColumnView())
->setHeader($header)
- ->setNavigation($nav)
- ->setFixed(true)
- ->setMainColumn($view);
+ ->setFooter($view);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
+ ->setNavigation($nav)
->appendChild($content);
-
}
public function renderModuleStatus($viewer) {
$versions = $this->loadVersions($viewer);
$version_property_list = id(new PHUIPropertyListView());
foreach ($versions as $name => $info) {
$version = $info['version'];
if ($info['branchpoint']) {
$display = pht(
'%s (branched from %s on %s)',
$version,
$info['branchpoint'],
$info['upstream']);
} else {
$display = $version;
}
$version_property_list->addProperty($name, $display);
}
$phabricator_root = dirname(phutil_get_library_root('phabricator'));
$version_path = $phabricator_root.'/conf/local/VERSION';
if (Filesystem::pathExists($version_path)) {
$version_from_file = Filesystem::readFile($version_path);
$version_property_list->addProperty(
pht('Local Version'),
$version_from_file);
}
$version_property_list->addProperty('php', phpversion());
$binaries = PhutilBinaryAnalyzer::getAllBinaries();
foreach ($binaries as $binary) {
if (!$binary->isBinaryAvailable()) {
$binary_info = pht('Not Available');
} else {
$version = $binary->getBinaryVersion();
$path = $binary->getBinaryPath();
if ($path === null && $version === null) {
$binary_info = pht('-');
} else if ($path === null) {
$binary_info = $version;
} else if ($version === null) {
$binary_info = pht('- at %s', $path);
} else {
$binary_info = pht('%s at %s', $version, $path);
}
}
$version_property_list->addProperty(
$binary->getBinaryName(),
$binary_info);
}
return $version_property_list;
}
private function loadVersions(PhabricatorUser $viewer) {
$specs = array(
'phabricator',
'arcanist',
'phutil',
);
$all_libraries = PhutilBootloader::getInstance()->getAllLibraries();
// This puts the core libraries at the top:
$other_libraries = array_diff($all_libraries, $specs);
$specs = array_merge($specs, $other_libraries);
$log_futures = array();
$remote_futures = array();
foreach ($specs as $lib) {
$root = dirname(phutil_get_library_root($lib));
$log_command = csprintf(
'git log --format=%s -n 1 --',
'%H %ct');
$remote_command = csprintf(
'git remote -v');
$log_futures[$lib] = id(new ExecFuture('%C', $log_command))
->setCWD($root);
$remote_futures[$lib] = id(new ExecFuture('%C', $remote_command))
->setCWD($root);
}
$all_futures = array_merge($log_futures, $remote_futures);
id(new FutureIterator($all_futures))
->resolveAll();
// A repository may have a bunch of remotes, but we're only going to look
// for remotes we host to try to figure out where this repository branched.
$upstream_pattern = '(github\.com/phacility/|secure\.phabricator\.com/)';
$upstream_futures = array();
$lib_upstreams = array();
foreach ($specs as $lib) {
$remote_future = $remote_futures[$lib];
list($err, $stdout) = $remote_future->resolve();
if ($err) {
// If this fails for whatever reason, just move on.
continue;
}
// These look like this, with a tab separating the first two fields:
// remote-name http://remote.uri/ (push)
$upstreams = array();
$remotes = phutil_split_lines($stdout, false);
foreach ($remotes as $remote) {
$remote_pattern = '/^([^\t]+)\t([^ ]+) \(([^)]+)\)\z/';
$matches = null;
if (!preg_match($remote_pattern, $remote, $matches)) {
continue;
}
// Remote URIs are either "push" or "fetch": we only care about "fetch"
// URIs.
$type = $matches[3];
if ($type != 'fetch') {
continue;
}
$uri = $matches[2];
$is_upstream = preg_match($upstream_pattern, $uri);
if (!$is_upstream) {
continue;
}
$name = $matches[1];
$upstreams[$name] = $name;
}
// If we have several suitable upstreams, try to pick the one named
// "origin", if it exists. Otherwise, just pick the first one.
if (isset($upstreams['origin'])) {
$upstream = $upstreams['origin'];
} else if ($upstreams) {
$upstream = head($upstreams);
} else {
$upstream = null;
}
if (!$upstream) {
continue;
}
$lib_upstreams[$lib] = $upstream;
$merge_base_command = csprintf(
'git merge-base HEAD %s/master --',
$upstream);
$root = dirname(phutil_get_library_root($lib));
$upstream_futures[$lib] = id(new ExecFuture('%C', $merge_base_command))
->setCWD($root);
}
if ($upstream_futures) {
id(new FutureIterator($upstream_futures))
->resolveAll();
}
$results = array();
foreach ($log_futures as $lib => $future) {
list($err, $stdout) = $future->resolve();
if (!$err) {
list($hash, $epoch) = explode(' ', $stdout);
$version = pht('%s (%s)', $hash, phabricator_date($epoch, $viewer));
} else {
$version = pht('Unknown');
}
$result = array(
'version' => $version,
'upstream' => null,
'branchpoint' => null,
);
$upstream_future = idx($upstream_futures, $lib);
if ($upstream_future) {
list($err, $stdout) = $upstream_future->resolve();
if (!$err) {
$branchpoint = trim($stdout);
if (strlen($branchpoint)) {
// We only list a branchpoint if it differs from HEAD.
if ($branchpoint != $hash) {
$result['upstream'] = $lib_upstreams[$lib];
$result['branchpoint'] = trim($stdout);
}
}
}
}
$results[$lib] = $result;
}
return $results;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Nov 27, 3:01 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1281
Default Alt Text
(106 KB)

Event Timeline