Ssmith has uploaded a new change for review. https://gerrit.wikimedia.org/r/187297
Change subject: Add generic board functionality & update sql ...................................................................... Add generic board functionality & update sql Needs big english refactor Change-Id: I0e09c65f7d2ea73dae261e20b337d07774a6a55e --- A cividump.sql M gulpfile.js M persistence.sql A routes/library.js M server.js M src/app/startup.js M src/components/app-content/app-content.html M src/components/app-content/app-content.js M src/components/boards/bigEnglish/bigEnglishBoard.html A src/components/boards/generic-board/generic-board.html A src/components/boards/generic-board/generic-board.js M src/components/nav-bar/nav-bar.html M src/components/nav-bar/nav-bar.js M src/components/widgets/totals-earned-chart/totals-earned-chart.html R src/components/widgets/x-by-y/x-by-y.html R src/components/widgets/x-by-y/x-by-y.js M src/css/style.css 17 files changed, 274 insertions(+), 72 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/dash refs/changes/97/187297/1 diff --git a/cividump.sql b/cividump.sql new file mode 100644 index 0000000..1e7c4f6 --- /dev/null +++ b/cividump.sql Binary files differ diff --git a/gulpfile.js b/gulpfile.js index a464932..e6657cc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -38,7 +38,7 @@ 'components/widgets/totals-earned-chart/totals-earned-chart', 'components/widgets/amt-per-second-chart/amt-per-second-chart', 'components/boards/bigEnglish/bigEnglishBoard', - 'components/widgets/x-by-y-chart/x-by-y-chart' + 'components/widgets/x-by-y/x-by-y' ], insertRequire: ['app/startup'], bundles: { diff --git a/persistence.sql b/persistence.sql index 7e3b2c6..57ff27c 100644 --- a/persistence.sql +++ b/persistence.sql @@ -21,7 +21,7 @@ display_name VARCHAR(255), description TEXT, preview_path VARCHAR(255), /* preview image */ - UNIQUE (code) + UNIQUE (code) ); /* Saved widget configurations */ CREATE TABLE IF NOT EXISTS dash_widget_instance( @@ -55,9 +55,11 @@ ); /* Add definitions for existing widgets */ -INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'fraud', 'Fraud Gauge', 'Shows the percentage of transactions rejected by fraud filters', 'images/fraud.png' ); -INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'big-english', 'Big English', 'Shows a set of graphs relating to the big English fundraiser', 'images/big-english.png' ); +INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'fraud-gauge', 'Fraud Gauge', 'Shows the percentage of transactions rejected by fraud filters', 'images/fraud.png' ); INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'x-by-y', 'X by Y', 'A highly configurable chart allowing grouping by many measures', 'images/x-by-y.png' ); +INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'amt-per-second-chart', 'Amount Per Second', 'Shows USD per second required to reach Big English goal', 'images/amt-per-sec.png'); +INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'distance-to-goal-chart', 'Distance to Goal', 'Line chart showing USD needed to reach overall Big English goal', 'images/distance-to-goal.png'); +INSERT IGNORE INTO dash_widget ( code, display_name, description, preview_path ) VALUES ( 'totals-earned-chart', 'Totals Earned', 'Main Big English bar chart showing daily and hourly donation totals and counts', 'images/totals-earned.png'); /* Tailor these to your liking GRANT INSERT, SELECT, UPDATE, DELETE ON dash_widget_instance_board TO 'testuser'@'localhost'; diff --git a/routes/library.js b/routes/library.js new file mode 100644 index 0000000..9166ef6 --- /dev/null +++ b/routes/library.js @@ -0,0 +1,9 @@ +var persistence = require( '../persistence.js' ); + +module.exports = { + //find all widgets + //find all widget instances that are shared + get: function( req, res ) { + return res; + } +}; \ No newline at end of file diff --git a/server.js b/server.js index 565b3b2..111d2de 100644 --- a/server.js +++ b/server.js @@ -82,6 +82,7 @@ app.post( '/board', routes.board.save ); app.put( '/board/:id', routes.board.save ); app.get( '/board/:id', routes.board.get ); +app.get( '/library', routes.library.get ); /*jslint -W024*/ app.use( express.static( __dirname + ( config.debug ? '/src' : '/dist' ) ) ); diff --git a/src/app/startup.js b/src/app/startup.js index 00c9550..e6cc743 100644 --- a/src/app/startup.js +++ b/src/app/startup.js @@ -16,6 +16,7 @@ ko.components.register( 'date-pickers', { require: 'components/utils/date-pickers/date-pickers' }); //register boards + ko.components.register( 'generic-board', { require: 'components/boards/generic-board/generic-board' }); ko.components.register( 'bigEnglishBoard', { require: 'components/boards/bigEnglish/bigEnglishBoard' }); //register individual widgets @@ -23,7 +24,7 @@ ko.components.register( 'totals-earned-chart', { require: 'components/widgets/totals-earned-chart/totals-earned-chart' }); ko.components.register( 'distance-to-goal-chart', { require: 'components/widgets/distance-to-goal-chart/distance-to-goal-chart' }); ko.components.register( 'amt-per-second-chart', { require: 'components/widgets/amt-per-second-chart/amt-per-second-chart' }); - ko.components.register( 'x-by-y-chart', { require: 'components/widgets/x-by-y-chart/x-by-y-chart' }); + ko.components.register( 'x-by-y', { require: 'components/widgets/x-by-y/x-by-y' }); //fire up router ko.applyBindings({ route: router.currentRoute }); diff --git a/src/components/app-content/app-content.html b/src/components/app-content/app-content.html index 8f2c95b..7e9c738 100644 --- a/src/components/app-content/app-content.html +++ b/src/components/app-content/app-content.html @@ -4,7 +4,7 @@ <div class="container-fluid" data-bind='if: loggedIn'> <div class="row"> - <div data-bind="component: userDefaultBoard" class="col-md-12"></div> + <generic-board params="widgets: widgets, userWidgets: userWidgets"></generic-board> </div> </div> diff --git a/src/components/app-content/app-content.js b/src/components/app-content/app-content.js index 08e79ab..cd3447c 100644 --- a/src/components/app-content/app-content.js +++ b/src/components/app-content/app-content.js @@ -12,17 +12,37 @@ self.content = ko.observable('this is the content'); self.description = ko.observable(); self.graphs = ko.observableArray([]); + self.userdata = ko.observable(); + self.widgets = ko.observableArray(); + self.boards = ko.observableArray(); + self.thisBoardWidgets = ko.observableArray(); + self.userDefaultBoard = ko.observable(); + self.userBoards = ko.observableArray(); + self.userWidgets = ko.observableArray(); - //set this based on user settings. - self.userDefaultBoard = ko.observable('bigEnglishBoard'); + //get widget info + $.get('widget', function(widgetdata){ + self.widgets( widgetdata ); + }); - //for now make this dummy - it should come from params/global user settings - self.userBoards = ko.observableArray([ - { name: 'Big English', component: 'bigEnglishBoard' }, - { name: 'A/B Testing', component: 'bigEnglishBoard' }, - { name: 'Fraud Monitoring', component: 'bigEnglishBoard' }, - { name: 'Times Honey is Cute', component: 'bigEnglishBoard' } - ]); + //get user info + $.get('user/info', function( userdata ){ + self.userdata( userdata ); + }).done( function( thedata ){ + $.get('board/' + self.userdata().defaultBoard, function( thedata ){ + + self.userDefaultBoard( thedata ); + + //set this based on user settings. + //(for now do this, because there is an issue) + self.userWidgets([5,3,4,1]); + // self.userWidgets($.map(self.userDefaultBoard().widgets, function(obj){ + // return obj.id; + // })); + }); + }); + + self.loggedIn = ko.observable(false); self.welcome = ko.observable(''); diff --git a/src/components/boards/bigEnglish/bigEnglishBoard.html b/src/components/boards/bigEnglish/bigEnglishBoard.html index 8f1b9b7..cd36b4f 100644 --- a/src/components/boards/bigEnglish/bigEnglishBoard.html +++ b/src/components/boards/bigEnglish/bigEnglishBoard.html @@ -19,55 +19,6 @@ </div> </span> -<div class="row"> - <div class="panel panel-transparent"> - <div class="panel-body"> - <!--Main updates: Goal, Total so far, Remaining to raise--> - <div class="row-fluid bigEnglish-updates"> - <div class="col-md-4 col-sm-4 col-lg-4"> - <div class="row factbox factbox-blue"> - <div class="col-md-3"> - <div class="factbox-icon"> - <i class='fa fa-soccer-ball-o'></i> - </div> - </div> - <div class="col-md-9"> - <p class='factbox-header'>2014 Big English Goal</p> - <h3 data-bind="text: bigEnglishGoal"></h3> - </div> - </div> - </div> - <div class="col-md-4 col-sm-4 col-lg-4"> - <div class="row factbox factbox-yellow"> - <div class="col-md-3"> - <div class="factbox-icon"> - <i class='fa fa-gift'></i> - </div> - </div> - <div class="col-md-9"> - <p class='factbox-header'>Total To Date</p> - <h3 data-bind="text: totalRaisedToDate"></h3> - </div> - </div> - </div> - <div class="col-md-4 col-sm-4 col-lg-4"> - <div class="row factbox factbox-red"> - <div class="col-md-3"> - <div class="factbox-icon"> - <i class='fa fa-calculator'></i> - </div> - </div> - <div class="col-md-9"> - <p class='factbox-header'>Remaining To Raise</p> - <h3 data-bind="text: totalRemainingToDate"></h3> - </div> - </div> - </div> - </div> - </div> - </div> -</div> - <x-by-y-chart></x-by-y-chart> <totals-earned-chart params="title: 'Donation Amounts by Day in December', dailyCountArray: dailyCountArray, dailyDataArray: dailyDataArray, dayObj: dayObj, dataChanged: dataChanged"></totals-earned-chart> diff --git a/src/components/boards/generic-board/generic-board.html b/src/components/boards/generic-board/generic-board.html new file mode 100644 index 0000000..4a18bd9 --- /dev/null +++ b/src/components/boards/generic-board/generic-board.html @@ -0,0 +1,41 @@ +<div class="col-md-12"> + + <div class="row"> + <div class="col-md-4 titleCol"> + <h2 style="display:inline" data-bind="text: boardName"></h2> + <p data-bind="text: displayDate"></p> + </div> + <div class="col-md-8 titleCol"> + <div class="btn-group btn-group-xs pull-right"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="modal" data-target="#boardSQLModal"><i class="fa fa-database"></i></button> + <button type="button" class="btn btn-default" data-bind="click: reloadBoard"><i class="fa fa-refresh"></i></button> + </div> + </div> + </div> + + <span data-bind="if: dataLoading"> + <div class="loading"> + <img src="/images/catloader.gif" /> + <div>Loading Dash<span class="ellipsis" data-bind="text: ellipsis"></span></div> + </div> + </span> + + <div class="row" data-bind="foreach: widgetsToPlace"> + <div data-bind="component: { name: code, params: 'hiii' }"><span data-bind="text: display_name"></span></div> + </div> + + <div class="modal fade" id="boardSQLModal"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> + <h4><span data-bind="text: boardName"></span> SQL:</h4> + </div> + <div class="modal-body"> + <p data-bind="text: boardSQL"></p> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> + </div><!-- /.modal --> + +</div> \ No newline at end of file diff --git a/src/components/boards/generic-board/generic-board.js b/src/components/boards/generic-board/generic-board.js new file mode 100644 index 0000000..4659df3 --- /dev/null +++ b/src/components/boards/generic-board/generic-board.js @@ -0,0 +1,104 @@ +define( [ + 'knockout', + 'text!components/boards/generic-board/generic-board.html', + 'momentjs', + 'numeraljs' +], function( ko, template, moment, numeral ){ + + + function GenericBoardViewModel( params ){ + + var self = this, + timeFormat = 'dddd, MMMM Do YYYY, h:mm:ss a'; + + console.log('params: ', params); + + self.boardName = ko.observable('Default Board'); + self.widgets = params.widgets(); + self.widgetsOnThisBoard = params.userWidgets(); + self.boardSQL = ko.observable('Board SQL not available yet!'); + + //make this false until data loading has been written + self.dataLoading = ko.observable(false); + + // Get the date + self.displayDate = ko.observable( moment().format( timeFormat ) ); + + // Allows components in the board to subscribe to a single property + // and get notified of any changes to the available data. + self.dataChanged = ko.computed(function() { + + }); + + //figure out which widgets to place in the board + self.widgetsToPlace = ko.observableArray(); + $.each(self.widgets, function(n, widget){ + if(self.widgetsOnThisBoard.indexOf(widget.id) >= 0){ + self.widgetsToPlace.push(widget); + } + }); + + //todo: this could go elsewhere + self.ellipsis = ko.observable(''); + self.ellipsisObj = { + 'value' : ['', '.', '..', '...', '....'], + 'count' : 0, + 'run' : false, + 'timer' : null, + 'element' : '.ellipsis', + 'start' : function () { + var t = this; + this.run = true; + this.timer = setInterval(function () { + if (t.run) { + self.ellipsis(t.value[t.count % t.value.length]); + t.count++; + } + }, 400); + }, + 'stop' : function () { + this.run = false; + clearInterval(this.timer); + this.count = 0; + } + }; + self.ellipsisObj.start(); + + // Only recalculate child boards once per half second + self.dataChanged.extend( { rateLimit: 500 } ); + + self.loadData = function ( data, timestamp ) { + + }; + + self.widgetize = function(name){ + //trim the string + //capitalize letters after spaces + //remove spaces + } + + // Reload the data. For the automatic reload, we're fine getting + // something from the cache. + self.reloadBoard = function( automatic ){ + // self.dataLoading(true); + // var url = '/data/' + self.widgetize(self.boardName()); + // if ( automatic !== true ) { + // url += '/?cache=false'; + // } + // $.get( url , function ( dataget ) { + // self.loadData( dataget.results, dataget.timestamp ); + // self.dataLoading(false); + // }); + // // Do it every 5 minutes as well + // setTimeout( function () { + // self.reloadBoard( true ); + // }, 300000 ); + console.log('the board was reloaded.'); + }; + + self.reloadBoard( true ); + } + + return { viewModel: GenericBoardViewModel, template: template }; + +}); diff --git a/src/components/nav-bar/nav-bar.html b/src/components/nav-bar/nav-bar.html index 1c2bcc9..d560cc6 100644 --- a/src/components/nav-bar/nav-bar.html +++ b/src/components/nav-bar/nav-bar.html @@ -27,7 +27,7 @@ <div class="hide subNavBoardOpts subNavButton" id="profileLinks"> <ul> <li><a href="/logout">Log out</a></li> - <li><a href="#">Profile</a></li> + <li><a href="/profile">Profile</a></li> </ul> </div> </span> @@ -44,9 +44,6 @@ </div> <div class="mainNavButton"><i class="fa fa-plug"></i><span> Library</span> - </div> - - <div class="mainNavButton"><i class="fa fa-calculator"></i><span> Reports</span> </div> </span> diff --git a/src/components/nav-bar/nav-bar.js b/src/components/nav-bar/nav-bar.js index d0612c1..95ce585 100644 --- a/src/components/nav-bar/nav-bar.js +++ b/src/components/nav-bar/nav-bar.js @@ -14,7 +14,7 @@ //make the nav menu fold out of view. $('#navContainer .navWrapper').toggleClass('hide'); $('#showNavMenu').css('display', 'inline'); - $('#dashApp').css('padding', '0 0 0 80px'); + $('#dashApp').css('padding', '0 0 0 10px'); }; self.showNav = function(){ diff --git a/src/components/widgets/totals-earned-chart/totals-earned-chart.html b/src/components/widgets/totals-earned-chart/totals-earned-chart.html index 6afc0ff..3ea4b2b 100644 --- a/src/components/widgets/totals-earned-chart/totals-earned-chart.html +++ b/src/components/widgets/totals-earned-chart/totals-earned-chart.html @@ -1,4 +1,53 @@ <div class="row"> + <div class="panel panel-transparent"> + <div class="panel-body"> + <!--Main updates: Goal, Total so far, Remaining to raise--> + <div class="row-fluid bigEnglish-updates"> + <div class="col-md-4 col-sm-4 col-lg-4"> + <div class="row factbox factbox-blue"> + <div class="col-md-3"> + <div class="factbox-icon"> + <i class='fa fa-soccer-ball-o'></i> + </div> + </div> + <div class="col-md-9"> + <p class='factbox-header'>2014 Big English Goal</p> + <h3 data-bind="text: bigEnglishGoal"></h3> + </div> + </div> + </div> + <div class="col-md-4 col-sm-4 col-lg-4"> + <div class="row factbox factbox-yellow"> + <div class="col-md-3"> + <div class="factbox-icon"> + <i class='fa fa-gift'></i> + </div> + </div> + <div class="col-md-9"> + <p class='factbox-header'>Total To Date</p> + <h3 data-bind="text: totalRaisedToDate"></h3> + </div> + </div> + </div> + <div class="col-md-4 col-sm-4 col-lg-4"> + <div class="row factbox factbox-red"> + <div class="col-md-3"> + <div class="factbox-icon"> + <i class='fa fa-calculator'></i> + </div> + </div> + <div class="col-md-9"> + <p class='factbox-header'>Remaining To Raise</p> + <h3 data-bind="text: totalRemainingToDate"></h3> + </div> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="row"> <div class="panel panel-purple"> <div class="panel-heading"> <p data-bind="text: title"></p> @@ -8,4 +57,27 @@ <div id='totalsEarnedChart'></div> </div> </div> -</div> \ No newline at end of file +</div> + +<div class="modal fade" id="BEsettingsModal"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> + <h4 class="modal-title">Options</h4> + </div> + <div class="modal-body"> + <label>Change Big English goal</label> + <div class="input-group"> + <span class="input-group-addon">$</span> + <input type="text" class="form-control" data-bind="textInput: goal"> + <span class="input-group-addon">.00</span> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-success pull-right" data-dismiss="modal">Submit</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> \ No newline at end of file diff --git a/src/components/widgets/x-by-y-chart/x-by-y-chart.html b/src/components/widgets/x-by-y/x-by-y.html similarity index 100% rename from src/components/widgets/x-by-y-chart/x-by-y-chart.html rename to src/components/widgets/x-by-y/x-by-y.html diff --git a/src/components/widgets/x-by-y-chart/x-by-y-chart.js b/src/components/widgets/x-by-y/x-by-y.js similarity index 98% rename from src/components/widgets/x-by-y-chart/x-by-y-chart.js rename to src/components/widgets/x-by-y/x-by-y.js index a6602f3..257c24a 100644 --- a/src/components/widgets/x-by-y-chart/x-by-y-chart.js +++ b/src/components/widgets/x-by-y/x-by-y.js @@ -1,6 +1,6 @@ define( [ 'knockout', - 'text!components/widgets/x-by-y-chart/x-by-y-chart.html', + 'text!components/widgets/x-by-y/x-by-y.html', 'momentjs', 'numeraljs', 'chartjs', diff --git a/src/css/style.css b/src/css/style.css index 18b6d94..83cb3ea 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -11,7 +11,7 @@ } .container-fluid { - padding: 15px 65px; + padding: 15px 85px; } #dashApp { @@ -69,6 +69,10 @@ margin-right: 8px; } +.mainNavButton:hover { + cursor: pointer; +} + .sidebar-nav a { color: #f5f5f5; } -- To view, visit https://gerrit.wikimedia.org/r/187297 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0e09c65f7d2ea73dae261e20b337d07774a6a55e Gerrit-PatchSet: 1 Gerrit-Project: wikimedia/fundraising/dash Gerrit-Branch: master Gerrit-Owner: Ssmith <ssm...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits