Skip to content
Browse files

Fix support for jquery tables, add the ability to specify fields,

refactor templates, add support for a simple HTML list output type, add
some CSS classes for bugs in various states, ignore all sorts of
swap files in the .gitignore
  • Loading branch information...
1 parent 060a430 commit 5a4db4a462ea41984ffdf306d5a732204c62349e @LegNeato LegNeato committed Apr 13, 2012
View
2 .gitignore
@@ -1 +1 @@
-*.swp
+*.sw*
View
43 Bugzilla.php
@@ -74,12 +74,14 @@ function BugzillaCreateCache( $updater ) {
function BugzillaIncludeHTML( &$out, &$sk ) {
global $wgScriptPath;
+ global $wgBugzillaJqueryTable;
- // Use local jquery
- $out->addScriptFile("$wgScriptPath/extensions/Bugzilla/web/jquery/1.6.2/jquery.min.js");
+ if( $wgBugzillaJqueryTable ) {
+ // Use local jquery
+ $out->addScript("<script type='text/javascript' src='$wgScriptPath/extensions/Bugzilla/web/jquery/1.6.2/jquery.min.js'></script>");
- // Use local jquery ui
- $out->addScriptFile("$wgScriptPath/extensions/Bugzilla/web/jqueryui/1.8.14/jquery-ui.min.js");
+ // Use local jquery ui
+ $out->addScript("<script type='text/javascript' src='$wgScriptPath/extensions/Bugzilla/web/jqueryui/1.8.14/jquery-ui.min.js'></script>");
// Add a local script file for the datatable
$out->addScriptFile("$wgScriptPath/extensions/Bugzilla/web/js/jquery.dataTables.js");
@@ -96,9 +98,18 @@ function BugzillaIncludeHTML( &$out, &$sk ) {
// Add the script to do table magic
$out->addInlineScript('$(document).ready(function() {
- $(".bugzilla").dataTable({
+ $("table.bugzilla").dataTable({
"bJQueryUI": true
})});');
+ }
+
+ // Add local bugzilla extension styles
+ $out->addStyle("$wgScriptPath/extensions/Bugzilla/web/css/bugzilla.css");
+
+ // Let the user optionally override bugzilla extension styles
+ if( file_exists("$wgScriptPath/extensions/Bugzilla/web/css/custom.css") ) {
+ $out->addStyle("$wgScriptPath/extensions/Bugzilla/web/css/custom.css");
+ }
// Let the other hooks keep processing
return TRUE;
@@ -122,7 +133,13 @@ function BugzillaRender($input, array $args, Parser $parser, $frame ) {
// We don't want the page to be cached
// TODO: Not sure if we need this
$parser->disableCache();
- $input = $parser->recursiveTagParse($input, $frame);
+
+ // TODO: Figure out to have the parser not do anything to our output
+ // mediawiki docs are wrong :-(
+ // error_log(print_r($parser->mStripState, true));
+ // $parser->mStripState->addItem( 'nowiki', 'NOWIKI', true);
+ // 'noparse' => true, 'isHTML' => true, 'markerType' => 'nowiki' );
+
// Create a new bugzilla object
$bz = Bugzilla::create($args, $input, $parser->getTitle());
@@ -138,13 +155,19 @@ function BugzillaRender($input, array $args, Parser $parser, $frame ) {
$wgBugzillaRESTURL = 'https://api-dev.bugzilla.mozilla.org/latest';
$wgBugzillaURL = 'https://bugzilla.mozilla.org';
$wgBugzillaTagName = 'bugzilla';
-$wgBugzillaMethod = 'REST'; // XML-RPC and JSON-RPC may be supported later
-$wgBugzillaUseCache = TRUE;
-$wgBugzillaCacheMins = 5;
+$wgBugzillaMethod = 'REST'; // XML-RPC and JSON-RPC aren't supported yet
+$wgBugzillaDefaultFields = array(
+ 'id',
+ 'summary',
+ 'priority',
+ 'status',
+);
$wgBugzillaJqueryTable = FALSE;
// Cache settings
-$wgCacheObject = 'BugzillaCacheMysql';
+$wgBugzillaUseCache = TRUE;
+$wgCacheObject = 'BugzillaCacheDummy';
+$wgBugzillaCacheMins = 10;
$wgBugzillaChartStorage = realpath($cwd . '/charts');
$wgBugzillaFontStorage = $cwd . '/pchart/fonts';
View
57 BugzillaOutput.class.php
@@ -6,8 +6,8 @@
public $cache;
public function __construct($config, $options, $title='') {
- $this->title = $title;
- $this->config = $config;
+ $this->title = $title;
+ $this->config = $config;
$this->error = FALSE;
$this->response = new stdClass();
@@ -64,20 +64,53 @@ protected function _getCache()
return $this->cache;
}
-
- abstract public function _setup_template_data();
+
+ abstract protected function _setup_template_data();
}
-class BugzillaTable extends BugzillaOutput {
+class BugzillaBugListing extends BugzillaOutput {
+
+ protected function _setup_template_data() {
- public function _setup_template_data() {
- if(count($this->query->data->bugs) > 0) {
- $this->response->bugs = $this->query->data->bugs;
- } else {
- $this->response->bugs = array();
+ global $wgBugzillaDefaultFields;
+
+ $this->response->bugs = array();
+ $this->response->fields = array();
+
+ // Set the bug data for the templates
+ if(count($this->query->data['bugs']) > 0) {
+ $this->response->bugs = $this->query->data['bugs'];
+ }
+
+ // Set the field data for the templates
+ if( isset($this->query->options['include_fields']) &&
+ !empty($this->query->options['include_fields']) ) {
+ // User specified some fields
+ $tmp = @explode(',', $this->query->options['include_fields']);
+ foreach( $tmp as $tmp_field ) {
+ $field = trim($tmp_field);
+ // Catch if the user specified the same field multiple times
+ if( !empty($field) &&
+ !in_array($field, $this->response->fields) ) {
+ array_push($this->response->fields, $field);
+ }
+ }
+ }else {
+ // If the user didn't specify any fields in the query config use
+ // default fields
+ $this->response->fields = $wgBugzillaDefaultFields;
}
}
+
+}
+
+class BugzillaList extends BugzillaBugListing {
+
+}
+
+class BugzillaTable extends BugzillaBugListing {
+
}
abstract class BugzillaGraph extends BugzillaOutput {
@@ -94,9 +127,9 @@ public function generate_chart($chart_name)
{
global $wgBugzillaChartStorage, $wgBugzillaFontStorage;
$pData = new pData();
- $pData->addPoints($this->query->data->data, 'Counts');
+ $pData->addPoints($this->query->data['data'], 'Counts');
$pData->setAxisName(0, 'Bugs');
- $pData->addPoints($this->query->data->x_labels, "Bugs");
+ $pData->addPoints($this->query->data['x_labels'], "Bugs");
$pData->setSerieDescription("Bugs", "Bugs");
$pData->setAbscissa("Bugs");
View
77 BugzillaQuery.class.php
@@ -21,14 +21,15 @@ public function create($type, $options, $title) {
abstract class BugzillaBaseQuery {
public function __construct($type, $options, $title) {
- $this->type = $type;
- $this->title = $title;
- $this->url = FALSE;
- $this->id = FALSE;
- $this->fetched_at = FALSE;
- $this->error = FALSE;
- $this->data = array();
- $this->cache = FALSE;
+ $this->type = $type;
+ $this->title = $title;
+ $this->url = FALSE;
+ $this->id = FALSE;
+ $this->fetched_at = FALSE;
+ $this->error = FALSE;
+ $this->data = array();
+ $this->synthetic_fields = array();
+ $this->cache = FALSE;
$this->_set_options($options);
}
@@ -59,10 +60,43 @@ protected function _generate_id() {
// Sort it so the keys are always in the same order
ksort($this->options);
+
+ // Treat include_fields special because we don't want to query multiple
+ // times if the same fields were requested in a different order
+ $saved_include_fields = array();
+ if( isset($this->options['include_fields']) &&
+ !empty($this->options['include_fields']) ) {
+
+ $saved_include_fields = $this->options['include_fields'];
+
+ // This is important. If a user asks for a subset of the default
+ // fields and another user has the same query w/ a subset,
+ // it is silly to cache the queries separately. We know the
+ // defaults will always be pulled, so anything asking for
+ // any combination of the defaults (or any combined subset) are
+ // esentially the same
+ $include_fields = $this->synthetic_fields;
+
+ $tmp = @explode(',', $this->options['include_fields']);
+ foreach( $tmp as $tmp_field ) {
+ $field = trim($tmp_field);
+ // Catch if the user specified the same field multiple times
+ if( !empty($field) && !in_array($field, $include_fields) ) {
+ array_push($include_fields, $field);
+ }
+ }
+ sort($include_fields);
+ $this->options['include_fields'] = @implode(',', $include_fields);
+ }
// Get a string representation of the array
$id_string = serialize($this->options);
+ // Restore the include_fields to what the user wanted
+ if( $saved_include_fields ) {
+ $this->options['include_fields'] = $saved_include_fields;
+ }
+
// Hash it
$this->id = sha1($id_string);
@@ -108,13 +142,11 @@ public function fetch() {
protected function _set_options($query_options_raw) {
// Make sure query options are valid JSON
- $this->options = json_decode($query_options_raw);
+ $this->options = json_decode($query_options_raw, TRUE);
if( !$query_options_raw || !$this->options ) {
$this->error = 'Query options must be valid json';
return;
}
- // Object is kinda useless, make it an array
- $this->options = get_object_vars($this->options);
}
abstract public function _fetch_by_options();
@@ -131,21 +163,25 @@ class BugzillaRESTQuery extends BugzillaBaseQuery {
function __construct($type, $options, $title='') {
global $wgBugzillaRESTURL;
+ global $wgBugzillaDefaultFields;
parent::__construct($type, $options, $title);
// See what sort of REST query we are going to
switch( $type ) {
// Whitelist
- case 'bug':
case 'count':
$this->url = $wgBugzillaRESTURL . '/' . urlencode($type);
+ // Note there are no synthetic fields for count
break;
// Default to a bug query
+ case 'bug':
default:
$this->url = $wgBugzillaRESTURL . '/bug';
+ // Even if the user didn't specify, we need these
+ $this->synthetic_fields = $wgBugzillaDefaultFields;
}
$this->fetch();
@@ -165,15 +201,28 @@ public function _fetch_by_options() {
$request->setHeader('Accept', 'application/json');
$request->setHeader('Content-Type', 'application/json');
- // Add in the requested query options
+ // Save the real options
+ $saved_options = $this->options;
+
+ // Add any synthetic fields to the options
+ if( !empty($this->synthetic_fields) ) {
+ $this->options['include_fields'] =
+ @array_merge((array)$this->options['include_fields'],
+ $this->synthetic_fields);
+ }
+
+ // Add the requested query options to the request
$url = $request->getUrl();
$url->setQueryVariables($this->options);
+ // Retore the real options, removing anything we synthesized
+ $this->options = $saved_options;
+
// This is basically straight from the HTTP/Request2 docs
try {
$response = $request->send();
if (200 == $response->getStatus()) {
- $this->data = json_decode($response->getBody());
+ $this->data = json_decode($response->getBody(), TRUE);
} else {
$this->error = 'Server returned unexpected HTTP status: ' .
$response->getStatus() . ' ' .
View
36 templates/bug/list.tpl
@@ -0,0 +1,36 @@
+<ul class="bugzilla ui-helper-reset">
+ <?php
+ $base = dirname(__FILE__) . '/../../templates/fields/';
+
+ foreach( $response->bugs as $bug ) {
+ echo "<li class='bugzilla-status-${bug['status']}'>";
+ $count = 0;
+ foreach( $response->fields as $field ) {
+ if( $count ) {
+ echo " - ";
+ }
+ echo "<span class='bugzilla-data-$field'>";
+
+ // Get our template path
+ $subtemplate = $base .
+ escapeshellcmd(str_replace('..',
+ 'DOTS',
+ $field)) .
+ '.tpl';
+
+ // Make sure a template is there
+ if( !file_exists($subtemplate) ) {
+ $subtemplate = $base . '_default.tpl';
+ }
+
+ // Print out the data
+ $data = $bug[$field];
+ require($subtemplate);
+
+ echo "</span>";
+ $count++;
+ }
+ echo "</li>\n";
+ }
+ ?>
+</ul>
View
64 templates/bug/table.tpl
@@ -1,20 +1,58 @@
-<table class="bugzilla ui-helper-reset">
+<?php
+ global $wgBugzillaJqueryTable;
+ $extra_class = ($wgBugzillaJqueryTable) ? 'jquery ui-helper-reset' : '';
+?>
+<table class="bugzilla <?php echo $extra_class ?>">
<thead>
<tr>
- <th>ID</th>
- <th>Summary</th>
- <th>Status</th>
- <th>Priority</th>
+ <?php
+ foreach( $response->fields as $field ) {
+ echo "<th>";
+ switch( $field ) {
+ case 'id':
+ echo 'ID';
+ break;
+ default:
+ echo htmlspecialchars(
+ ucfirst(
+ str_replace('_', ' ',
+ preg_replace('/^cf_/', '',
+ $field))));
+ }
+ echo "</th>\n";
+ }
+ ?>
</tr>
</thead>
<tbody>
- <?php foreach($response->bugs as $bug): ?>
- <tr>
- <td><a href="<?php echo $wgBugzillaURL ?>/show_bug.cgi?id=<?php echo $bug->id ?>"><?php echo $bug->id ?></a></td>
- <td><a href="<?php echo $wgBugzillaURL ?>/show_bug.cgi?id=<?php echo $bug->id ?>"><?php echo $bug->summary ?></a></td>
- <td><?php echo $bug->status ?></td>
- <td><?php echo $bug->priority ?></td>
- </tr>
- <?php endforeach; ?>
+ <?php
+ $base = dirname(__FILE__) . '/../../templates/fields/';
+
+ foreach( $response->bugs as $bug ) {
+ echo "<tr class='bugzilla-status-${bug['status']}'>";
+ foreach( $response->fields as $field ) {
+ echo "<td class='bugzilla-data-$field'>";
+
+ // Get our template path
+ $subtemplate = $base .
+ escapeshellcmd(str_replace('..',
+ 'DOTS',
+ $field)) .
+ '.tpl';
+
+ // Make sure a template is there
+ if( !file_exists($subtemplate) ) {
+ $subtemplate = $base . '_default.tpl';
+ }
+
+ // Print out the data
+ $data = $bug[$field];
+ require($subtemplate);
+
+ echo "</td>\n";
+ }
+ echo "</tr>\n";
+ }
+ ?>
</tbody>
</table>
View
5 templates/fields/_default.tpl
@@ -0,0 +1,5 @@
+<?php
+ echo "<span class='bugzilla-field-$field'>";
+ echo htmlspecialchars($bug[$field]);
+ echo "</span>";
+?>
View
8 templates/fields/id.tpl
@@ -0,0 +1,8 @@
+<?php
+ global $wgBugzillaURL;
+
+ echo "<a href='$wgBugzillaURL/show_bug.cgi?id=" .
+ urlencode($bug['id']) ."'>";
+ echo htmlspecialchars($bug['id']);
+ echo "</a>";
+?>
View
8 templates/fields/summary.tpl
@@ -0,0 +1,8 @@
+<?php
+ global $wgBugzillaURL;
+
+ echo "<a href='$wgBugzillaURL/show_bug.cgi?id=" .
+ urlencode($bug['id']) ."'>";
+ echo htmlspecialchars($bug['summary']);
+ echo "</a>";
+?>
View
8 templates/fields/url.tpl
@@ -0,0 +1,8 @@
+<?php
+ global $wgBugzillaURL;
+
+ echo "<a href='$wgBugzillaURL/show_bug.cgi?id=" .
+ urlencode($bug['id']) ."'>";
+ echo htmlspecialchars($bug['url']);
+ echo "</a>";
+?>
View
33 web/css/bugzilla.css
@@ -1,5 +1,32 @@
-/*
-table.bugzilla {
+
+/* Jquery table */
+table.jquery.bugzilla {
width: 100%;
}
-*/
+
+/* Table view styles */
+
+tr.bugzilla-status-NEW {
+ background-color: #ffeeee;
+}
+
+tr.bugzilla-status-ASSIGNED {
+ background-color: #eeeeff;
+}
+
+tr.bugzilla-status-REOPENED {
+ background-color: #ffffee;
+}
+
+tr.bugzilla-status-RESOLVED {
+ background-color: #eeffee;
+}
+
+tr.bugzilla-status-VERIFIED {
+ background-color: #ccffcc;
+
+/* General styles */
+.bugzilla-status-RESOLVED .bugzilla-data-id,
+.bugzilla-status-VERIFIED .bugzilla-data-id {
+ text-decoration: line-through;
+}

0 comments on commit 5a4db4a

Please sign in to comment.
Something went wrong with that request. Please try again.