1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Merge branch 'master' into redesign-2015

This commit is contained in:
epriestley 2015-06-23 10:26:41 -07:00
commit 524aa39aa2
25 changed files with 669 additions and 676 deletions

View file

@ -10,7 +10,7 @@ return array(
'core.pkg.css' => '7f0d6232',
'core.pkg.js' => 'a590b451',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'fe951924',
'differential.pkg.css' => '27498de3',
'differential.pkg.js' => 'ebef29b1',
'diffusion.pkg.css' => '385e85b3',
'diffusion.pkg.js' => '0115b37c',
@ -61,7 +61,6 @@ return array(
'rsrc/css/application/differential/changeset-view.css' => '9b8e8bb7',
'rsrc/css/application/differential/core.css' => '7ac3cabc',
'rsrc/css/application/differential/phui-inline-comment.css' => 'fa5b8d1f',
'rsrc/css/application/differential/results-table.css' => '181aa9d9',
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
@ -357,7 +356,6 @@ return array(
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
'rsrc/js/application/differential/behavior-show-field-details.js' => 'bba9eedf',
'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb',
'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d',
'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'b42eddc7',
@ -511,7 +509,6 @@ return array(
'differential-changeset-view-css' => '9b8e8bb7',
'differential-core-view-css' => '7ac3cabc',
'differential-inline-comment-editor' => 'd4c87bf4',
'differential-results-table-css' => '181aa9d9',
'differential-revision-add-comment-css' => 'c47f8c40',
'differential-revision-comment-css' => '14b8565a',
'differential-revision-history-css' => '0e8eb855',
@ -565,7 +562,6 @@ return array(
'javelin-behavior-differential-feedback-preview' => 'b064af76',
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
'javelin-behavior-differential-populate' => '8694b1df',
'javelin-behavior-differential-show-field-details' => 'bba9eedf',
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
'javelin-behavior-differential-user-select' => 'a8d8459d',
'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04',
@ -1711,11 +1707,6 @@ return array(
'javelin-workflow',
'phabricator-draggable-list',
),
'bba9eedf' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'bd4c8dca' => array(
'javelin-install',
'javelin-util',
@ -2192,7 +2183,6 @@ return array(
'differential.pkg.css' => array(
'differential-core-view-css',
'differential-changeset-view-css',
'differential-results-table-css',
'differential-revision-history-css',
'differential-revision-list-css',
'differential-table-of-contents-css',

View file

@ -141,7 +141,6 @@ return array(
'differential.pkg.css' => array(
'differential-core-view-css',
'differential-changeset-view-css',
'differential-results-table-css',
'differential-revision-history-css',
'differential-revision-list-css',
'differential-table-of-contents-css',

View file

@ -419,7 +419,6 @@ phutil_register_library_map(array(
'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php',
'DifferentialRepositoryLookup' => 'applications/differential/query/DifferentialRepositoryLookup.php',
'DifferentialRequiredSignaturesField' => 'applications/differential/customfield/DifferentialRequiredSignaturesField.php',
'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php',
'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php',
'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php',
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
@ -894,6 +893,7 @@ phutil_register_library_map(array(
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php',
'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php',
'HarbormasterManagePlansCapability' => 'applications/harbormaster/capability/HarbormasterManagePlansCapability.php',
'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php',
'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php',
@ -921,6 +921,7 @@ phutil_register_library_map(array(
'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php',
'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php',
'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php',
'HarbormasterUnitPropertyView' => 'applications/harbormaster/view/HarbormasterUnitPropertyView.php',
'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php',
'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php',
'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php',
@ -3789,7 +3790,6 @@ phutil_register_library_map(array(
'DifferentialRepositoryField' => 'DifferentialCoreCustomField',
'DifferentialRepositoryLookup' => 'Phobject',
'DifferentialRequiredSignaturesField' => 'DifferentialCoreCustomField',
'DifferentialResultsTableView' => 'AphrontView',
'DifferentialRevertPlanField' => 'DifferentialStoredCustomField',
'DifferentialReviewedByField' => 'DifferentialCoreCustomField',
'DifferentialReviewer' => 'Phobject',
@ -4356,6 +4356,7 @@ phutil_register_library_map(array(
'HarbormasterDAO' => 'PhabricatorLiskDAO',
'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterLintPropertyView' => 'AphrontView',
'HarbormasterManagePlansCapability' => 'PhabricatorPolicyCapability',
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',
@ -4383,6 +4384,7 @@ phutil_register_library_map(array(
'HarbormasterTargetWorker' => 'HarbormasterWorker',
'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation',
'HarbormasterUIEventListener' => 'PhabricatorEventListener',
'HarbormasterUnitPropertyView' => 'AphrontView',
'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterWorker' => 'PhabricatorWorker',
@ -6730,6 +6732,7 @@ phutil_register_library_map(array(
'PhabricatorProjectInterface',
'PhabricatorDestructibleInterface',
'PhabricatorSpacesInterface',
'PhabricatorMentionableInterface',
),
'PholioMockCommentController' => 'PholioController',
'PholioMockEditController' => 'PholioController',

View file

@ -264,11 +264,11 @@ final class PhabricatorCalendarEventSearchEngine
$list = new PHUIObjectItemListView();
foreach ($events as $event) {
$from = phabricator_datetime($event->getDateFrom(), $viewer);
$duration = '';
$event_date_info = $this->getEventDateLabel($event);
$creator_handle = $handles[$event->getUserPHID()];
$attendees = array();
foreach ($event->getInvitees() as $invitee) {
$attendees[] = $invitee->getInviteePHID();
}
@ -287,8 +287,8 @@ final class PhabricatorCalendarEventSearchEngine
$item = id(new PHUIObjectItemView())
->setHeader($viewer->renderHandle($event->getPHID())->render())
->addAttribute($event_date_info)
->addAttribute($attendees)
->addIcon('none', $from)
->addIcon('none', $duration);
$list->addItem($item);
@ -520,4 +520,41 @@ final class PhabricatorCalendarEventSearchEngine
return false;
}
private function getEventDateLabel($event) {
$viewer = $this->requireViewer();
$from_datetime = PhabricatorTime::getDateTimeFromEpoch(
$event->getDateFrom(),
$viewer);
$to_datetime = PhabricatorTime::getDateTimeFromEpoch(
$event->getDateTo(),
$viewer);
$from_date_formatted = $from_datetime->format('Y m d');
$to_date_formatted = $to_datetime->format('Y m d');
if ($event->getIsAllDay()) {
if ($from_date_formatted == $to_date_formatted) {
return pht(
'%s, All Day',
phabricator_date($event->getDateFrom(), $viewer));
} else {
return pht(
'%s - %s, All Day',
phabricator_date($event->getDateFrom(), $viewer),
phabricator_date($event->getDateTo(), $viewer));
}
} else if ($from_date_formatted == $to_date_formatted) {
return pht(
'%s - %s',
phabricator_datetime($event->getDateFrom(), $viewer),
phabricator_time($event->getDateTo(), $viewer));
} else {
return pht(
'%s - %s',
phabricator_datetime($event->getDateFrom(), $viewer),
phabricator_datetime($event->getDateTo(), $viewer));
}
}
}

View file

@ -160,6 +160,7 @@ final class DifferentialCreateDiffConduitAPIMethod
return array(
'diffid' => $diff->getID(),
'phid' => $diff->getPHID(),
'uri' => $uri,
);
}

View file

@ -265,8 +265,25 @@ final class DifferentialRevisionViewController extends DifferentialController {
$revision_detail_box->setInfoView($revision_warnings);
}
$detail_diffs = array_select_keys(
$diffs,
array($diff_vs, $target->getID()));
$detail_diffs = mpull($detail_diffs, null, 'getPHID');
$buildables = id(new HarbormasterBuildableQuery())
->setViewer($user)
->withBuildablePHIDs(array_keys($detail_diffs))
->withManualBuildables(false)
->needBuilds(true)
->needTargets(true)
->execute();
$buildables = mpull($buildables, null, 'getBuildablePHID');
foreach ($detail_diffs as $diff_phid => $detail_diff) {
$detail_diff->attachBuildable(idx($buildables, $diff_phid));
}
$diff_detail_box = $this->buildDiffDetailView(
array_select_keys($diffs, array($diff_vs, $target->getID())),
$detail_diffs,
$revision,
$field_list);

View file

@ -38,7 +38,6 @@ final class DifferentialLintField
$keys = array(
'arc:lint',
'arc:lint-excuse',
'arc:lint-postponed',
);
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
@ -51,208 +50,72 @@ final class DifferentialLintField
$diff->attachProperty($key, idx($properties, $key));
}
$path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename');
$status = $this->renderLintStatus($diff);
$lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
$lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
$ldata = $diff->getProperty('arc:lint');
$ltail = null;
$lint = array();
$rows = array();
$rows[] = array(
'style' => 'star',
'name' => $lstar,
'value' => $lmsg,
'show' => true,
);
$excuse = $diff->getProperty('arc:lint-excuse');
if ($excuse) {
$rows[] = array(
'style' => 'excuse',
'name' => 'Excuse',
'value' => phutil_escape_html_newlines($excuse),
'show' => true,
);
$buildable = $diff->getBuildable();
if ($buildable) {
$target_phids = array();
foreach ($buildable->getBuilds() as $build) {
foreach ($build->getBuildTargets() as $target) {
$target_phids[] = $target->getPHID();
}
}
$show_limit = 10;
$hidden = array();
if ($ldata) {
$ldata = igroup($ldata, 'path');
foreach ($ldata as $path => $messages) {
$rows[] = array(
'style' => 'section',
'name' => $path,
'show' => $show_limit,
);
foreach ($messages as $message) {
$path = idx($message, 'path');
$line = idx($message, 'line');
$code = idx($message, 'code');
$severity = idx($message, 'severity');
$name = idx($message, 'name');
$description = idx($message, 'description');
$line_link = pht('line %d', intval($line));
if (isset($path_changesets[$path])) {
$href = '#C'.$path_changesets[$path].'NL'.max(1, $line);
// TODO: We are always showing the active diff
// if ($diff->getID() != $this->getDiff()->getID()) {
// $href = '/D'.$diff->getRevisionID().'?id='.$diff->getID().$href;
// }
$line_link = phutil_tag(
'a',
array(
'href' => $href,
),
$line_link);
$lint = id(new HarbormasterBuildLintMessage())->loadAllWhere(
'buildTargetPHID IN (%Ls) LIMIT 25',
$target_phids);
}
if ($show_limit) {
--$show_limit;
$show = true;
if (!$lint) {
// No Harbormaster messages, so look for legacy messages and make them
// look like modern messages.
$legacy_lint = $diff->getProperty('arc:lint');
if ($legacy_lint) {
// Show the top 100 legacy lint messages. Previously, we showed some
// by default and let the user toggle the rest. With modern messages,
// we can send the user to the Harbormaster detail page. Just show
// "a lot" of messages in legacy cases to try to strike a balance
// between implementation simplicitly and compatibility.
$legacy_lint = array_slice($legacy_lint, 0, 100);
$target = new HarbormasterBuildTarget();
foreach ($legacy_lint as $message) {
try {
$modern = HarbormasterBuildLintMessage::newFromDictionary(
$target,
$this->getModernLintMessageDictionary($message));
$lint[] = $modern;
} catch (Exception $ex) {
// Ignore any poorly formatted messages.
}
}
}
}
if ($lint) {
$path_map = mpull($diff->loadChangesets(), 'getID', 'getFilename');
foreach ($path_map as $path => $id) {
$href = '#C'.$id.'NL';
// TODO: When the diff is not the right-hand-size diff, we should
// ideally adjust this URI to be absolute.
$path_map[$path] = $href;
}
$view = id(new HarbormasterLintPropertyView())
->setPathURIMap($path_map)
->setLintMessages($lint);
} else {
$show = false;
if (empty($hidden[$severity])) {
$hidden[$severity] = 0;
}
$hidden[$severity]++;
$view = null;
}
$rows[] = array(
'style' => $this->getSeverityStyle($severity),
'name' => ucwords($severity),
'value' => hsprintf(
'(%s) %s at %s',
$code,
$name,
$line_link),
'show' => $show,
return array(
$status,
$view,
);
if (!empty($message['locations'])) {
$locations = array();
foreach ($message['locations'] as $location) {
$other_line = idx($location, 'line');
$locations[] =
idx($location, 'path', $path).
($other_line ? ":{$other_line}" : '');
}
$description .= "\n".pht(
'Other locations: %s',
implode(', ', $locations));
}
if (strlen($description)) {
$rows[] = array(
'style' => 'details',
'value' => phutil_escape_html_newlines($description),
'show' => false,
);
if (empty($hidden['details'])) {
$hidden['details'] = 0;
}
$hidden['details']++;
}
}
}
}
$postponed = $diff->getProperty('arc:lint-postponed');
if ($postponed) {
foreach ($postponed as $linter) {
$rows[] = array(
'style' => $this->getPostponedStyle(),
'name' => 'Postponed',
'value' => $linter,
'show' => false,
);
if (empty($hidden['postponed'])) {
$hidden['postponed'] = 0;
}
$hidden['postponed']++;
}
}
$show_string = $this->renderShowString($hidden);
$view = new DifferentialResultsTableView();
$view->setRows($rows);
$view->setShowMoreString($show_string);
return $view->render();
}
private function getSeverityStyle($severity) {
$map = array(
ArcanistLintSeverity::SEVERITY_ERROR => 'red',
ArcanistLintSeverity::SEVERITY_WARNING => 'yellow',
ArcanistLintSeverity::SEVERITY_AUTOFIX => 'yellow',
ArcanistLintSeverity::SEVERITY_ADVICE => 'yellow',
);
return idx($map, $severity);
}
private function getPostponedStyle() {
return 'blue';
}
private function renderShowString(array $hidden) {
if (!$hidden) {
return null;
}
// Reorder hidden things by severity.
$hidden = array_select_keys(
$hidden,
array(
ArcanistLintSeverity::SEVERITY_ERROR,
ArcanistLintSeverity::SEVERITY_WARNING,
ArcanistLintSeverity::SEVERITY_AUTOFIX,
ArcanistLintSeverity::SEVERITY_ADVICE,
'details',
'postponed',
)) + $hidden;
$show = array();
foreach ($hidden as $key => $value) {
switch ($key) {
case ArcanistLintSeverity::SEVERITY_ERROR:
$show[] = pht('%d Error(s)', $value);
break;
case ArcanistLintSeverity::SEVERITY_WARNING:
$show[] = pht('%d Warning(s)', $value);
break;
case ArcanistLintSeverity::SEVERITY_AUTOFIX:
$show[] = pht('%d Auto-Fix(es)', $value);
break;
case ArcanistLintSeverity::SEVERITY_ADVICE:
$show[] = pht('%d Advice(s)', $value);
break;
case 'details':
$show[] = pht('%d Detail(s)', $value);
break;
case 'postponed':
$show[] = pht('%d Postponed', $value);
break;
default:
$show[] = $value;
break;
}
}
return pht(
'Show Full Lint Results (%s)',
implode(', ', $show));
}
public function getWarningsForDetailView() {
@ -278,4 +141,50 @@ final class DifferentialLintField
return $warnings;
}
private function renderLintStatus(DifferentialDiff $diff) {
$colors = array(
DifferentialLintStatus::LINT_NONE => 'grey',
DifferentialLintStatus::LINT_OKAY => 'green',
DifferentialLintStatus::LINT_WARN => 'yellow',
DifferentialLintStatus::LINT_FAIL => 'red',
DifferentialLintStatus::LINT_SKIP => 'blue',
DifferentialLintStatus::LINT_AUTO_SKIP => 'blue',
DifferentialLintStatus::LINT_POSTPONED => 'blue',
);
$icon_color = idx($colors, $diff->getLintStatus(), 'grey');
$message = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
$excuse = $diff->getProperty('arc:lint-excuse');
if (strlen($excuse)) {
$excuse = array(
phutil_tag('strong', array(), pht('Excuse:')),
' ',
phutil_escape_html_newlines($excuse),
);
}
$status = id(new PHUIStatusListView())
->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)
->setTarget($message)
->setNote($excuse));
return $status;
}
private function getModernLintMessageDictionary(array $map) {
// Strip out `null` values to satisfy stricter typechecks.
foreach ($map as $key => $value) {
if ($value === null) {
unset($map[$key]);
}
}
// TODO: We might need to remap some stuff here?
return $map;
}
}

View file

@ -48,182 +48,67 @@ final class DifferentialUnitField
$diff->attachProperty($key, idx($properties, $key));
}
$ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
$umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
$status = $this->renderUnitStatus($diff);
$rows = array();
$unit = array();
$rows[] = array(
'style' => 'star',
'name' => $ustar,
'value' => $umsg,
'show' => true,
);
$excuse = $diff->getProperty('arc:unit-excuse');
if ($excuse) {
$rows[] = array(
'style' => 'excuse',
'name' => pht('Excuse'),
'value' => phutil_escape_html_newlines($excuse),
'show' => true,
);
}
$show_limit = 10;
$hidden = array();
$udata = $diff->getProperty('arc:unit');
if ($udata) {
$sort_map = array(
ArcanistUnitTestResult::RESULT_BROKEN => 0,
ArcanistUnitTestResult::RESULT_FAIL => 1,
ArcanistUnitTestResult::RESULT_UNSOUND => 2,
ArcanistUnitTestResult::RESULT_SKIP => 3,
ArcanistUnitTestResult::RESULT_POSTPONED => 4,
ArcanistUnitTestResult::RESULT_PASS => 5,
);
foreach ($udata as $key => $test) {
$udata[$key]['sort'] = idx($sort_map, idx($test, 'result'));
}
$udata = isort($udata, 'sort');
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($this->getViewer());
$markup_objects = array();
foreach ($udata as $key => $test) {
$userdata = idx($test, 'userdata');
if ($userdata) {
if ($userdata !== false) {
$userdata = str_replace("\000", '', $userdata);
}
$markup_object = id(new PhabricatorMarkupOneOff())
->setContent($userdata)
->setPreserveLinebreaks(true);
$engine->addObject($markup_object, 'default');
$markup_objects[$key] = $markup_object;
$buildable = $diff->getBuildable();
if ($buildable) {
$target_phids = array();
foreach ($buildable->getBuilds() as $build) {
foreach ($build->getBuildTargets() as $target) {
$target_phids[] = $target->getPHID();
}
}
$engine->process();
foreach ($udata as $key => $test) {
$result = idx($test, 'result');
$default_hide = false;
switch ($result) {
case ArcanistUnitTestResult::RESULT_POSTPONED:
case ArcanistUnitTestResult::RESULT_PASS:
$default_hide = true;
break;
$unit = id(new HarbormasterBuildUnitMessage())->loadAllWhere(
'buildTargetPHID IN (%Ls) LIMIT 25',
$target_phids);
}
if ($show_limit && !$default_hide) {
--$show_limit;
$show = true;
if (!$unit) {
$legacy_unit = $diff->getProperty('arc:unit');
if ($legacy_unit) {
// Show the top 100 legacy unit messages.
$legacy_unit = array_slice($legacy_unit, 0, 100);
$target = new HarbormasterBuildTarget();
foreach ($legacy_unit as $message) {
try {
$modern = HarbormasterBuildUnitMessage::newFromDictionary(
$target,
$this->getModernUnitMessageDictionary($message));
$unit[] = $modern;
} catch (Exception $ex) {
// Just ignore it if legacy messages aren't formatted like
// we expect.
}
}
}
}
if ($unit) {
$path_map = mpull($diff->loadChangesets(), 'getID', 'getFilename');
foreach ($path_map as $path => $id) {
$href = '#C'.$id.'NL';
// TODO: When the diff is not the right-hand-size diff, we should
// ideally adjust this URI to be absolute.
$path_map[$path] = $href;
}
$view = id(new HarbormasterUnitPropertyView())
->setPathURIMap($path_map)
->setUnitMessages($unit);
} else {
$show = false;
if (empty($hidden[$result])) {
$hidden[$result] = 0;
}
$hidden[$result]++;
$view = null;
}
$value = idx($test, 'name');
$namespace = idx($test, 'namespace');
if ($namespace) {
$value = $namespace.'::'.$value;
}
if (!empty($test['link'])) {
$value = phutil_tag(
'a',
array(
'href' => $test['link'],
'target' => '_blank',
),
$value);
}
$rows[] = array(
'style' => $this->getResultStyle($result),
'name' => ucwords($result),
'value' => $value,
'show' => $show,
return array(
$status,
$view,
);
if (isset($markup_objects[$key])) {
$rows[] = array(
'style' => 'details',
'value' => $engine->getOutput($markup_objects[$key], 'default'),
'show' => false,
);
if (empty($hidden['details'])) {
$hidden['details'] = 0;
}
$hidden['details']++;
}
}
}
$show_string = $this->renderShowString($hidden);
$view = new DifferentialResultsTableView();
$view->setRows($rows);
$view->setShowMoreString($show_string);
return $view->render();
}
private function getResultStyle($result) {
$map = array(
ArcanistUnitTestResult::RESULT_PASS => 'green',
ArcanistUnitTestResult::RESULT_FAIL => 'red',
ArcanistUnitTestResult::RESULT_SKIP => 'blue',
ArcanistUnitTestResult::RESULT_BROKEN => 'red',
ArcanistUnitTestResult::RESULT_UNSOUND => 'yellow',
ArcanistUnitTestResult::RESULT_POSTPONED => 'blue',
);
return idx($map, $result);
}
private function renderShowString(array $hidden) {
if (!$hidden) {
return null;
}
// Reorder hidden things by severity.
$hidden = array_select_keys(
$hidden,
array(
ArcanistUnitTestResult::RESULT_BROKEN,
ArcanistUnitTestResult::RESULT_FAIL,
ArcanistUnitTestResult::RESULT_UNSOUND,
ArcanistUnitTestResult::RESULT_SKIP,
ArcanistUnitTestResult::RESULT_POSTPONED,
ArcanistUnitTestResult::RESULT_PASS,
'details',
)) + $hidden;
$noun = array(
ArcanistUnitTestResult::RESULT_BROKEN => pht('Broken'),
ArcanistUnitTestResult::RESULT_FAIL => pht('Failed'),
ArcanistUnitTestResult::RESULT_UNSOUND => pht('Unsound'),
ArcanistUnitTestResult::RESULT_SKIP => pht('Skipped'),
ArcanistUnitTestResult::RESULT_POSTPONED => pht('Postponed'),
ArcanistUnitTestResult::RESULT_PASS => pht('Passed'),
);
$show = array();
foreach ($hidden as $key => $value) {
if ($key == 'details') {
$show[] = pht('%d Detail(s)', $value);
} else {
$show[] = $value.' '.idx($noun, $key);
}
}
return pht(
'Show Full Unit Results (%s)',
implode(', ', $show));
}
public function getWarningsForDetailView() {
@ -248,4 +133,51 @@ final class DifferentialUnitField
}
private function renderUnitStatus(DifferentialDiff $diff) {
$colors = array(
DifferentialUnitStatus::UNIT_NONE => 'grey',
DifferentialUnitStatus::UNIT_OKAY => 'green',
DifferentialUnitStatus::UNIT_WARN => 'yellow',
DifferentialUnitStatus::UNIT_FAIL => 'red',
DifferentialUnitStatus::UNIT_SKIP => 'blue',
DifferentialUnitStatus::UNIT_AUTO_SKIP => 'blue',
DifferentialUnitStatus::UNIT_POSTPONED => 'blue',
);
$icon_color = idx($colors, $diff->getUnitStatus(), 'grey');
$message = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
$excuse = $diff->getProperty('arc:unit-excuse');
if (strlen($excuse)) {
$excuse = array(
phutil_tag('strong', array(), pht('Excuse:')),
' ',
phutil_escape_html_newlines($excuse),
);
}
$status = id(new PHUIStatusListView())
->addItem(
id(new PHUIStatusItemView())
->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)
->setTarget($message)
->setNote($excuse));
return $status;
}
private function getModernUnitMessageDictionary(array $map) {
// Strip out `null` values to satisfy stricter typechecks.
foreach ($map as $key => $value) {
if ($value === null) {
unset($map[$key]);
}
}
// TODO: Remap more stuff here?
return $map;
}
}

View file

@ -587,6 +587,21 @@ final class DifferentialTransactionEditor
$diff->setRevisionID($object->getID());
$diff->save();
// Update Harbormaster to set the containerPHID correctly for any
// existing buildables. We may otherwise have buildables stuck with
// the old (`null`) container.
// TODO: This is a bit iffy, maybe we can find a cleaner approach?
$table = new HarbormasterBuildable();
$conn_w = $table->establishConnection('w');
queryfx(
$conn_w,
'UPDATE %T SET containerPHID = %s WHERE buildablePHID = %s',
$table->getTableName(),
$object->getPHID(),
$diff->getPHID());
return;
}

View file

@ -39,6 +39,7 @@ final class DifferentialDiff
private $changesets = self::ATTACHABLE;
private $revision = self::ATTACHABLE;
private $properties = array();
private $buildable = self::ATTACHABLE;
protected function getConfiguration() {
return array(
@ -323,6 +324,15 @@ final class DifferentialDiff
return $this->assertAttachedKey($this->properties, $key);
}
public function attachBuildable(HarbormasterBuildable $buildable = null) {
$this->buildable = $buildable;
return $this;
}
public function getBuildable() {
return $this->assertAttached($this->buildable);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -1,115 +0,0 @@
<?php
final class DifferentialResultsTableView extends AphrontView {
private $rows;
private $showMoreString;
public function setRows(array $rows) {
$this->rows = $rows;
return $this;
}
public function setShowMoreString($show_more_string) {
$this->showMoreString = $show_more_string;
return $this;
}
public function render() {
$rows = array();
$any_hidden = false;
foreach ($this->rows as $row) {
$style = idx($row, 'style');
switch ($style) {
case 'section':
$cells = phutil_tag(
'th',
array(
'colspan' => 2,
),
idx($row, 'name'));
break;
default:
$name = phutil_tag(
'th',
array(
),
idx($row, 'name'));
$value = phutil_tag(
'td',
array(
),
idx($row, 'value'));
$cells = array($name, $value);
break;
}
$show = idx($row, 'show');
$rows[] = javelin_tag(
'tr',
array(
'style' => $show ? null : 'display: none',
'sigil' => $show ? null : 'differential-results-row-toggle',
'class' => 'differential-results-row-'.$style,
),
$cells);
if (!$show) {
$any_hidden = true;
}
}
if ($any_hidden) {
$show_more = javelin_tag(
'a',
array(
'href' => '#',
'mustcapture' => true,
),
$this->showMoreString);
$hide_more = javelin_tag(
'a',
array(
'href' => '#',
'mustcapture' => true,
),
pht('Hide'));
$rows[] = javelin_tag(
'tr',
array(
'class' => 'differential-results-row-show',
'sigil' => 'differential-results-row-show',
),
phutil_tag('th', array('colspan' => 2), $show_more));
$rows[] = javelin_tag(
'tr',
array(
'class' => 'differential-results-row-show',
'sigil' => 'differential-results-row-hide',
'style' => 'display: none',
),
phutil_tag('th', array('colspan' => 2), $hide_more));
$this->initBehavior('differential-show-field-details');
}
$this->requireResource('differential-results-table-css');
return javelin_tag(
'table',
array(
'class' => 'differential-results-table',
'sigil' => 'differential-results-table',
),
$rows);
}
}

View file

@ -18,6 +18,8 @@ final class HarbormasterSendMessageConduitAPIMethod
return array(
'buildTargetPHID' => 'required phid',
'lint' => 'optional list<wild>',
'unit' => 'optional list<wild>',
'type' => 'required '.$type_const,
);
}
@ -40,10 +42,31 @@ final class HarbormasterSendMessageConduitAPIMethod
throw new Exception(pht('No such build target!'));
}
$message = HarbormasterBuildMessage::initializeNewMessage($viewer)
$save = array();
$lint_messages = $request->getValue('lint', array());
foreach ($lint_messages as $lint) {
$save[] = HarbormasterBuildLintMessage::newFromDictionary(
$build_target,
$lint);
}
$unit_messages = $request->getValue('unit', array());
foreach ($unit_messages as $unit) {
$save[] = HarbormasterBuildUnitMessage::newFromDictionary(
$build_target,
$unit);
}
$save[] = HarbormasterBuildMessage::initializeNewMessage($viewer)
->setBuildTargetPHID($build_target->getPHID())
->setType($message_type)
->save();
->setType($message_type);
$build_target->openTransaction();
foreach ($save as $object) {
$object->save();
}
$build_target->saveTransaction();
// If the build has completely paused because all steps are blocked on
// waiting targets, this will resume it.

View file

@ -48,9 +48,7 @@ final class HarbormasterBuildViewController
$this->buildPropertyLists($box, $build, $actions);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
$build->getBuildable()->getMonogram(),
'/'.$build->getBuildable()->getMonogram());
$this->addBuildableCrumb($crumbs, $build->getBuildable());
$crumbs->addTextCrumb($title);
if ($generation === null || $generation > $build->getBuildGeneration() ||
@ -99,28 +97,51 @@ final class HarbormasterBuildViewController
$item->setIcon($icon, $color);
$status_view->addItem($item);
$properties->addProperty(pht('Name'), $build_target->getName());
$when = array();
$started = $build_target->getDateStarted();
$now = PhabricatorTime::getNow();
if ($started) {
$ended = $build_target->getDateCompleted();
if ($ended) {
$when[] = pht(
'Completed at %s',
phabricator_datetime($started, $viewer));
if ($build_target->getDateStarted() !== null) {
$properties->addProperty(
pht('Started'),
phabricator_datetime($build_target->getDateStarted(), $viewer));
if ($build_target->isComplete()) {
$properties->addProperty(
pht('Completed'),
phabricator_datetime($build_target->getDateCompleted(), $viewer));
$properties->addProperty(
pht('Duration'),
phutil_format_relative_time_detailed(
$build_target->getDateCompleted() -
$build_target->getDateStarted()));
$duration = ($ended - $started);
if ($duration) {
$when[] = pht(
'Built for %s',
phutil_format_relative_time_detailed($duration));
} else {
$when[] = pht('Built instantly');
}
} else {
$when[] = pht(
'Started at %s',
phabricator_datetime($started, $viewer));
$duration = ($now - $started);
if ($duration) {
$when[] = pht(
'Running for %s',
phutil_format_relative_time_detailed($duration));
}
}
} else {
$created = $build_target->getDateCreated();
$when[] = pht(
'Queued at %s',
phabricator_datetime($started, $viewer));
$duration = ($now - $created);
if ($duration) {
$when[] = pht(
'Waiting for %s',
phutil_format_relative_time_detailed($duration));
}
}
$properties->addProperty(
pht('Elapsed'),
phutil_format_relative_time_detailed(
time() - $build_target->getDateStarted()));
}
}
pht('When'),
phutil_implode_html(" \xC2\xB7 ", $when));
$properties->addProperty(pht('Status'), $status_view);
@ -162,9 +183,7 @@ final class HarbormasterBuildViewController
$variables = $build_target->getVariables();
if ($variables) {
$properties = new PHUIPropertyListView();
foreach ($variables as $key => $value) {
$properties->addProperty($key, $value);
}
$properties->addRawContent($this->buildProperties($variables));
$target_box->addPropertyList($properties, pht('Variables'));
}
@ -183,7 +202,12 @@ final class HarbormasterBuildViewController
}
$properties = new PHUIPropertyListView();
$properties->addProperty(pht('Build Target ID'), $build_target->getID());
$properties->addProperty(
pht('Build Target ID'),
$build_target->getID());
$properties->addProperty(
pht('Build Target PHID'),
$build_target->getPHID());
$target_box->addPropertyList($properties, pht('Metadata'));
$targets[] = $target_box;
@ -528,4 +552,30 @@ final class HarbormasterBuildViewController
return $table;
}
private function buildProperties(array $properties) {
ksort($properties);
$rows = array();
foreach ($properties as $key => $value) {
$rows[] = array(
$key,
$value,
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Key'),
pht('Value'),
))
->setColumnClasses(
array(
'pri right',
'wide',
));
return $table;
}
}

View file

@ -3,21 +3,12 @@
final class HarbormasterBuildableViewController
extends HarbormasterController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$id = $this->id;
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$buildable = id(new HarbormasterBuildableQuery())
->setViewer($viewer)
->withIDs(array($id))
->withIDs(array($request->getURIData('id')))
->needBuildableHandles(true)
->needContainerHandles(true)
->executeOne();
@ -25,6 +16,8 @@ final class HarbormasterBuildableViewController
return new Aphront404Response();
}
$id = $buildable->getID();
// Pull builds and build targets.
$builds = id(new HarbormasterBuildQuery())
->setViewer($viewer)
@ -32,7 +25,10 @@ final class HarbormasterBuildableViewController
->needBuildTargets(true)
->execute();
list($lint, $unit) = $this->renderLintAndUnit($builds);
$buildable->attachBuilds($builds);
$object = $buildable->getBuildableObject();
$build_list = $this->buildBuildList($buildable);
@ -55,12 +51,14 @@ final class HarbormasterBuildableViewController
$this->buildPropertyLists($box, $buildable, $actions);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb("B{$id}");
$crumbs->addTextCrumb($buildable->getMonogram());
return $this->buildApplicationPage(
array(
$crumbs,
$box,
$lint,
$unit,
$build_list,
$timeline,
),
@ -144,16 +142,16 @@ final class HarbormasterBuildableViewController
->setActionList($actions);
$box->addPropertyList($properties);
$properties->addProperty(
pht('Buildable'),
$buildable->getBuildableHandle()->renderLink());
if ($buildable->getContainerHandle() !== null) {
$properties->addProperty(
pht('Container'),
$buildable->getContainerHandle()->renderLink());
}
$properties->addProperty(
pht('Buildable'),
$buildable->getBuildableHandle()->renderLink());
$properties->addProperty(
pht('Origin'),
$buildable->getIsManualBuildable()
@ -250,7 +248,66 @@ final class HarbormasterBuildableViewController
$build_list->addItem($item);
}
return $build_list;
$build_list->setFlush(true);
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Builds'))
->appendChild($build_list);
return $box;
}
private function renderLintAndUnit(array $builds) {
$viewer = $this->getViewer();
$targets = array();
foreach ($builds as $build) {
foreach ($build->getBuildTargets() as $target) {
$targets[] = $target;
}
}
if (!$targets) {
return;
}
$target_phids = mpull($targets, 'getPHID');
$lint_data = id(new HarbormasterBuildLintMessage())->loadAllWhere(
'buildTargetPHID IN (%Ls) LIMIT 25',
$target_phids);
$unit_data = id(new HarbormasterBuildUnitMessage())->loadAllWhere(
'buildTargetPHID IN (%Ls) LIMIT 25',
$target_phids);
if ($lint_data) {
$lint_table = id(new HarbormasterLintPropertyView())
->setUser($viewer)
->setLintMessages($lint_data);
$lint = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint Messages'))
->appendChild($lint_table);
} else {
$lint = null;
}
if ($unit_data) {
$unit_table = id(new HarbormasterUnitPropertyView())
->setUser($viewer)
->setUnitMessages($unit_data);
$unit = id(new PHUIObjectBoxView())
->setHeaderText(pht('Unit Tests'))
->appendChild($unit_table);
} else {
$unit = null;
}
return array($lint, $unit);
}
}

View file

@ -2,4 +2,14 @@
abstract class HarbormasterController extends PhabricatorController {
protected function addBuildableCrumb(
PHUICrumbsView $crumbs,
HarbormasterBuildable $buildable) {
$monogram = $buildable->getMonogram();
$uri = '/'.$monogram;
$crumbs->addTextCrumb($monogram, $uri);
}
}

View file

@ -332,6 +332,11 @@ final class HarbormasterBuildEngine extends Phobject {
$message->save();
$target->setTargetStatus($new_status);
if ($target->isComplete()) {
$target->setDateCompleted(PhabricatorTime::getNow());
}
$target->save();
}
}

View file

@ -13,6 +13,7 @@ final class HarbormasterBuildableQuery
private $needContainerHandles;
private $needBuildableHandles;
private $needBuilds;
private $needTargets;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -59,19 +60,17 @@ final class HarbormasterBuildableQuery
return $this;
}
public function needTargets($need) {
$this->needTargets = $need;
return $this;
}
public function newResultObject() {
return new HarbormasterBuildable();
}
protected function loadPage() {
$table = new HarbormasterBuildable();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $page) {
@ -157,11 +156,12 @@ final class HarbormasterBuildableQuery
}
}
if ($this->needBuilds) {
if ($this->needBuilds || $this->needTargets) {
$builds = id(new HarbormasterBuildQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withBuildablePHIDs(mpull($page, 'getPHID'))
->needBuildTargets($this->needTargets)
->execute();
$builds = mgroup($builds, 'getBuildablePHID');
foreach ($page as $key => $buildable) {
@ -172,47 +172,45 @@ final class HarbormasterBuildableQuery
return $page;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'phid IN (%Ls)',
$this->phids);
}
if ($this->buildablePHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'buildablePHID IN (%Ls)',
$this->buildablePHIDs);
}
if ($this->containerPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'containerPHID in (%Ls)',
$this->containerPHIDs);
}
if ($this->manualBuildables !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'isManualBuildable = %d',
(int)$this->manualBuildables);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
return $where;
}
public function getQueryApplicationClass() {

View file

@ -15,7 +15,7 @@ final class HarbormasterBuildUnitMessage
public static function initializeNewUnitMessage(
HarbormasterBuildTarget $build_target) {
return id(new HarbormasterBuildLintMessage())
return id(new HarbormasterBuildUnitMessage())
->setBuildTargetPHID($build_target->getPHID());
}

View file

@ -0,0 +1,78 @@
<?php
final class HarbormasterLintPropertyView extends AphrontView {
private $pathURIMap = array();
private $lintMessages = array();
public function setPathURIMap(array $map) {
$this->pathURIMap = $map;
return $this;
}
public function setLintMessages(array $messages) {
assert_instances_of($messages, 'HarbormasterBuildLintMessage');
$this->lintMessages = $messages;
return $this;
}
public function render() {
$rows = array();
foreach ($this->lintMessages as $message) {
$path = $message->getPath();
$line = $message->getLine();
$href = null;
if (strlen(idx($this->pathURIMap, $path))) {
$href = $this->pathURIMap[$path].max($line, 1);
}
$severity = $this->renderSeverity($message->getSeverity());
$location = $path.':'.$line;
if (strlen($href)) {
$location = phutil_tag(
'a',
array(
'href' => $href,
),
$location);
}
$rows[] = array(
$location,
$severity,
$message->getCode(),
$message->getName(),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Location'),
pht('Severity'),
pht('Code'),
pht('Message'),
))
->setColumnClasses(
array(
'pri',
null,
null,
'wide',
));
return $table;
}
private function renderSeverity($severity) {
$names = ArcanistLintSeverity::getLintSeverities();
$name = idx($names, $severity, $severity);
// TODO: Add some color here?
return $name;
}
}

View file

@ -0,0 +1,90 @@
<?php
final class HarbormasterUnitPropertyView extends AphrontView {
private $pathURIMap = array();
private $unitMessages = array();
public function setPathURIMap(array $map) {
$this->pathURIMap = $map;
return $this;
}
public function setUnitMessages(array $messages) {
assert_instances_of($messages, 'HarbormasterBuildUnitMessage');
$this->unitMessages = $messages;
return $this;
}
public function render() {
$rows = array();
$any_duration = false;
foreach ($this->unitMessages as $message) {
$result = $this->renderResult($message->getResult());
$duration = $message->getDuration();
if ($duration !== null) {
$any_duration = true;
$duration = pht('%s ms', new PhutilNumber((int)(1000 * $duration)));
}
$name = $message->getName();
$namespace = $message->getNamespace();
if (strlen($namespace)) {
$name = $namespace.'::'.$name;
}
$engine = $message->getEngine();
if (strlen($engine)) {
$name = $engine.' > '.$name;
}
$rows[] = array(
$result,
$duration,
$name,
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Result'),
pht('Time'),
pht('Test'),
))
->setColumnClasses(
array(
null,
null,
'pri wide',
))
->setColumnVisibility(
array(
true,
$any_duration,
));
return $table;
}
private function renderResult($result) {
$names = array(
ArcanistUnitTestResult::RESULT_BROKEN => pht('Broken'),
ArcanistUnitTestResult::RESULT_FAIL => pht('Failed'),
ArcanistUnitTestResult::RESULT_UNSOUND => pht('Unsound'),
ArcanistUnitTestResult::RESULT_SKIP => pht('Skipped'),
ArcanistUnitTestResult::RESULT_POSTPONED => pht('Postponed'),
ArcanistUnitTestResult::RESULT_PASS => pht('Passed'),
);
$result = idx($names, $result, $result);
// TODO: Add some color.
return $result;
}
}

View file

@ -59,7 +59,7 @@ final class HarbormasterTargetWorker extends HarbormasterWorker {
$target->setTargetStatus($next_status);
if ($target->isComplete()) {
$target->setDateCompleted(time());
$target->setDateCompleted(PhabricatorTime::getNow());
}
$target->save();
@ -70,12 +70,12 @@ final class HarbormasterTargetWorker extends HarbormasterWorker {
} catch (HarbormasterBuildFailureException $ex) {
// A build step wants to fail explicitly.
$target->setTargetStatus(HarbormasterBuildTarget::STATUS_FAILED);
$target->setDateCompleted(time());
$target->setDateCompleted(PhabricatorTime::getNow());
$target->save();
} catch (HarbormasterBuildAbortedException $ex) {
// A build step is aborting because the build has been restarted.
$target->setTargetStatus(HarbormasterBuildTarget::STATUS_ABORTED);
$target->setDateCompleted(time());
$target->setDateCompleted(PhabricatorTime::getNow());
$target->save();
} catch (Exception $ex) {
phlog($ex);

View file

@ -10,7 +10,8 @@ final class PholioMock extends PholioDAO
PhabricatorApplicationTransactionInterface,
PhabricatorProjectInterface,
PhabricatorDestructibleInterface,
PhabricatorSpacesInterface {
PhabricatorSpacesInterface,
PhabricatorMentionableInterface {
const MARKUP_FIELD_DESCRIPTION = 'markup:description';

View file

@ -22,6 +22,7 @@ final class PHUIStatusItemView extends AphrontTagView {
const ICON_MINUS = 'fa-minus-circle';
const ICON_OPEN = 'fa-circle-o';
const ICON_CLOCK = 'fa-clock-o';
const ICON_STAR = 'fa-star';
/* render_textarea */
public function setIcon($icon, $color = null, $label = null) {

View file

@ -1,78 +0,0 @@
/**
* @provides differential-results-table-css
*/
table.differential-results-table {
border-collapse: separate;
width: 96%;
font-size: 11px;
}
.differential-results-table th {
text-align: center;
white-space: nowrap;
vertical-align: middle;
padding: 2px 4px;
width: 50px;
border-right: 1px solid #fff;
background: #f7f7f7;
}
.device .differential-results-table th {
white-space: normal;
}
.differential-results-table td {
padding: 0 8px;
margin: 0;
vertical-align: middle;
background: #f7f7f7;
}
.differential-results-table tr.differential-results-row-star th,
.differential-results-table tr.differential-results-row-star td {
background: {$greybackground};
}
.differential-results-table tr.differential-results-row-section th {
padding-top: 4px;
text-align: left;
}
.differential-results-table tr.differential-results-row-excuse th {
background: #3399ff;
}
.differential-results-table tr.differential-results-row-excuse td {
padding-top: 8px;
padding-right: 8px;
padding-bottom: 8px;
}
.differential-results-table tr.differential-results-row-red th {
background: #ff4422;
}
.differential-results-table tr.differential-results-row-yellow th {
background: #ffdd66;
}
.differential-results-table tr.differential-results-row-green th {
background: #22dd44;
}
.differential-results-table tr.differential-results-row-blue th {
background: #88bbff;
}
.differential-results-table tr.differential-results-row-details td {
color: {$lightgreytext};
}
.differential-results-table tr.differential-results-row-show th {
border-top: 1px solid #fff;
border-right: none;
padding: 2px;
color: {$bluetext};
background: {$greybackground};
}

View file

@ -1,40 +0,0 @@
/**
* @provides javelin-behavior-differential-show-field-details
* @requires javelin-behavior
* javelin-stratcom
* javelin-dom
*/
JX.behavior('differential-show-field-details', function() {
JX.Stratcom.listen(
'click',
['differential-results-row-show', 'tag:a'],
function(e) {
toggle(e, true);
});
JX.Stratcom.listen(
'click',
['differential-results-row-hide', 'tag:a'],
function(e) {
toggle(e, false);
});
function toggle(e, show) {
e.kill();
var f = show ? JX.DOM.show : JX.DOM.hide;
var g = show ? JX.DOM.hide : JX.DOM.show;
var table = e.getNode('differential-results-table');
var rows = JX.DOM.scry(table, 'tr', 'differential-results-row-toggle');
for (var ii = 0; ii < rows.length; ii++) {
f(rows[ii]);
}
g(JX.DOM.find(table, 'tr', 'differential-results-row-show'));
f(JX.DOM.find(table, 'tr', 'differential-results-row-hide'));
}
});