Ejegg has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/327401 )

Change subject: WIP top 10 days / hours
......................................................................

WIP top 10 days / hours

TODO: wire up filters

Bug: T152028
Change-Id: I183615c9cb077f078cafa9602fe36aa8fcfbe31a
---
M routes/data.js
A schema/0005_top10.sql
M src/app/startup.js
A src/components/widgets/top10/top10.html
A src/components/widgets/top10/top10.js
A widgets/top10.js
6 files changed, 159 insertions(+), 4 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/dash 
refs/changes/01/327401/1

diff --git a/routes/data.js b/routes/data.js
index 599b3f1..3319b30 100644
--- a/routes/data.js
+++ b/routes/data.js
@@ -329,13 +329,13 @@
                        return;
                }
        }
-       sqlQuery = sqlQuery.replace( '[[WHERE]]', whereClause );
+       sqlQuery = sqlQuery.replace( /\[\[WHERE\]\]/g, whereClause );
        for ( i = 0; i < joins.length; i++ ) {
                joinClause += widget.optionalJoins[joins[i]].text + ' ';
        }
-       sqlQuery = sqlQuery.replace( '[[JOINS]]', joinClause );
-       sqlQuery = sqlQuery.replace( '[[GROUP]]', groupClause );
-       sqlQuery = sqlQuery.replace( '[[SELECTGROUP]]', selectGroup );
+       sqlQuery = sqlQuery.replace( /\[\[JOINS\]\]/g, joinClause );
+       sqlQuery = sqlQuery.replace( /\[\[GROUP\]\]/g, groupClause );
+       sqlQuery = sqlQuery.replace( /\[\[SELECTGROUP\]\]/g, selectGroup );
 
        connection = mysql.createConnection({
                host: config.dbserver,
diff --git a/schema/0005_top10.sql b/schema/0005_top10.sql
new file mode 100644
index 0000000..2f68aa6
--- /dev/null
+++ b/schema/0005_top10.sql
@@ -0,0 +1,2 @@
+INSERT IGNORE INTO dash_widget (code, display_name, description, preview_path)
+       VALUES ('top10', 'Top 10 days and hours', 'Best 10 days and hours in 
the history of fundraising.', 'images/top10.png');
diff --git a/src/app/startup.js b/src/app/startup.js
index 775e4bd..42cd8eb 100644
--- a/src/app/startup.js
+++ b/src/app/startup.js
@@ -29,6 +29,7 @@
                        ko.components.register( 'distance-to-goal-chart',     { 
require: 'components/widgets/distance-to-goal-chart/distance-to-goal-chart' });
                        ko.components.register( 'donation-age',               { 
require: 'components/widgets/donation-age/donation-age' });
                        ko.components.register( 'fraud-gauge',                { 
require: 'components/widgets/fraud-gauge/fraud-gauge' });
+                       ko.components.register( 'top10',                      { 
require: 'components/widgets/top10/top10' });
                        ko.components.register( 'totals-earned-chart',        { 
require: 'components/widgets/totals-earned-chart/totals-earned-chart' });
                        ko.components.register( 'x-by-y',                     { 
require: 'components/widgets/x-by-y/x-by-y' });
 
diff --git a/src/components/widgets/top10/top10.html 
b/src/components/widgets/top10/top10.html
new file mode 100644
index 0000000..3947765
--- /dev/null
+++ b/src/components/widgets/top10/top10.html
@@ -0,0 +1,70 @@
+<div id="top10Widget" class="panel panel-purple panel-short widget-6">
+       <div class="panel-heading">
+               <span data-bind='text: title'></span>
+               <div class="btn-group btn-group-xs pull-right">
+                       <button type="button" class="btn btn-default 
dropdown-toggle" data-toggle="modal" data-target="#top10SqlModal"><i class="fa 
fa-database"></i></button>
+                       <button type="button" class="btn btn-default" 
data-toggle="modal" data-target="#top10FilterModal" ><i class="fa 
fa-edit"></i></button>
+                        <button type="button" class="btn btn-danger" 
data-bind="visible: !chartSaved() && optionStateChanged, click: 
saveWidgetConfig"><i class="fa fa-save"></i></button>
+                        <button type="button" class="btn btn-success" 
data-bind="visible: chartSaved && !optionStateChanged()"><i class="fa 
fa-save"></i> Saved</button>
+                        
+                       <button type="button" class="btn btn-default 
dropdown-toggle" data-toggle="modal" data-bind="attr: { 'data-target': 
'#remove'+instanceID }"><i class="fa fa-times"></i></button>
+               </div>
+       </div>
+       <div class="panel-body">
+               <div class="column text-center">
+                       <h4>Top 10 days</h4>
+                       <ul data-bind='foreach:days'>
+                               <li><span data-bind='text: date'></span>: 
$<span data-bind='text: total'></span></li>
+                       </ul>
+               </div>
+               <div class="column text-center">
+                       <h4>Top 10 hours</h4>
+                       <ul data-bind='foreach: hours'>
+                               <li><span data-bind='text: hour'></span>: 
$<span data-bind='text: total'></span></li>
+                       </ul>
+               </div>
+       </div>
+       <div class="modal fade" id="top10FilterModal">
+               <div class="modal-dialog">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <button type="button" class="close" 
data-dismiss="modal"><span aria-hidden="true">&times;</span><span 
class="sr-only">Close</span></button>
+                                       <h4 class="modal-title">Filters</h4>
+                               </div>
+                               <div class="modal-body">
+                                       <filters params="change: 
logStateChange, userChoices: userChoices, metadataRequest: metadataRequest, 
queryString: filterQueryString" />
+                               </div>
+                       </div>
+               </div>
+       </div>
+                                       
+
+       <div class="modal fade" id="top10SqlModal">
+               <div class="modal-dialog">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <button type="button" class="close" 
data-dismiss="modal"><span aria-hidden="true">&times;</span><span 
class="sr-only">Close</span></button>
+                                       <h4 class="modal-title">Top 10 SQL:</h4>
+                               </div>
+                               <div class="modal-body">
+                                       <p data-bind="text:queryStringSQL"></p>
+                               </div>
+                       </div><!-- /.modal-content -->
+               </div><!-- /.modal-dialog -->
+       </div><!-- /.modal -->
+
+       <div class="modal fade" data-bind="attr: { id: 'remove'+instanceID } ">
+               <div class="modal-dialog modal-sm">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <h2>Remove this widget from the 
board?</h2>
+                               </div>
+                               <div class="modal-body">
+                                       <button class="btn btn-lg btn-success 
pull-right" data-dismiss="modal" data-bind="click: 
$parents[2].removeWidgetFromBoard"> OK</button>
+                                       <button class="btn btn-lg btn-danger 
pull-right" data-dismiss="modal"> Cancel</button>
+                               </div>
+                       </div><!-- /.modal-content -->
+               </div>
+       </div>
+
+</div>
diff --git a/src/components/widgets/top10/top10.js 
b/src/components/widgets/top10/top10.js
new file mode 100644
index 0000000..53097a1
--- /dev/null
+++ b/src/components/widgets/top10/top10.js
@@ -0,0 +1,58 @@
+define([
+       'knockout',
+       'text!components/widgets/top10/top10.html',
+       'momentjs',
+       'WidgetBase'
+       ],
+function( ko, template, moment, WidgetBase ){
+
+       function Top10ViewModel( params ){
+
+               WidgetBase.call( this, params );
+
+               var self = this;
+
+               self.title = ko.observable(params.title);
+               self.queryStringSQL = ko.observable('This widget hasn\'t been 
set up yet!');
+               self.days = ko.observableArray();
+               self.hours = ko.observableArray();
+
+               // Reload the data.  For the automatic reload, we're fine 
getting
+               // something from the cache.
+               self.reloadData = function( automatic ){
+                       self.dataLoading(true);
+                       var url = '/data/top10';
+                       if ( automatic !== true ) {
+                               url += '?cache=false';
+                       }
+                       $.get( url , function ( dataget ) {
+                               var r, i, hours = [], days = [];
+                               for ( i = 0; i < dataget.results.length; i++ ) {
+                                       r = dataget.results[i];
+                                       if ( r.hour === -1 ) {
+                                               days.push( {
+                                                       date: r.year + '-' + 
r.month + '-' + r.day,
+                                                       total: r.usd_total
+                                               } );
+                                       } else {
+                                               hours.push( {
+                                                       hour: r.year + '-' + 
r.month + '-' + r.day + ' ' + r.hour + ':00',
+                                                       total: r.usd_total
+                                               } );
+                                       }
+                               }
+                               self.days( days );
+                               self.hours( hours );
+                               self.dataLoading( false );
+                               self.queryStringSQL( dataget.sqlQuery );
+                       });
+                       // Do it every 5 minutes as well
+                       setTimeout( function () {
+                               self.reloadData( true );
+                       }, 300000 );
+               };
+               self.reloadData( true );
+       }
+
+       return { viewModel: Top10ViewModel, template: template };
+});
diff --git a/widgets/top10.js b/widgets/top10.js
new file mode 100644
index 0000000..2a82c3b
--- /dev/null
+++ b/widgets/top10.js
@@ -0,0 +1,24 @@
+var extend             = require( 'node.extend' ),
+       commonFilters   = require( './common-filters.js' ),
+       config          = require( '../config.js' ),
+       filters         = {};
+
+extend( filters, commonFilters.paymentsInitial );
+extend( filters, commonFilters.contributionTracking );
+extend( filters, commonFilters.civicrmContribution );
+
+module.exports = {
+       name: 'top10',
+       query: 'SELECT * FROM (SELECT YEAR(receive_date) AS year, 
MONTH(receive_date) AS month, DAY(receive_date) AS day, -1 AS hour, count(*) AS 
donations, SUM(total_amount) AS usd_total FROM ' + config.civicrmDb + 
'.civicrm_contribution cc [[JOINS]] [[WHERE]] GROUP BY YEAR(receive_date), 
MONTH(receive_date), DAY(receive_date) ORDER BY usd_total DESC LIMIT 10) AS 
top_days UNION (SELECT YEAR(receive_date) AS year, MONTH(receive_date) AS 
month, DAY(receive_date) AS day, HOUR(receive_date) AS hour, count(*) AS 
donations, SUM(total_amount) AS usd_total FROM ' + config.civicrmDb + 
'.civicrm_contribution cc [[JOINS]] [[WHERE]] GROUP BY YEAR(receive_date), 
MONTH(receive_date), DAY(receive_date), HOUR(receive_date) ORDER BY usd_total 
DESC LIMIT 10);',
+       mainTableAlias: 'cc',
+       optionalJoins: {
+               ct: {
+                       text: 'LEFT JOIN drupal.contribution_tracking ct ON 
ct.contribution_id = cc.id'
+               },
+               pi: {
+                       text: 'LEFT JOIN payments_initial pi ON 
pi.contribution_tracking_id = ct.id',
+                       requires: [ 'ct' ]
+               }
+       },
+       filters: filters
+};

-- 
To view, visit https://gerrit.wikimedia.org/r/327401
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I183615c9cb077f078cafa9602fe36aa8fcfbe31a
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/fundraising/dash
Gerrit-Branch: master
Gerrit-Owner: Ejegg <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to