<commit_before>// my script now
(function($) {
    $.fn.db = new Array();
    $.fn.hearbeatTime = 5000;
    $.fn.angle = 9;
    $.fn.twrequest = 'rpp=50&q=%23nantes';
    $.fn.hashtag = '#nantes';
    $.fn.log = function(msg) {
        if (console) {
            console.log(msg);
        }
    };
    $.fn.feedTheDB = function()
    {
        $.ajax({
            url: ($.fn.feedTheDB.lastcall.refresh_url ? "https://search.twitter.com/search.json" + $().feedTheDB.lastcall.refresh_url: "https://search.twitter.com/search.json?" + $().twrequest),
            dataType: "jsonp",
            success: function(result) {
                for (i in result.results) {
                    var r = result.results[i];
                    r.played = 0;
                    $().db.push(r);
                }
                $.fn.feedTheDB.lastcall = result;
                $().log($.fn.feedTheDB.lastcall.refresh_url);
                $().log(result);
            }
        });
        $().log("another feed");
    };
    $.fn.feedTheDB.lastcall = {};

    $.fn.feedTheDB.sortfunction = function(a, b) {
        var playcom = (a.played - b.played);
        if (playcom == 0) {
            var playcom = (new Date(b.created_at)).getTime() - (new Date(a.created_at)).getTime();
        }
        return playcom;
        //causes an array to be sorted numerically and ascending
    };
    $.fn.sortDB = function() {
        $.fn.db.sort($.fn.feedTheDB.sortfunction);
        if ($.fn.db.length > 200) {
            $.fn.db = $.fn.db.slice(0, 200);
        }
    }

})(jQuery);

function hearbeat() {
    if ($().db.length < 1) {
        return false;
    }
    $().sortDB();

    jQuery('body').append('

');
    var domelem = jQuery('div.tweet:last');
    var elem = $().db[0];
    domelem.append('');
    domelem.append('' + elem.from_user + '');
    domelem.append('');
    domelem.append('
' + elem.text.linkify().tagify() + '
');
    domelem.updateTimeField();
    elem.played++;

    domelem.css('top', '-200px');
    domelem.css('left', $().getViewport().width - 400);
    domelem.animate({
        left: $().getViewport().width - 680,
        top: $().getViewport().height / 2
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = fx.now / fx.end;
            if (!isNaN(where_we_are)) {
                var deg = where_we_are * $().angle;
                $this = $(this);
                $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                $this.css("transform", 'rotate(' + deg + 'deg)');
            }
        },
        complete: function() {
            $this.animate({
                top: '+=40'
            },
            {
                specialEasing: {
                    top: 'easeOutQuad'
                },
                duration: $().hearbeatTime * 0.75
            });
        },
        specialEasing: {
            top: 'easeOutQuad'
        }
    }
    );
    window.setTimeout(followupannimation.bind(domelem), $().hearbeatTime);
}

function followupannimation2() {
    if (parseFloat(this.css('top')) < -200) {
        this.remove();
    } else {
        this.animate({
            left: 10,
            top: parseFloat(this.css('top')) - 100
        },
        $().hearbeatTime * 0.25);
        window.setTimeout(followupannimation2.bind(this), $().hearbeatTime);
    }
}
function followupannimation() {
    $this = $(this);

    $this.animate({
        left: 10,
        borderBottomColor: '#ffffff',
        borderTopColor: '#ffffff',
        borderRightColor: '#ffffff',
        borderLeftColor: '#ffffff',
        backgroundColor: '#eeeeee',
        top: $().getViewport().height - 120
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = Math.abs(fx.now / (fx.end - fx.start));
            if (!isNaN(where_we_are)) {

                if (fx.prop == 'left') {

                    //   $().log(fx);
                    var deg = where_we_are * $().angle;
                    $this = $(this);
                    $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                    $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                    $this.css("transform", 'rotate(' + deg + 'deg)');
                }
            }
        },
        specialEasing: {
            top: 'easeInQuad'
        }
    });
    window.setTimeout(followupannimation2.bind($this), $().hearbeatTime);
}

function areWeUp() {
    $.ajax({
        url: 'howweare.status',
        success: function(result) {
            if (result == "1") {
                hearbeat();
                $('#soon').animate({
                    opacity: 0
                },
                {
                    duration: 1000,
                    complete: function() {
                        $(this).remove()
                    }
                });
                var elemens = $('.reveal');
                elemens.css('display', 'block');
                elemens.animate({
                    opacity: 1
                },
                {
                    duration: 1000
                });
                hearbeat();
                window.setInterval(hearbeat, $().hearbeatTime);
            } else {
                window.setTimeout(areWeUp, 2000);

            }
        }
    });
}

$(function() {

    $().feedTheDB();
    areWeUp();

    //    testpouris();
    window.setInterval($().feedTheDB, 120000);
});

<commit_msg>tw search is good<commit_after>// my script now
(function($) {
    $.fn.db = new Array();
    $.fn.hearbeatTime = 5000;
    $.fn.angle = 9;
    $.fn.twrequest = 'rpp=80&q=from%3Aouestnumerique+OR+%23ouestnumeric+OR+%23ouestnumerique';
    $.fn.hashtag = '#nantes';
    $.fn.log = function(msg) {
        if (console) {
            console.log(msg);
        }
    };
    $.fn.feedTheDB = function()
    {
        $.ajax({
            url: ($.fn.feedTheDB.lastcall.refresh_url ? "https://search.twitter.com/search.json" + $().feedTheDB.lastcall.refresh_url: "https://search.twitter.com/search.json?" + $().twrequest),
            dataType: "jsonp",
            success: function(result) {
                for (i in result.results) {
                    var r = result.results[i];
                    r.played = 0;
                    $().db.push(r);
                }
                $.fn.feedTheDB.lastcall = result;
                $().log($.fn.feedTheDB.lastcall.refresh_url);
                $().log(result);
            }
        });
        $().log("another feed");
    };
    $.fn.feedTheDB.lastcall = {};

    $.fn.feedTheDB.sortfunction = function(a, b) {
        var playcom = (a.played - b.played);
        if (playcom == 0) {
            var playcom = (new Date(b.created_at)).getTime() - (new Date(a.created_at)).getTime();
        }
        return playcom;
        //causes an array to be sorted numerically and ascending
    };
    $.fn.sortDB = function() {
        $.fn.db.sort($.fn.feedTheDB.sortfunction);
        if ($.fn.db.length > 200) {
            $.fn.db = $.fn.db.slice(0, 200);
        }
    }

})(jQuery);

function hearbeat() {
    if ($().db.length < 1) {
        return false;
    }
    $().sortDB();

    jQuery('body').append('

');
    var domelem = jQuery('div.tweet:last');
    var elem = $().db[0];
    domelem.append('');
    domelem.append('' + elem.from_user + '');
    domelem.append('');
    domelem.append('
' + elem.text.linkify().tagify() + '
');
    domelem.updateTimeField();
    elem.played++;

    domelem.css('top', '-200px');
    domelem.css('left', $().getViewport().width - 400);
    domelem.animate({
        left: $().getViewport().width - 680,
        top: $().getViewport().height / 2
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = fx.now / fx.end;
            if (!isNaN(where_we_are)) {
                var deg = where_we_are * $().angle;
                $this = $(this);
                $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                $this.css("transform", 'rotate(' + deg + 'deg)');
            }
        },
        complete: function() {
            $this.animate({
                top: '+=40'
            },
            {
                specialEasing: {
                    top: 'easeOutQuad'
                },
                duration: $().hearbeatTime * 0.75
            });
        },
        specialEasing: {
            top: 'easeOutQuad'
        }
    }
    );
    window.setTimeout(followupannimation.bind(domelem), $().hearbeatTime);
}

function followupannimation2() {
    if (parseFloat(this.css('top')) < -200) {
        this.remove();
    } else {
        this.animate({
            left: 10,
            top: parseFloat(this.css('top')) - 100
        },
        $().hearbeatTime * 0.25);
        window.setTimeout(followupannimation2.bind(this), $().hearbeatTime);
    }
}
function followupannimation() {
    $this = $(this);

    $this.animate({
        left: 10,
        borderBottomColor: '#ffffff',
        borderTopColor: '#ffffff',
        borderRightColor: '#ffffff',
        borderLeftColor: '#ffffff',
        backgroundColor: '#eeeeee',
        top: $().getViewport().height - 120
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = Math.abs(fx.now / (fx.end - fx.start));
            if (!isNaN(where_we_are)) {

                if (fx.prop == 'left') {

                    //   $().log(fx);
                    var deg = where_we_are * $().angle;
                    $this = $(this);
                    $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                    $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                    $this.css("transform", 'rotate(' + deg + 'deg)');
                }
            }
        },
        specialEasing: {
            top: 'easeInQuad'
        }
    });
    window.setTimeout(followupannimation2.bind($this), $().hearbeatTime);
}

function areWeUp() {
    $.ajax({
        url: 'howweare.status',
        success: function(result) {
            if (result == "1") {
                hearbeat();
                $('#soon').animate({
                    opacity: 0
                },
                {
                    duration: 1000,
                    complete: function() {
                        $(this).remove()
                    }
                });
                var elemens = $('.reveal');
                elemens.css('display', 'block');
                elemens.animate({
                    opacity: 1
                },
                {
                    duration: 1000
                });
                hearbeat();
                window.setInterval(hearbeat, $().hearbeatTime);
            } else {
                window.setTimeout(areWeUp, 2000);

            }
        }
    });
}

$(function() {

    $().feedTheDB();
    areWeUp();

    //    testpouris();
    window.setInterval($().feedTheDB, 120000);
});

<|endoftext|>


<commit_before>var showentry=function(term){
	var str = JSON.stringify(term,"","");
	return "
"+term.entry+"
"+term.page+"

";
}

var doentrySearch=function(tofind){
	var arr=entrySearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var doabbSearch=function(tofind){
	var arr=abbSearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var showdetails=function(tofind){
	//var arr=entrySearch(tofind.replace(/\(\d+.\d+\)/,""));
	document.getElementById("display2").innerHTML=drawtable(tofind);

	var table = document.getElementById("details");
	var tds = table.getElementsByTagName("td");
	tds[0].innerHTML = tofind.page; tds[1].innerHTML = tofind.entry;
}

var drawtable = function(obj){

    var tablestart = "
";
    var thstart = "";
    var thend = "	";
    var tableend = "
";
    var trstart = "
";
    var trend = "
";
    var tdstart = "";
    var tdend = "	";
    var data = " ";//non-breaking-space (讓td tag有東西，但顯示出的是空格;td tag沒東西的話，格子會不存在，排版會亂掉)
    var tablehead = "
" + thstart + "頁碼" + thend + thstart + "詞條" + thend + thstart + "藏文解釋" + thend
    					   + thstart + "中文解釋" + thend + thstart + "略語1" + thend + thstart + "略語2" + thend
    					   + thstart + "略語3" + thend + thstart + "同義詞1" + thend + thstart + "同義詞2" + thend
    					   + thstart + "同義詞3" + thend + thstart + "註記" + thend + "
";

	var tablecontent = tablestart + tablehead;

	for (var i = 0; i < obj.tdefinitions.length; i++){
		for(var j = 0; j < obj.tdefinitions[i].cdefinitions.length; j++){
			var abb1 = obj.tdefinitions[i].cdefinitions[j].abbreviations[0];
			var abb2 = obj.tdefinitions[i].cdefinitions[j].abbreviations[1];
			var abb3 = obj.tdefinitions[i].cdefinitions[j].abbreviations[2];
			var syn1 = obj.tdefinitions[i].cdefinitions[j].synonyms[0];
			var syn2 = obj.tdefinitions[i].cdefinitions[j].synonyms[1];
			var syn3 = obj.tdefinitions[i].cdefinitions[j].synonyms[2];
		tablecontent += "
" + tdstart + " " + tdend + tdstart + " " + tdend + tdstart + obj.tdefinitions[i].tdef + tdend
							   + tdstart + obj.tdefinitions[i].cdefinitions[j].cdef + tdend + tdstart + abb1 + tdend
							   + tdstart + abb2 + tdend + tdstart + abb3 + tdend + tdstart + syn1 + tdend
							   + tdstart + syn2 + tdend + tdstart + syn3 + tdend + tdstart + " " + tdend + "
";
		}
    }
    return tablecontent + tableend + "<button onClick='edit()'>Edit</button>";
}

/*var addRow=function(){
	var table = document.getElementById("edited_details");
    var cells=table.getElementsByTagName("tr")
    console.log(cells[0].innerHTML);
    var row = table.insertRow(cells.length);
    var cell1 = row.insertCell(0);
    var cell2 = row.insertCell(1);
//    cell1.innerHTML = "<input></input>";
//    cell2.innerHTML = "<input></input>";
} */

var cancel=function(){
	document.getElementById("display2").innerHTML=localStorage.undo;
}

var edit=function(){
	var table=document.getElementById("details").innerHTML;
	var edittable="<button onClick='addRow()'>Add Row</button>"+"<button onClick='save_edit()'>Save</button>"+"<button onClick='cancel()'>Cancel</button>"
					+"
"+table.replace(//g,"");
	document.getElementById("display2").innerHTML=edittable;
}

var save_edit=function(){
	var table=document.getElementById("edited_details").innerHTML;

	var savetable="<button onClick='edit()'>Edit</button>"+"
"+
					table.replace(//g,"");
	localStorage.undo=savetable;
	document.getElementById("display2").innerHTML=savetable;
}	<commit_msg>rm non-breaking-space<commit_after>var showentry=function(term){
	var str = JSON.stringify(term,"","");
	return "
"+term.entry+"
"+term.page+"

";
}

var doentrySearch=function(tofind){
	var arr=entrySearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var doabbSearch=function(tofind){
	var arr=abbSearch(tofind);
	document.getElementById("display1").innerHTML=arr.map(showentry).join("
");
}

var showdetails=function(tofind){
	//var arr=entrySearch(tofind.replace(/\(\d+.\d+\)/,""));
	document.getElementById("display2").innerHTML=drawtable(tofind);

	var table = document.getElementById("details");
	var tds = table.getElementsByTagName("td");
	tds[0].innerHTML = tofind.page; tds[1].innerHTML = tofind.entry;
}

var drawtable = function(obj){

    var tablestart = "
";
    var thstart = "";
    var thend = "	";
    var tableend = "
";
    var trstart = "
";
    var trend = "
";
    var tdstart = "";
    var tdend = "	";
    var data = "";//non-breaking-space (讓td tag有東西，但顯示出的是空格;td tag沒東西的話，格子會不存在，排版會亂掉)
    var tablehead = "
" + thstart + "頁碼" + thend + thstart + "詞條" + thend + thstart + "藏文解釋" + thend
    					   + thstart + "中文解釋" + thend + thstart + "略語1" + thend + thstart + "略語2" + thend
    					   + thstart + "略語3" + thend + thstart + "同義詞1" + thend + thstart + "同義詞2" + thend
    					   + thstart + "同義詞3" + thend + thstart + "註記" + thend + "
";

	var tablecontent = tablestart + tablehead;

	for (var i = 0; i < obj.tdefinitions.length; i++){
		for(var j = 0; j < obj.tdefinitions[i].cdefinitions.length; j++){
			var abb1 = obj.tdefinitions[i].cdefinitions[j].abbreviations[0];
			var abb2 = obj.tdefinitions[i].cdefinitions[j].abbreviations[1];
			var abb3 = obj.tdefinitions[i].cdefinitions[j].abbreviations[2];
			var syn1 = obj.tdefinitions[i].cdefinitions[j].synonyms[0];
			var syn2 = obj.tdefinitions[i].cdefinitions[j].synonyms[1];
			var syn3 = obj.tdefinitions[i].cdefinitions[j].synonyms[2];
		tablecontent += "
" + tdstart + data + tdend + tdstart + data + tdend + tdstart + obj.tdefinitions[i].tdef + tdend
							   + tdstart + obj.tdefinitions[i].cdefinitions[j].cdef + tdend + tdstart + abb1 + tdend
							   + tdstart + abb2 + tdend + tdstart + abb3 + tdend + tdstart + syn1 + tdend
							   + tdstart + syn2 + tdend + tdstart + syn3 + tdend + tdstart
							   + obj.tdefinitions[i].cdefinitions[j].note + tdend + "
";
		}
    }
    return tablecontent + tableend + "<button onClick='edit()'>Edit</button>";
}

/*var addRow=function(){
	var table = document.getElementById("edited_details");
    var cells=table.getElementsByTagName("tr")
    console.log(cells[0].innerHTML);
    var row = table.insertRow(cells.length);
    var cell1 = row.insertCell(0);
    var cell2 = row.insertCell(1);
//    cell1.innerHTML = "<input></input>";
//    cell2.innerHTML = "<input></input>";
} */

var cancel=function(){
	document.getElementById("display2").innerHTML=localStorage.undo;
}

var edit=function(){
	var table=document.getElementById("details").innerHTML;
	var edittable="<button onClick='addRow()'>Add Row</button>"+"<button onClick='save_edit()'>Save</button>"+"<button onClick='cancel()'>Cancel</button>"
					+"
"+table.replace(//g,"");
	document.getElementById("display2").innerHTML=edittable;
}

var save_edit=function(){
	var table=document.getElementById("edited_details").innerHTML;

	var savetable="<button onClick='edit()'>Edit</button>"+"
"+
					table.replace(//g,"");
	localStorage.undo=savetable;
	document.getElementById("display2").innerHTML=savetable;
}	<|endoftext|>


<commit_before>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    layout: {
        type: 'fit'
    },

    launch: function() {

        this._loadBuildDefs();

        /*  // Creates a table using Rally ui
            Rally.data.ModelFactory.getModel({
                    type:'Build Definition',
                    scope:this,
                    success: function(model){

                        var myGrid = Ext.create('Rally.ui.grid.Grid',{
                            model: model,
                            columnCfgs: [
                                'Name',
                                'Description',
                                'LastStatus'
                                ]
                        });
                        this.add(myGrid);

                    },
                    context: {
                        workspace: "/workspace/4365660833"
                    }

                });
        */

    },

    // Creates a query for specific build definitions
    _createQuery: function(buildDefRecords) {

        // get first entry
        var q = Ext.create('Rally.data.QueryFilter', {
            property: 'BuildDefinition',
            operator: '=',
            value: buildDefRecords[0].get('_ref')
            //            value: '/slm/webservice/1.37/builddefinition/6035424766' //PacSystems Mainline Build Definition
        });

        // remove teh first entry
        Ext.Array.remove(buildDefRecords, buildDefRecords[0]);

        // cycle through the remaineder in the array
        Ext.Array.forEach(buildDefRecords, function(item, index, allItems) {
            q = q.or(Ext.create('Rally.data.QueryFilter', {
                property: 'BuildDefinition',
                operator: '=',
                value: item.get('_ref')
            }));
        });

        console.log("query = ", q.toString());

        return q;

    },

    _getBuilds: function(buildDefRecords) {
        var query = this._createQuery(buildDefRecords);

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Fetched %d builds", records.length);
                    Ext.Array.forEach(records, function(item) {
                        //                        console.log("Name: %s, Def: %s, Status %s", item.get("Number"), item.get("BuildDefinition")._ref, item.get("Status"));
                    });
                    this._siftBuilds(records);
                },
                scope: this
            },
            sorters: [{
                property: 'CreationDate',
                direction: 'DESC'
            }],
            filters: query,
            autoLoad: true,
            pageSize: 100
        });
    },

    _loadBuildDefs: function() {

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build Definition',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Loaded %d Build Definitions.", records.length);

                    this.buildDefinitions = [];
                    Ext.Array.forEach(records, function(item) {
                        Ext.Array.push(this.buildDefinitions, item.get("_ref"));

                    }, this);
                    console.log("Build definitions array ", this.buildDefinitions);

                    this._getBuilds(records);
                },
                scope: this
            },
            autoLoad: true
        });

    },

    // creates the build def/ build record data struct
    _siftBuilds: function(buildDefBuildRecords) {

        var buildStructure = {};

        // Create a build structure
        Ext.Array.forEach(buildDefBuildRecords, function(item) {
            build = item;
            buildDef = item.get("BuildDefinition")._ref;
            //console.log(item.get("BuildDefinition"));

            if (!buildStructure.hasOwnProperty(buildDef)) {
                buildStructure[buildDef] = {
                    buildDefName: item.get("BuildDefinition")._refObjectName,
                    builds: [build],
                    lastBuild: null,
                    failCount: 0
                };
                //                console.log("Added new build def %s",buildDef);

            }
            else {
                Ext.Array.push(buildStructure[buildDef].builds, build);
                //                console.log("Pushed build  %s",item.get("Number"));
            }

        });

        //Now update the lastGoodBuild and failCount fields

        // for each build ref
        //    for each build
        //      if build failed
        //          increment failCount
        //      else
        //          set lastGoodBuild
        //          break;
        Ext.Array.forEach(this.buildDefinitions, function(item) {

            var buildDef = item;
            buildStructure[buildDef].failCount = 0;

            //            console.log("Working on %s",buildDef);

            Ext.Array.forEach(buildStructure[item].builds, function(item) {

                var build = item;

                if (build.get("Status") === "FAILURE") {
                    if (buildStructure[buildDef].lastGoodBuild == undefined) {
                        buildStructure[buildDef].failCount = buildStructure[buildDef].failCount + 1;
                        //                        console.log("%s failed, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    }
                    else {
                        return;
                    }
                }
                else {
                    //                    console.log("%s succeeded, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    buildStructure[buildDef].lastGoodBuild = build;
                    return;
                }

            });

            console.log("Build %s Fails %d", buildDef, buildStructure[buildDef].failCount);

        });
        console.log(buildStructure);

        gridFormattedBuilds = [];
        var count = 0;
        //format data into a new grid-freindly array
        Ext.Array.forEach(this.buildDefinitions, function(item) {
            var buildDef = item;

            gridFormattedBuilds[count] = {};
            gridFormattedBuilds[count].Name = buildStructure[buildDef].buildDefName; //i.e : "PACSystems Mainline CI Builds"

            //todo: make sure a build exists
            gridFormattedBuilds[count].Status = buildStructure[buildDef].builds[0].get("Status");
            gridFormattedBuilds[count].CurrentBuild = buildStructure[buildDef].builds[0].get("Number");
            gridFormattedBuilds[count].LastGoodBuild = buildStructure[buildDef].lastGoodBuild.get("Number");
            gridFormattedBuilds[count].NumFailedBuilds = buildStructure[buildDef].failCount;

            //field for build refs
            gridFormattedBuilds[count].CurrentBuildRef = buildStructure[buildDef].builds[0].get('_ref');
            gridFormattedBuilds[count].LastGoodBuildRef = buildStructure[buildDef].lastGoodBuild.get('_ref');

            count++;
        });
        console.log("Grid Array:");
        console.log(gridFormattedBuilds);

        //pipe it into a store
        Ext.create('Ext.data.Store', {
            storeId: 'ciBuildStore',
            fields: ['Name', 'Status', 'CurrentBuild', 'LastGoodBuild', 'NumFailedBuilds'],
            data: gridFormattedBuilds

        });

        // Color
        var statusTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {Status};
",
                "<tpl default>",
                    "
 {Status};
",
            "</tpl>");
        var currentBuildTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {CurrentBuild}
",
                "<tpl default>",
                    "
 {CurrentBuild}
",
            "</tpl>");

        var lastGoodBuildTpl = new Ext.XTemplate(
            "<tpl>",
                    "
 {LastGoodBuild}
",
            "</tpl>");

        //{
        //    text: 'Verdict', dataIndex: 'Verdict', width: 95,
        //    renderer: function(value){
        //        if((value === "Fail") || (value === "Error") || (value === "Blocked")){
        //            return Ext.String.format("
{0}
", value);
        //        } else if ( value === "Inconclusive" ) {
        //            return Ext.String.format("
{0}
", value);
        //        }else{
        //            return Ext.String.format("
{0}
", value);
        //        }
        //    }
        //}

        var myGrid = Ext.create('Ext.grid.Panel', {
//            title: 'Build Status',
            store: Ext.data.StoreManager.lookup('ciBuildStore'),
            columns: [
                { text: 'Name', dataIndex: 'Name', width: 205 },
//                { text: 'Status', dataIndex: 'Status', flex: 1, xtype: 'templatecolumn', tpl: statusTpl},
                { text: 'Current Build', dataIndex: 'CurrentBuild', width: 175, xtype: 'templatecolumn', tpl: currentBuildTpl},
                { text: 'Last Good Build', dataIndex: 'LastGoodBuild', width: 175, xtype: 'templatecolumn', tpl: lastGoodBuildTpl },
                { text: 'Failed Builds', dataIndex: 'NumFailedBuilds', width: 50, tooltip: 'Number of failed builds since the last success', tooltipType: "qtip"},
                { menuDisabled: true, sortable: false, xtype: 'actioncolumn',items: [{
                    icon: 'https://raw.github.com/skandl/BuildActionBoard/master/button_got_it.jpg',
                    iconCls: 'gotItButton',
                    tooltip: 'I got it',
                    handler: function(grid, rowIndex, colIndex) {
                        console.log("Selected row %d", rowIndex);
                    }}],
                },
                {text: ' Savior', dataIndex: 'Owner', flex: 1}
            ],
            listeners: {
                cellclick: function(table, td, cellIndex, record, tr, rowIndex){
                    // cellIndex 1 is current build
                    //todo qualify index into array
                    if (cellIndex === 1)
                    {
                        console.log(gridFormattedBuilds[rowIndex].CurrentBuildRef);
    		Rally.environment.getMessageBus().publish('buildSelected', gridFormattedBuilds[rowIndex].CurrentBuildRef);

                    }

                    if (cellIndex === 2)
                    {
                        console.log(gridFormattedBuilds[rowIndex].CurrentBuildRef);
                        console.log(gridFormattedBuilds[rowIndex].LastGoodBuildRef);
                        Rally.environment.getMessageBus().publish('buildSelected', gridFormattedBuilds[rowIndex].LastGoodBuildRef);
                    }
                    console.log("cell click %d %d",cellIndex, rowIndex);

                }
            },
            height: 200
            //            plugins: [{
            //                ptype: 'rowexpander',
            //                rowBodyTpl: new Ext.XTemplate('foo')
            //            }],
            //            collapsible: true,
            //            animCollapse: false
        });

        this.add(myGrid);

    }

});
<commit_msg>adds Motion hax<commit_after>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    layout: {
        type: 'fit'
    },

    launch: function() {

        this._loadBuildDefs();

        /*  // Creates a table using Rally ui
            Rally.data.ModelFactory.getModel({
                    type:'Build Definition',
                    scope:this,
                    success: function(model){

                        var myGrid = Ext.create('Rally.ui.grid.Grid',{
                            model: model,
                            columnCfgs: [
                                'Name',
                                'Description',
                                'LastStatus'
                                ]
                        });
                        this.add(myGrid);

                    },
                    context: {
                        workspace: "/workspace/4365660833"
                    }

                });
        */

    },

    // Creates a query for specific build definitions
    _createQuery: function(buildDefRecords) {

        // get first entry
        var q = Ext.create('Rally.data.QueryFilter', {
            property: 'BuildDefinition',
            operator: '=',
            value: buildDefRecords[0].get('_ref')
            //            value: '/slm/webservice/1.37/builddefinition/6035424766' //PacSystems Mainline Build Definition
        });

        // remove teh first entry
        Ext.Array.remove(buildDefRecords, buildDefRecords[0]);

        // cycle through the remaineder in the array
        Ext.Array.forEach(buildDefRecords, function(item, index, allItems) {
            q = q.or(Ext.create('Rally.data.QueryFilter', {
                property: 'BuildDefinition',
                operator: '=',
                value: item.get('_ref')
            }));
        });

        console.log("query = ", q.toString());

        return q;

    },

    _getBuilds: function(buildDefRecords) {
        var query = this._createQuery(buildDefRecords);

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Fetched %d builds", records.length);
                    Ext.Array.forEach(records, function(item) {
                        //                        console.log("Name: %s, Def: %s, Status %s", item.get("Number"), item.get("BuildDefinition")._ref, item.get("Status"));
                    });
                    this._siftBuilds(records);
                },
                scope: this
            },
            sorters: [{
                property: 'CreationDate',
                direction: 'DESC'
            }],
            filters: query,
            autoLoad: true,
            pageSize: 100
        });
    },

    _loadBuildDefs: function() {

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build Definition',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Loaded %d Build Definitions.", records.length);

                    this.buildDefinitions = [];
                    Ext.Array.forEach(records, function(item) {
                        Ext.Array.push(this.buildDefinitions, item.get("_ref"));

                    }, this);
                    console.log("Build definitions array ", this.buildDefinitions);

                    this._getBuilds(records);
                },
                scope: this
            },
            autoLoad: true
        });

    },

    // creates the build def/ build record data struct
    _siftBuilds: function(buildDefBuildRecords) {

        var buildStructure = {};

        // Create a build structure
        Ext.Array.forEach(buildDefBuildRecords, function(item) {
            build = item;
            buildDef = item.get("BuildDefinition")._ref;
            //console.log(item.get("BuildDefinition"));

            if (!buildStructure.hasOwnProperty(buildDef)) {
                buildStructure[buildDef] = {
                    buildDefName: item.get("BuildDefinition")._refObjectName,
                    builds: [build],
                    lastBuild: null,
                    failCount: 0
                };
                //                console.log("Added new build def %s",buildDef);

            }
            else {
                Ext.Array.push(buildStructure[buildDef].builds, build);
                //                console.log("Pushed build  %s",item.get("Number"));
            }

        });

        //Now update the lastGoodBuild and failCount fields

        // for each build ref
        //    for each build
        //      if build failed
        //          increment failCount
        //      else
        //          set lastGoodBuild
        //          break;
        Ext.Array.forEach(this.buildDefinitions, function(item) {

            var buildDef = item;
            buildStructure[buildDef].failCount = 0;

            //            console.log("Working on %s",buildDef);

            Ext.Array.forEach(buildStructure[item].builds, function(item) {

                var build = item;

                if (build.get("Status") === "FAILURE") {
                    if (buildStructure[buildDef].lastGoodBuild == undefined) {
                        buildStructure[buildDef].failCount = buildStructure[buildDef].failCount + 1;
                        //                        console.log("%s failed, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    }
                    else {
                        return;
                    }
                }
                else {
                    //                    console.log("%s succeeded, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    buildStructure[buildDef].lastGoodBuild = build;
                    return;
                }

            });

            console.log("Build %s Fails %d", buildDef, buildStructure[buildDef].failCount);

        });
        console.log(buildStructure);

        gridFormattedBuilds = [];
        var count = 0;
        //format data into a new grid-freindly array
        Ext.Array.forEach(this.buildDefinitions, function(item) {
            var buildDef = item;

            gridFormattedBuilds[count] = {};
            gridFormattedBuilds[count].Name = buildStructure[buildDef].buildDefName; //i.e : "PACSystems Mainline CI Builds"

            //todo: make sure a build exists
            gridFormattedBuilds[count].Status = buildStructure[buildDef].builds[0].get("Status");
            gridFormattedBuilds[count].CurrentBuild = buildStructure[buildDef].builds[0].get("Number");
            gridFormattedBuilds[count].LastGoodBuild = buildStructure[buildDef].lastGoodBuild.get("Number");
            gridFormattedBuilds[count].NumFailedBuilds = buildStructure[buildDef].failCount;

            //field for build refs
            gridFormattedBuilds[count].CurrentBuildRef = buildStructure[buildDef].builds[0].get('_ref');
            gridFormattedBuilds[count].LastGoodBuildRef = buildStructure[buildDef].lastGoodBuild.get('_ref');

            count++;
        });
        console.log("Grid Array:");
        console.log(gridFormattedBuilds);

        // Motion Hack - fix junked motion build ID's
        if (count >= 3)
        {
            gridFormattedBuilds[2].CurrentBuild = 'MOTION_CI_R59632_40E1';
            gridFormattedBuilds[2].LastGoodBuild = 'MOTION_CI_R59632_40E1';
        }

        //pipe it into a store
        Ext.create('Ext.data.Store', {
            storeId: 'ciBuildStore',
            fields: ['Name', 'Status', 'CurrentBuild', 'LastGoodBuild', 'NumFailedBuilds'],
            data: gridFormattedBuilds

        });

        // Color
        var statusTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {Status};
",
                "<tpl default>",
                    "
 {Status};
",
            "</tpl>");
        var currentBuildTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {CurrentBuild}
",
                "<tpl default>",
                    "
 {CurrentBuild}
",
            "</tpl>");

        var lastGoodBuildTpl = new Ext.XTemplate(
            "<tpl>",
                    "
 {LastGoodBuild}
",
            "</tpl>");

        //{
        //    text: 'Verdict', dataIndex: 'Verdict', width: 95,
        //    renderer: function(value){
        //        if((value === "Fail") || (value === "Error") || (value === "Blocked")){
        //            return Ext.String.format("
{0}
", value);
        //        } else if ( value === "Inconclusive" ) {
        //            return Ext.String.format("
{0}
", value);
        //        }else{
        //            return Ext.String.format("
{0}
", value);
        //        }
        //    }
        //}

        var myGrid = Ext.create('Ext.grid.Panel', {
//            title: 'Build Status',
            store: Ext.data.StoreManager.lookup('ciBuildStore'),
            columns: [
                { text: 'Name', dataIndex: 'Name', width: 205 },
//                { text: 'Status', dataIndex: 'Status', flex: 1, xtype: 'templatecolumn', tpl: statusTpl},
                { text: 'Current Build', dataIndex: 'CurrentBuild', width: 175, xtype: 'templatecolumn', tpl: currentBuildTpl},
                { text: 'Last Good Build', dataIndex: 'LastGoodBuild', width: 175, xtype: 'templatecolumn', tpl: lastGoodBuildTpl },
                { text: 'Failed Builds', dataIndex: 'NumFailedBuilds', width: 50, tooltip: 'Number of failed builds since the last success', tooltipType: "qtip"},
                { menuDisabled: true, sortable: false, xtype: 'actioncolumn',items: [{
                    icon: 'https://raw.github.com/skandl/BuildActionBoard/master/button_got_it.jpg',
                    iconCls: 'gotItButton',
                    tooltip: 'I got it',
                    handler: function(grid, rowIndex, colIndex) {
                        console.log("Selected row %d", rowIndex);
                    }}],
                },
                {text: ' Savior', dataIndex: 'Owner', flex: 1}
            ],
            listeners: {
                cellclick: function(table, td, cellIndex, record, tr, rowIndex){
                    // cellIndex 1 is current build
                    //todo qualify index into array
                    if (cellIndex === 1)
                    {
                        console.log(gridFormattedBuilds[rowIndex].CurrentBuildRef);
    		Rally.environment.getMessageBus().publish('buildSelected', gridFormattedBuilds[rowIndex].CurrentBuildRef);

                    }

                    if (cellIndex === 2)
                    {
                        console.log(gridFormattedBuilds[rowIndex].CurrentBuildRef);
                        console.log(gridFormattedBuilds[rowIndex].LastGoodBuildRef);
                        Rally.environment.getMessageBus().publish('buildSelected', gridFormattedBuilds[rowIndex].LastGoodBuildRef);
                    }
                    console.log("cell click %d %d",cellIndex, rowIndex);

                }
            },
            height: 200
            //            plugins: [{
            //                ptype: 'rowexpander',
            //                rowBodyTpl: new Ext.XTemplate('foo')
            //            }],
            //            collapsible: true,
            //            animCollapse: false
        });

        this.add(myGrid);

    }

});
<|endoftext|>


<commit_before>var Ext = window.Ext4 || window.Ext;

var COMPUTE_METRICS_BUTTON_ID = 'compute-metrics-button';
var NUMBERS_COMBO_BOX_ID = 'numbers-combo-box';
var NUMBERS_COMBO_BOX_ID_AS_QUERY = '#' + NUMBERS_COMBO_BOX_ID;
var NUMBERS_STORE_ID = 'number-store';
var PROJECT_PICKER_ID = 'project-picker';
var RELEASE_COMBO_BOX_ID = 'release-combo-box';
var RELEASE_COMBO_BOX_ID_AS_QUERY = '#' + RELEASE_COMBO_BOX_ID;
var RETRIEVE_RESULTS_BUTTON_ID = 'retrieve-results-button';
var SPRINT_COMBO_BOX_ID = 'sprint-combo-box';
var SPRINT_COMBO_BOX_ID_AS_QUERY = '#' + SPRINT_COMBO_BOX_ID;
var UI_CONTAINER_ID = 'ui-container';
var UI_CONTAINER_ID_AS_QUERY = '#' + UI_CONTAINER_ID;

var MODELS = {
    FEATURE : 'PortfolioItem/Feature',
    USER_STORY : 'UserStory',
    DEFECT : 'Defect'
};

var FEATURE_STATES = {
    DONE : 'Done',
    EMPTY : ''
};

var CUBE_TEAMS = {};

Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    launch: function() {
        var me = this;

        me.buildUIContainer(UI_CONTAINER_ID);
    },

    doComputeMetrics: function () {
        var me = this;

        for (var i = 0; i < CUBE_TEAMS.length; i++) {
            var featureStore = me.createTeamFeatureStore(CUBE_TEAMS[i]);
            window.console.log("WHat is the featureStore?", featureStore);
        }
    },

    doRetrieveResults: function () {

    },

    onProjectSelect: function (projectPicker) {
        CUBE_TEAMS = projectPicker.selectedValues.items;
    },

    onReleaseSelect: function () {

    },

    launchTeamFeatureSnapshotStores: function (teamFeatureStore) {
        var me = this;
        var refTeamFeatureRecords = teamFeatureStore.getItems();

        window.console.log("What are the teamFeatureRecords?", refTeamFeatureRecords);

        for (var i = 0; i < refTeamFeatureRecords.length; i++) {
            me.createTeamFeatureSnapshotStore(refTeamFeatureRecords[i], teamFeatureStore.storeId);
        }
    },

    analyzeFeature: function (featureSnapshotStore) {
        window.console.log("What is the feature snapshot store?", featureSnapshotStore);

        var me = this;

        var refFeatureSnapshots = featureSnapshotStore.data.items;

        var featureState = {
            isPlanned: false,
            isCompleted: false,
            isAdded: false,
            isRemoved: false
        };

        for (var i = 0; i < refFeatureSnapshots.length; i++) {
            featureState.isPlanned = me.determinePlannedStatus(refFeatureSnapshots[i], featureState.isPlanned);
            featureState.isCompleted = me.determineCompletedStatus(refFeatureSnapshots[i], featureState.isCompleted);
            window.console.log("What is the completedState of feature: " + refFeatureSnapshots[i].data.FormattedID, featureState.isCompleted);
        }
    },

    determinePlannedStatus: function (featureSnapshot, isPlanned) {
        var me = this;

        if (isPlanned) {
            return true;
        }

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        var releaseStartDate = me._getCurrentlySelectedReleaseStartDate();
        var releaseEndDate = me._getCurrentlySelectedReleaseEndDate();
        var validFromDate = featureSnapshot.data._ValidFrom;
        var validToDate = featureSnapshot.data._ValidTo;

        if (validFromDate >= releaseStartDate && releaseStartDate <= validToDate && featureSnapshot.data.Release.Name === currentReleaseName) {
            return true;
        }

        return false;
    },

    determineCompletedStatus: function (featureSnapshot, isCompleted) {
        var me = this;

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        var releaseStartDate = me._getCurrentlySelectedReleaseStartDate();
        var releaseEndDate = me._getCurrentlySelectedReleaseEndDate();
        var validFromDate = featureSnapshot.data._ValidFrom;
        var validToDate = featureSnapshot.data._ValidTo;

        if (isCompleted) {
            if (featureSnapshot.data.State === FEATURE_STATES.DONE) {
                return true;
            } else {
                return false;
            }
        }

        if (releaseStartDate <= validFromDate && validFromDate <= releaseEndDate && featureSnapshot.data.Release.Name === currentReleaseName && featureSnapshot.data.State === FEATURE_STATES.DONE) {
            return true;
        }

        return false;
    },

    buildUIContainer: function (desiredContainerId) {
        var me = this;

        me.prepareUIContainer(desiredContainerId);
        me.prepareReleaseComboBox(RELEASE_COMBO_BOX_ID);
        me.prepareSprintComboBox(SPRINT_COMBO_BOX_ID);
        me.prepareNumbersComboBox(NUMBERS_COMBO_BOX_ID, NUMBERS_STORE_ID);
        me.prepareProjectPicker(PROJECT_PICKER_ID);
        me.prepareComputeMetricsButton(COMPUTE_METRICS_BUTTON_ID);
        me.prepareRetrieveResultsButton(RETRIEVE_RESULTS_BUTTON_ID);
    },

    prepareUIContainer: function (desiredContainerId) {
        var me = this;

        var uiContainer = me.createHBoxContainer(desiredContainerId);
        me.add(uiContainer);
    },

    prepareReleaseComboBox: function (desiredComboBoxId) {
        var me = this;

        var releaseComboBox = me.createReleaseComboBox(desiredComboBoxId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(releaseComboBox);

        window.console.log("What is the release combo box?", releaseComboBox);
    },

    prepareSprintComboBox: function (desiredComboBoxId) {
        var me = this;

        var sprintComboBox = me.createSprintComboBox(desiredComboBoxId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(sprintComboBox);
    },

    prepareNumbersComboBox: function (desiredComboBoxId, desiredNumberStoreId) {
        var me = this;

        var numberStore = me.createNumberStore(desiredNumberStoreId);
        var numbersComboBox = me.createNumbersComboBox(desiredComboBoxId, numberStore);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(numbersComboBox);
    },

    prepareProjectPicker: function (desiredPickerId) {
        var me = this;

        var projectPicker = me.createProjectPicker(desiredPickerId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(projectPicker);

        window.console.log("What is the projectPicker?", projectPicker);
    },

    prepareComputeMetricsButton: function (desiredButtonId) {
        var me = this;

        var computeMetricsButton = me.createComputeMetricsButton(desiredButtonId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(computeMetricsButton);
    },

    prepareRetrieveResultsButton: function (desiredButtonId) {
        var me = this;

        var retrieveResultsButton = me.createRetrieveResultsButton(desiredButtonId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(retrieveResultsButton);
    },

    createHBoxContainer: function (desiredContainerId) {
        return Ext.create('Ext.container.Container', {
            itemId: desiredContainerId,
            layout: {
                type: 'hbox'
            }
        });
    },

    createReleaseComboBox: function (desiredComboBoxId) {
        var me = this;

        return Ext.create('Rally.ui.combobox.ReleaseComboBox', {
            fieldLabel: 'Release',
            labelAlign: 'right',
            itemId: desiredComboBoxId,
            listeners: {
                select: me.onReleaseSelect,
                scope: me
            }
        });
    },

    createSprintComboBox: function (desiredComboBoxId) {
        var me = this;

        return Ext.create('Rally.ui.combobox.IterationComboBox', {
            fieldLabel: 'Sprint',
            labelAlign: 'right',
            itemId: desiredComboBoxId,
            width: 425
        });
    },

    createNumbersComboBox: function (desiredComboBoxId, associatedStore) {
        return Ext.create('Ext.form.field.ComboBox', {
            fieldLabel: 'Number of Sprints:',
            store: associatedStore,
            displayField: 'number',
            itemId: desiredComboBoxId,
            valueField: 'number',
            value: 1,
            width: 175
        });
    },

    createProjectPicker: function(desiredPickerId) {
        var me = this;

        return Ext.create('Rally.ui.picker.project.MultiProjectPicker', {
            listeners: {
                select: me.onProjectSelect,
                scope: me
            },
            storeConfig: {
                fetch: ['Name', 'Parent']
            }
        });
    },

    createComputeMetricsButton: function (desiredButtonId) {
        var me = this;

        return Ext.create('Rally.ui.Button', {
            itemId: desiredButtonId,
            text: 'Compute Metrics',
            handler: me.doComputeMetrics,
            scope: me
        });
    },

    createRetrieveResultsButton: function (desiredButtonId) {
        var me = this;

        return Ext.create('Rally.ui.Button', {
            itemId: desiredButtonId,
            text: 'Retrieve Results',
            handler: me.doRetrieveResults,
            scope: me
        });
    },

    createNumberStore: function (desiredNumberStoreId) {
        return Ext.create('Ext.data.Store', {
            fields: ['number'],
            storeId: desiredNumberStoreId,
            data: [
                {"number":"1"},
                {"number":"2"},
                {"number":"3"},
                {"number":"4"},
                {"number":"5"},
                {"number":"6"},
                {"number":"7"}
            ]
        });
    },

    createTeamFeatureStore: function (teamObject) {
        var me = this;

        var currentlySelectedRelease = me._getReferenceToCurrentlySelectedRelease();
        var featureFilterByReleaseAndTeam = me.createReleaseFilter(currentlySelectedRelease).and(me.createTeamFilter(teamObject));

        return Ext.create('Rally.data.wsapi.Store', {
            autoLoad: true,
            model: MODELS.FEATURE,
            storeId: teamObject.data.ObjectID,
            context: {
                project: me.getContext.getProject,
                scope: me
            },
            listeners: {
                load: me.launchTeamFeatureSnapshotStores,
                scope: me
            },
            filters: featureFilterByReleaseAndTeam
        });
    },

    createTeamFeatureSnapshotStore: function (featureObject, teamObjectId) {
        var me = this;

        var findSettings = {
            '_TypeHierarchy': MODELS.FEATURE,
            'Project': teamObjectId,
            'FormattedID': featureObject.FormattedID
        };

        window.console.log("What is teamObjectId?", teamObjectId);
        window.console.log("What is featureObject.FormattedID?", featureObject.FormattedID);

        return Ext.create('Rally.data.lookback.SnapshotStore', {
            autoLoad: true,
            find: findSettings,
            storeId: teamObjectId,
            fetch: ['FormattedID', 'Name', 'Release', 'State'],
            hydrate: ['FormattedID', 'Project', 'Release', 'State'],
            listeners: {
                load: me.analyzeFeature,
                scope: me
            },
            sorters: [
                {
                    property: 'ObjectID',
                    direction: 'ASC'
                }
            ]
        });
    },

    createTeamFilter: function (teamObject) {
        return Ext.create('Rally.data.wsapi.Filter', {
            property: 'Project.Name',
            operation: '=',
            value: teamObject.data.Name
        });
    },

    createReleaseFilter: function (currentlySelectedRelease) {
        var me = this;

        return Ext.create('Rally.data.wsapi.Filter', {
            property: 'Release.Name',
            operation: '=',
            value: currentlySelectedRelease
        });
    },

    _getReferenceToCurrentlySelectedRelease: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().get('_refObjectName');
    },

    _getCurrentlySelectedReleaseStartDate: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().raw.ReleaseStartDate;
    },

    _getCurrentlySelectedReleaseEndDate: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().raw.ReleaseDate;
    }
});
<commit_msg>Added code to determine if a feature was added or removed through snapshot analysis.<commit_after>var Ext = window.Ext4 || window.Ext;

var COMPUTE_METRICS_BUTTON_ID = 'compute-metrics-button';
var NUMBERS_COMBO_BOX_ID = 'numbers-combo-box';
var NUMBERS_COMBO_BOX_ID_AS_QUERY = '#' + NUMBERS_COMBO_BOX_ID;
var NUMBERS_STORE_ID = 'number-store';
var PROJECT_PICKER_ID = 'project-picker';
var RELEASE_COMBO_BOX_ID = 'release-combo-box';
var RELEASE_COMBO_BOX_ID_AS_QUERY = '#' + RELEASE_COMBO_BOX_ID;
var RETRIEVE_RESULTS_BUTTON_ID = 'retrieve-results-button';
var SPRINT_COMBO_BOX_ID = 'sprint-combo-box';
var SPRINT_COMBO_BOX_ID_AS_QUERY = '#' + SPRINT_COMBO_BOX_ID;
var UI_CONTAINER_ID = 'ui-container';
var UI_CONTAINER_ID_AS_QUERY = '#' + UI_CONTAINER_ID;

var MODELS = {
    FEATURE : 'PortfolioItem/Feature',
    USER_STORY : 'UserStory',
    DEFECT : 'Defect'
};

var FEATURE_STATES = {
    DONE : 'Done',
    EMPTY : ''
};

var CUBE_TEAMS = {};

Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    launch: function() {
        var me = this;

        me.buildUIContainer(UI_CONTAINER_ID);
    },

    doComputeMetrics: function () {
        var me = this;

        for (var i = 0; i < CUBE_TEAMS.length; i++) {
            var featureStore = me.createTeamFeatureStore(CUBE_TEAMS[i]);
            window.console.log("What is the featureStore?", featureStore);
        }
    },

    doRetrieveResults: function () {

    },

    onProjectSelect: function (projectPicker) {
        CUBE_TEAMS = projectPicker.selectedValues.items;
    },

    onReleaseSelect: function () {

    },

    launchTeamFeatureSnapshotStores: function (teamFeatureStore) {
        var me = this;
        var refTeamFeatureRecords = teamFeatureStore.getItems();

        window.console.log("What are the teamFeatureRecords?", refTeamFeatureRecords);

        for (var i = 0; i < refTeamFeatureRecords.length; i++) {
            me.createTeamFeatureSnapshotStore(refTeamFeatureRecords[i], teamFeatureStore.storeId);
        }
    },

    analyzeFeature: function (featureSnapshotStore) {
        window.console.log("What is the feature snapshot store for " + featureSnapshotStore.data.items[0].data.FormattedID, featureSnapshotStore);

        var me = this;

        var refFeatureSnapshots = featureSnapshotStore.data.items;

        var featureState = {
            isPlanned: false,
            isCompleted: false,
            isAdded: false,
            isRemoved: false,
            isPartOfRelease: false
        };

        for (var i = 0; i < refFeatureSnapshots.length; i++) {
            featureState.isPartOfRelease = me.determineReleaseStatus(refFeatureSnapshots[i]);
            featureState.isPlanned = me.determinePlannedStatus(refFeatureSnapshots[i], featureState.isPlanned);
            featureState.isCompleted = me.determineCompletedStatus(refFeatureSnapshots[i], featureState.isCompleted);
            featureState.isAdded = me.determineAddedStatus(refFeatureSnapshots[i], featureState.isAdded, featureState.isPlanned);
            featureState.isRemoved = me.determineRemovedStatus(refFeatureSnapshots[i], featureState.isPartOfRelease, featureState.isRemoved);
//            window.console.log("What is the release state of feature: " + refFeatureSnapshots[i].data.FormattedID, featureState.isPartOfRelease);
//            window.console.log("What is the planned state of feature: " + refFeatureSnapshots[i].data.FormattedID, featureState.isPlanned);
//            window.console.log("What is the added state of feature: " + refFeatureSnapshots[i].data.FormattedID, featureState.isAdded);
            window.console.log("What is the removed state of feature: " + refFeatureSnapshots[i].data.FormattedID, featureState.isRemoved);
        }
    },

    determineReleaseStatus: function (featureSnapshot) {
        var me = this;

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        return (featureSnapshot.data.Release.Name === currentReleaseName);
    },

    determinePlannedStatus: function (featureSnapshot, isPlanned) {
        if (isPlanned) {
            return true;
        }

        var me = this;

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        var releaseStartDate = me._getCurrentlySelectedReleaseStartDate();
        var releaseEndDate = me._getCurrentlySelectedReleaseEndDate();
        var validFromDate = featureSnapshot.data._ValidFrom;
        var validToDate = featureSnapshot.data._ValidTo;

        if (validFromDate <= releaseStartDate && validToDate >= releaseStartDate && featureSnapshot.data.Release.Name === currentReleaseName) {
            return true;
        }

        return false;
    },

    determineCompletedStatus: function (featureSnapshot, isCompleted) {
        if (isCompleted) {
            return (featureSnapshot.data.State === FEATURE_STATES.DONE);
        }

        var me = this;

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        var releaseStartDate = me._getCurrentlySelectedReleaseStartDate();
        var releaseEndDate = me._getCurrentlySelectedReleaseEndDate();
        var validFromDate = featureSnapshot.data._ValidFrom;
        var validToDate = featureSnapshot.data._ValidTo;

        if (releaseStartDate <= validFromDate && validFromDate <= releaseEndDate && featureSnapshot.data.Release.Name === currentReleaseName && featureSnapshot.data.State === FEATURE_STATES.DONE) {
            return true;
        }

        return false;
    },

    determineAddedStatus: function (featureSnapshot, isAdded, isPlanned) {
        if (isAdded) {
            return !isPlanned;
        }

        var me = this;

        var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
        var releaseStartDate = me._getCurrentlySelectedReleaseStartDate();
        var releaseEndDate = me._getCurrentlySelectedReleaseEndDate();
        var validFromDate = featureSnapshot.data._ValidFrom;
        var validToDate = featureSnapshot.data._ValidTo;

        if (validFromDate > releaseStartDate && validFromDate <= releaseEndDate && featureSnapshot.data.Release.Name === currentReleaseName && !isPlanned) {
            return true;
        }

        return false;
    },

    determineRemovedStatus: function (featureSnapshot, isPartOfRelease, isRemoved) {
        var me = this;

        if (isPartOfRelease) {
            var currentReleaseName = me._getReferenceToCurrentlySelectedRelease();
            return featureSnapshot.data.Release.Name !== currentReleaseName;
        }

        return isRemoved;
    },

    buildUIContainer: function (desiredContainerId) {
        var me = this;

        me.prepareUIContainer(desiredContainerId);
        me.prepareReleaseComboBox(RELEASE_COMBO_BOX_ID);
        me.prepareSprintComboBox(SPRINT_COMBO_BOX_ID);
        me.prepareNumbersComboBox(NUMBERS_COMBO_BOX_ID, NUMBERS_STORE_ID);
        me.prepareProjectPicker(PROJECT_PICKER_ID);
        me.prepareComputeMetricsButton(COMPUTE_METRICS_BUTTON_ID);
        me.prepareRetrieveResultsButton(RETRIEVE_RESULTS_BUTTON_ID);
    },

    prepareUIContainer: function (desiredContainerId) {
        var me = this;

        var uiContainer = me.createHBoxContainer(desiredContainerId);
        me.add(uiContainer);
    },

    prepareReleaseComboBox: function (desiredComboBoxId) {
        var me = this;

        var releaseComboBox = me.createReleaseComboBox(desiredComboBoxId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(releaseComboBox);

        window.console.log("What is the release combo box?", releaseComboBox);
    },

    prepareSprintComboBox: function (desiredComboBoxId) {
        var me = this;

        var sprintComboBox = me.createSprintComboBox(desiredComboBoxId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(sprintComboBox);
    },

    prepareNumbersComboBox: function (desiredComboBoxId, desiredNumberStoreId) {
        var me = this;

        var numberStore = me.createNumberStore(desiredNumberStoreId);
        var numbersComboBox = me.createNumbersComboBox(desiredComboBoxId, numberStore);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(numbersComboBox);
    },

    prepareProjectPicker: function (desiredPickerId) {
        var me = this;

        var projectPicker = me.createProjectPicker(desiredPickerId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(projectPicker);

        window.console.log("What is the projectPicker?", projectPicker);
    },

    prepareComputeMetricsButton: function (desiredButtonId) {
        var me = this;

        var computeMetricsButton = me.createComputeMetricsButton(desiredButtonId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(computeMetricsButton);
    },

    prepareRetrieveResultsButton: function (desiredButtonId) {
        var me = this;

        var retrieveResultsButton = me.createRetrieveResultsButton(desiredButtonId);
        me.down(UI_CONTAINER_ID_AS_QUERY).add(retrieveResultsButton);
    },

    createHBoxContainer: function (desiredContainerId) {
        return Ext.create('Ext.container.Container', {
            itemId: desiredContainerId,
            layout: {
                type: 'hbox'
            }
        });
    },

    createReleaseComboBox: function (desiredComboBoxId) {
        var me = this;

        return Ext.create('Rally.ui.combobox.ReleaseComboBox', {
            fieldLabel: 'Release',
            labelAlign: 'right',
            itemId: desiredComboBoxId,
            listeners: {
                select: me.onReleaseSelect,
                scope: me
            }
        });
    },

    createSprintComboBox: function (desiredComboBoxId) {
        var me = this;

        return Ext.create('Rally.ui.combobox.IterationComboBox', {
            fieldLabel: 'Sprint',
            labelAlign: 'right',
            itemId: desiredComboBoxId,
            width: 425
        });
    },

    createNumbersComboBox: function (desiredComboBoxId, associatedStore) {
        return Ext.create('Ext.form.field.ComboBox', {
            fieldLabel: 'Number of Sprints:',
            store: associatedStore,
            displayField: 'number',
            itemId: desiredComboBoxId,
            valueField: 'number',
            value: 1,
            width: 175
        });
    },

    createNumberStore: function (desiredNumberStoreId) {
        return Ext.create('Ext.data.Store', {
            fields: ['number'],
            storeId: desiredNumberStoreId,
            data: [
                {"number":"1"},
                {"number":"2"},
                {"number":"3"},
                {"number":"4"},
                {"number":"5"},
                {"number":"6"},
                {"number":"7"}
            ]
        });
    },

    createProjectPicker: function(desiredPickerId) {
        var me = this;

        return Ext.create('Rally.ui.picker.project.MultiProjectPicker', {
            listeners: {
                select: me.onProjectSelect,
                scope: me
            },
            storeConfig: {
                fetch: ['Name', 'Parent']
            }
        });
    },

    createComputeMetricsButton: function (desiredButtonId) {
        var me = this;

        return Ext.create('Rally.ui.Button', {
            itemId: desiredButtonId,
            text: 'Compute Metrics',
            handler: me.doComputeMetrics,
            scope: me
        });
    },

    createRetrieveResultsButton: function (desiredButtonId) {
        var me = this;

        return Ext.create('Rally.ui.Button', {
            itemId: desiredButtonId,
            text: 'Retrieve Results',
            handler: me.doRetrieveResults,
            scope: me
        });
    },

    createTeamFeatureStore: function (teamObject) {
        var me = this;

        var currentlySelectedRelease = me._getReferenceToCurrentlySelectedRelease();
        var featureFilterByReleaseAndTeam = me.createReleaseFilter(currentlySelectedRelease).and(me.createTeamFilter(teamObject));

        return Ext.create('Rally.data.wsapi.Store', {
            autoLoad: true,
            model: MODELS.FEATURE,
            storeId: teamObject.data.ObjectID,
            context: {
                project: me.getContext.getProject,
                scope: me
            },
            listeners: {
                load: me.launchTeamFeatureSnapshotStores,
                scope: me
            },
            filters: featureFilterByReleaseAndTeam
        });
    },

    createTeamFeatureSnapshotStore: function (featureObject, teamObjectId) {
        var me = this;

        var findSettings = {
            '_TypeHierarchy': MODELS.FEATURE,
            'Project': teamObjectId,
            'ObjectID': featureObject.ObjectID
        };

        window.console.log("What is teamObjectId?", teamObjectId);
        window.console.log("What is featureObject.FormattedID?", featureObject.FormattedID);

        return Ext.create('Rally.data.lookback.SnapshotStore', {
            autoLoad: true,
            find: findSettings,
            storeId: teamObjectId,
            fetch: ['FormattedID', 'Name', 'Release', 'State'],
            hydrate: ['FormattedID', 'Project', 'Release', 'State'],
            listeners: {
                load: me.analyzeFeature,
                scope: me
            },
            sorters: [
                {
                    property: 'ObjectID',
                    direction: 'ASC'
                }
            ]
        });
    },

    createTeamFilter: function (teamObject) {
        return Ext.create('Rally.data.wsapi.Filter', {
            property: 'Project.Name',
            operation: '=',
            value: teamObject.data.Name
        });
    },

    createReleaseFilter: function (currentlySelectedRelease) {
        var me = this;

        return Ext.create('Rally.data.wsapi.Filter', {
            property: 'Release.Name',
            operation: '=',
            value: currentlySelectedRelease
        });
    },

    _getReferenceToCurrentlySelectedRelease: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().get('_refObjectName');
    },

    _getCurrentlySelectedReleaseStartDate: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().raw.ReleaseStartDate;
    },

    _getCurrentlySelectedReleaseEndDate: function () {
        var me = this;

        return me.down(RELEASE_COMBO_BOX_ID_AS_QUERY).getRecord().raw.ReleaseDate;
    }
});
<|endoftext|>


<commit_before>Ext.define('Rally.ui.picker.SonOfMultiObjectPicker', {
    extend: 'Rally.ui.picker.MultiObjectPicker',
    alias: 'widget.sonofrallymultiobjectpicker',
    _createStoreAndExpand: function() {
console.log('creating store');
            var storeCreator = Ext.create('Rally.data.DataStoreCreator', {
                modelType: this.modelType,
                storeConfig: this.storeConfig,
                storeType: this.storeType
            });
            this.mon(storeCreator, 'storecreate', function(store) {
                this.store = store;
                this.expand();
            }, this, {single: true});
            storeCreator.createStore();
    }
});
Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',

    dayRange: 30,
    severityValues: [],     // custom values for defect 'severity'
    priorityValues: [],     // custom values for defect 'priority'
    stateValues: [],        // custom values for defect 'state'

    launch: function() {
        this._loadDumbChart();
        this._loadDefectFilterValues();
    },

    _loadDumbChart: function() {
        this.dumbChart = Ext.create("Rally.ui.chart.Chart", {
            itemId: 'dumbChart',
            chartConfig: {
              chart: {
                type: 'area'
            }
          },
            chartData: {
              series: [{
                name: 'USA',
                data: [6]
            }] //[{data: [1,2,3]}] //hcData
            }
        });
        this.add(this.dumbChart);
        this.down("#dumbChart").destroy();

    },

    // kickoff series of async value fetches for Defect attributes (severity, priority, etc)
    _loadDefectFilterValues: function() {
        Rally.data.ModelFactory.getModel({
            type: 'Defect',
            success: function(model) {
                this._loadDefectSeverityValues(model);
            },
            scope: this
        });
    },

    // Load custom defect 'severity' values for the filter pulldown
    _loadDefectSeverityValues: function(model) {
        this.severity = model.getField('Severity');
        var store = this.severity.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.severityValues.push(el.data.StringValue);}
                }, this);
                this._loadDefectPriorityValues(model);
            },
            scope: this
        }, this);
    },

    // Load custom defect 'priority' values for the filter pulldown
    _loadDefectPriorityValues: function(model) {
        var priority = model.getField('Priority');
        var store = priority.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.priorityValues.push(el.data.StringValue);}
                }, this);
                this._loadDefectStateValues(model);
            },
            scope: this
        }, this);
    },

    // Load custom defect 'state' values for the filter pulldown
    _loadDefectStateValues: function(model) {
        var state = model.getField('State');
        var store = state.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.stateValues.push(el.data.StringValue);}
                }, this);
                this._loadDayRangeSelector();
            },
            scope: this
        }, this);
    },

    // create the 30/60/90 day range selector
    _loadDayRangeSelector: function() {

        this.add({
            xtype: 'dayrangepicker',
            itemId: 'dayRangePicker',
            defaultSelection: '30',   // 30|60|90
            autoLoadSelection: true
        });

        this.down('#dayRangePicker').on({
            on30clicked: function() {
                console.log('day range %i', 30);
                this.dayRange = DayRangePicker.THIRTY;
                this._getChartData();
            },
            on60clicked: function() {
                console.log('day range %i', 60);
                this.dayRange = DayRangePicker.SIXTY;
                this._getChartData();
            },
            on90clicked: function() {
                console.log('day range %i', 90);
                this.dayRange = DayRangePicker.NINETY;
                this._getChartData();
            },
            scope: this
        });

        this._multiSelect();
        this._getChartData();
    },

    _createMultiPicker: function(values, title)
    {
        var storeData = [];
        _.each(values, function(value, i) {
            storeData.push({Name: value, ObjectID: i, _CreatedAt: i});
        });

        this.add({
            xtype: 'sonofrallymultiobjectpicker',
            itemId: title,
            modelType: 'attributedefinition',
            config: {selectionKey: '_CreatedAt'},
            placeholderText: title,
            storeConfig: {
                data: storeData
            },
            listeners:
            {
                select: function() {
                    this._getSelectedValues("#" + title);
                },
                scope: this
            },
            storeType: 'Rally.data.custom.Store'
        });

        this.add(
        {
            xtype: 'button',
            text: 'Click me',
            handler: function() {
                alert('You clicked the ' + title + ' button!');
            }
        });
    },

    _getSelectedValues: function(id) {
        var picker = this.down(id);
        var selected = [];
        if (picker) {
            _.each(picker.selectedValues.items, function(val) {
                selected.push(val.data.Name);
            });
        }
        console.log(selected);
    },

    _multiSelect: function() {
        this._createMultiPicker(this.priorityValues, "Priorities");
        this._createMultiPicker(this.stateValues, "States");
    },

    _getFilters: function() {
        var daysAgo = Ext.Date.add(new Date(), Ext.Date.DAY, -this.dayRange);
        var startOnISOString = Rally.util.DateTime.toIsoString(daysAgo, true);

        var filters =
            [
                {
                    property: '_TypeHierarchy',
                    operator: 'in',
                    value: ['Defect']
                },
                {
                    property: 'Severity',
                    operator: 'in',
                    value: this.severityValues
                },
                {
                    property: "Project",
                    operator: "in",
                    value: [279050021]
                },
                {
                    property: "_ValidTo",
                    operator: ">=",
                    value: startOnISOString
                }
            ];

        // var stateValues = _.pluck(this.down('#stateBox').getChecked(), 'inputValue');
        // if (!_.contains(stateValues, "All") && stateValues.length)
        // {
        //     filters.push({
        //         property: "State",
        //         operator: "in",
        //         value: stateValues
        //     });
        // }

        // var priorityValues = _.pluck(this.down('#priorityBox').getChecked(), 'inputValue');
        // if (!_.contains(priorityValues, "All"))
        // {
        //     filters.push({
        //         property: "Priority",
        //         operator: "in",
        //         value: priorityValues
        //     });
        // }

        return filters;

    },

    _getChartData: function() {

        var myFilters = this._getFilters();

        if (this.down("#myChart")) {
          this.down("#myChart").destroy();
          //this.remove(this.down("#myChart"));
        }

        Ext.create('Rally.data.lookback.SnapshotStore', {
            listeners: {
                load: function(store,data,success) {
                  this._onDefectsLoaded(data);
                },
                scope: this
            },
            fetch: ['Name', 'Severity'],
            autoLoad: true,
            context: {
                workspace: '/workspace/41529001',
                project: '/project/279050021',
                projectScopeUp: false,
                projectScopeDown: true
            },
            hydrate: ['Severity'],
            filters: myFilters,
            scope: this
        });

    },

    _getChartConfiguration: function() {
        return{
          chart: {
                type: 'area'
            },
            title: {
                text: 'Historic and Estimated Worldwide Population Growth by Region'
            },
            subtitle: {
                text: 'Source: Wikipedia.org'
            },
            xAxis: {
                type: 'datetime'
            },
            yAxis: {
                title: {
                    text: 'Count'
                },
                labels: {
                    formatter: function() {
                        return this.value;
                    }
                }
            },
            tooltip: {
                shared: true
            },
            plotOptions: {
                area: {
                    stacking: 'normal',
                    lineColor: '#666666',
                    lineWidth: 1,
                    marker: {
                        lineWidth: 1,
                        lineColor: '#666666'
                    }
                }
            }
        };
    },

    _onDefectsLoaded: function (data) {
        // we are going to use lumenize and the TimeSeriesCalculator to aggregate the data into
        // a time series.

        var snapShotData = _.map(data,function(d){return d.data;});

        // can be used to 'knockout' holidays
        var holidays = [
            {year: 2014, month: 1, day: 1}  // Made up holiday to test knockout
        ];

        // metrics to chart
        // var metrics = [
        //     {as: 'defectMajor',     f: 'filteredCount', filterField: 'Severity', filterValues: ["Major Problem"]},
        //     {as: 'defectMinor',   f: 'filteredCount', filterField: 'Severity', filterValues: ["Minor Problem"]},
        //     {as: 'defectCosmetic', f: 'filteredCount', filterField: 'Severity', filterValues: ["Cosmetic"]}
        // ];

        var metrics = [];
        _.each(this.severityValues, function(value) {
            metrics.push({
                as: value, f: 'filteredCount', filterField: 'Severity', filterValues: [value]
            });
        });

        // not used yet
        var summaryMetricsConfig = [
        ];

        var derivedFieldsAfterSummary = [
        ];

        // not used yet
        var deriveFieldsOnInput = [
        ];

        // small change

        // calculator config
        var config = {
          metrics: metrics,
          granularity: 'day',
          tz: 'America/Chicago',
          holidays: holidays,
          workDays: 'Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday',
          summaryMetricsConfig: summaryMetricsConfig,
          deriveFieldsAfterSummary: derivedFieldsAfterSummary,
          deriveFieldsOnInput: deriveFieldsOnInput
        };

        // release start and end dates

        var daysAgo = Ext.Date.add(new Date(), Ext.Date.DAY, -this.dayRange);

        var currentDate = Ext.Date.add(new Date(), Ext.Date.DAY, 0);

        var startOnISOString = Rally.util.DateTime.toIsoString(daysAgo, true);
        var upToDateISOString = Rally.util.DateTime.toIsoString(currentDate, true);
        //var startOnISOString = new lumenize.Time("2013-09-28").getISOStringInTZ(config.tz)
        //var upToDateISOString = new lumenize.Time("2013-10-28").getISOStringInTZ(config.tz)

        // create the c alculator and add snapshots to it.
        //calculator = new Rally.data.lookback.Lumenize.TimeSeriesCalculator(config);
        calculator = new Rally.data.lookback.Lumenize.TimeSeriesCalculator(config);

        calculator.addSnapshots(snapShotData, startOnISOString, upToDateISOString);

        // create a high charts series config object, used to get the hc series data

        var hcConfig = []
        _.each(this.severityValues, function(value) {
            hcConfig.push({name: value});
        });

        //var hcConfig = [ { name : "defectMajor" }, { name : "defectMinor"},{name:"defectCosmetic"}];
        var hcData = Rally.data.lookback.Lumenize.arrayOfMaps_To_HighChartsSeries(calculator.getResults().seriesData, hcConfig);

        var dt;

        _.each(hcData, function(seriesObj) {
            dt = Ext.Date.format(daysAgo, 'Y-m-d').split("-");
            seriesObj.pointStart = Date.UTC(dt[0], dt[1] - 1, dt[2]);
            seriesObj.pointInterval = 24 * 3600 * 1000;
        });

        var myChart = Ext.create("Rally.ui.chart.Chart", {
            chartConfig: this._getChartConfiguration(),
            chartData: {
                series: hcData
            },
            itemId: 'myChart'
        });
        this.add(myChart);
        Ext.util.Observable.capture(myChart, function(e)
        {
          console.log('chart %s - %s', myChart.getId(), e);
          return true;
        });
    }
});
<commit_msg>simplified chart logic to just use Severity epr original request; still need to figure out load mask issue<commit_after>Ext.define('Rally.ui.picker.SonOfMultiObjectPicker', {
    extend: 'Rally.ui.picker.MultiObjectPicker',
    alias: 'widget.sonofrallymultiobjectpicker',
    _createStoreAndExpand: function() {
console.log('creating store');
            var storeCreator = Ext.create('Rally.data.DataStoreCreator', {
                modelType: this.modelType,
                storeConfig: this.storeConfig,
                storeType: this.storeType
            });
            this.mon(storeCreator, 'storecreate', function(store) {
                this.store = store;
                this.expand();
            }, this, {single: true});
            storeCreator.createStore();
    }
});
Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',

    dayRange: 30,
    severityValues: [],     // custom values for defect 'severity'
    priorityValues: [],     // custom values for defect 'priority'
    stateValues: [],        // custom values for defect 'state'

    launch: function() {
        //this._loadDumbChart();
        this._loadDefectFilterValues();
    },

    _loadDumbChart: function() {
        this.dumbChart = Ext.create("Rally.ui.chart.Chart", {
            itemId: 'dumbChart',
            chartConfig: {
              chart: {
                type: 'area'
            }
          },
            chartData: {
              series: [{
                name: 'USA',
                data: [6]
            }] //[{data: [1,2,3]}] //hcData
            }
        });
        this.add(this.dumbChart);
        this.down("#dumbChart").destroy();

    },

    // kickoff series of async value fetches for Defect attributes (severity, priority, etc)
    _loadDefectFilterValues: function() {
        Rally.data.ModelFactory.getModel({
            type: 'Defect',
            success: function(model) {
                this._loadDefectSeverityValues(model);
            },
            scope: this
        });
    },

    // Load custom defect 'severity' values for the filter pulldown
    _loadDefectSeverityValues: function(model) {
        this.severity = model.getField('Severity');
        var store = this.severity.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.severityValues.push(el.data.StringValue);}
                }, this);
                // DPT not chaining calls right now
                // this._loadDefectPriorityValues(model);
                this._loadDayRangeSelector();
            },
            scope: this
        }, this);
    },

    // Load custom defect 'priority' values for the filter pulldown
    _loadDefectPriorityValues: function(model) {
        var priority = model.getField('Priority');
        var store = priority.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.priorityValues.push(el.data.StringValue);}
                }, this);
                this._loadDefectStateValues(model);
            },
            scope: this
        }, this);
    },

    // Load custom defect 'state' values for the filter pulldown
    _loadDefectStateValues: function(model) {
        var state = model.getField('State');
        var store = state.getAllowedValueStore();
        store.load({
            callback: function(data) {
                _.each(data, function(el) {
                    if (el.data.StringValue != "") {this.stateValues.push(el.data.StringValue);}
                }, this);
                this._loadDayRangeSelector();
            },
            scope: this
        }, this);
    },

    // create the 30/60/90 day range selector
    _loadDayRangeSelector: function() {

        this.add({
            xtype: 'dayrangepicker',
            itemId: 'dayRangePicker',
            defaultSelection: '30',   // 30|60|90
            autoLoadSelection: true
        });

        this.down('#dayRangePicker').on({
            on30clicked: function() {
                console.log('day range %i', 30);
                this.dayRange = DayRangePicker.THIRTY;
                this._getChartData();
            },
            on60clicked: function() {
                console.log('day range %i', 60);
                this.dayRange = DayRangePicker.SIXTY;
                this._getChartData();
            },
            on90clicked: function() {
                console.log('day range %i', 90);
                this.dayRange = DayRangePicker.NINETY;
                this._getChartData();
            },
            scope: this
        });

        //this._multiSelect();
        this._getChartData();
    },

    _createMultiPicker: function(values, title)
    {
        var storeData = [];
        _.each(values, function(value, i) {
            storeData.push({Name: value, ObjectID: i, _CreatedAt: i});
        });

        this.add({
            xtype: 'sonofrallymultiobjectpicker',
            itemId: title,
            modelType: 'attributedefinition',
            config: {selectionKey: '_CreatedAt'},
            placeholderText: title,
            storeConfig: {
                data: storeData
            },
            listeners:
            {
                select: function() {
                    this._getSelectedValues("#" + title);
                },
                scope: this
            },
            storeType: 'Rally.data.custom.Store'
        });

        this.add(
        {
            xtype: 'button',
            text: 'Click me',
            handler: function() {
                alert('You clicked the ' + title + ' button!');
            }
        });
    },

    _getSelectedValues: function(id) {
        var picker = this.down(id);
        var selected = [];
        if (picker) {
            _.each(picker.selectedValues.items, function(val) {
                selected.push(val.data.Name);
            });
        }
        console.log(selected);
    },

    _multiSelect: function() {
        this._createMultiPicker(this.severityValues, "Severity");
    },

    _getChartFilters: function() {
        var daysAgo = Ext.Date.add(new Date(), Ext.Date.DAY, -this.dayRange);
        var startOnISOString = Rally.util.DateTime.toIsoString(daysAgo, true);

        var filters =
            [
                {
                    property: '_TypeHierarchy',
                    operator: 'in',
                    value: ['Defect']
                },
                {
                    property: 'Severity',
                    operator: 'in',
                    value: this.severityValues
                },
                {
                    property: "Project",
                    operator: "in",
                    value: [279050021]    // FIXME get from context
                },
                {
                    property: "_ValidTo",
                    operator: ">=",
                    value: startOnISOString
                }
            ];

        // var stateValues = _.pluck(this.down('#stateBox').getChecked(), 'inputValue');
        // if (!_.contains(stateValues, "All") && stateValues.length)
        // {
        //     filters.push({
        //         property: "State",
        //         operator: "in",
        //         value: stateValues
        //     });
        // }

        // var priorityValues = _.pluck(this.down('#priorityBox').getChecked(), 'inputValue');
        // if (!_.contains(priorityValues, "All"))
        // {
        //     filters.push({
        //         property: "Priority",
        //         operator: "in",
        //         value: priorityValues
        //     });
        // }

        return filters;

    },

    _getChartData: function() {

        var myFilters = this._getChartFilters();
console.log('filters', myFilters);
/*
        if (this.down("#myChart")) {
          this.down("#myChart").destroy();
        }
*/

        Ext.create('Rally.data.lookback.SnapshotStore', {
            listeners: {
                load: function(store,data,success) {
                  this._onDefectsLoaded(data);
                },
                scope: this
            },
            fetch: ['Name', 'Severity'],
            autoLoad: true,
            context: {
                workspace: '/workspace/41529001',
                project: '/project/279050021',
                projectScopeUp: false,
                projectScopeDown: true
            },
            hydrate: ['Severity'],
            filters: myFilters,
            scope: this
        });

    },

    _getChartConfiguration: function() {
        return{
          chart: {
                type: 'area'
            },
            title: {
                text: 'Defect Trend'
            },
            subtitle: {
                text: 'Severity'
            },
            xAxis: {
                type: 'datetime'
            },
            yAxis: {
                title: {
                    text: 'Count'
                },
                labels: {
                    formatter: function() {
                        return this.value;
                    }
                }
            },
            tooltip: {
                shared: true
            },
            plotOptions: {
                area: {
                    stacking: 'normal',
                    lineColor: '#666666',
                    lineWidth: 1,
                    marker: {
                        lineWidth: 1,
                        lineColor: '#666666'
                    }
                }
            }
        };
    },

    _onDefectsLoaded: function (data) {

        var snapShotData = _.map(data,function(d){return d.data;});

        // can be used to 'knockout' holidays
        var holidays = [
            {year: 2014, month: 1, day: 1}  // Made up holiday to test knockout
        ];

        // metrics to chart
        // var metrics = [
        //     {as: 'defectMajor',     f: 'filteredCount', filterField: 'Severity', filterValues: ["Major Problem"]},
        //     {as: 'defectMinor',   f: 'filteredCount', filterField: 'Severity', filterValues: ["Minor Problem"]},
        //     {as: 'defectCosmetic', f: 'filteredCount', filterField: 'Severity', filterValues: ["Cosmetic"]}
        // ];

        var metrics = [];
        _.each(this.severityValues, function(value) {
            metrics.push({
                as: value, f: 'filteredCount', filterField: 'Severity', filterValues: [value]
            });
        });

        // not used yet
        var summaryMetricsConfig = [
        ];

        var derivedFieldsAfterSummary = [
        ];

        // not used yet
        var deriveFieldsOnInput = [
        ];

        // small change

        // calculator config
        var config = {
          metrics: metrics,
          granularity: 'day',
          tz: 'America/Chicago',
          holidays: holidays,
          workDays: 'Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday',
          summaryMetricsConfig: summaryMetricsConfig,
          deriveFieldsAfterSummary: derivedFieldsAfterSummary,
          deriveFieldsOnInput: deriveFieldsOnInput
        };

        // release start and end dates
        var daysAgo = Ext.Date.add(new Date(), Ext.Date.DAY, -this.dayRange);

        var currentDate = Ext.Date.add(new Date(), Ext.Date.DAY, 0);

        var startOnISOString = Rally.util.DateTime.toIsoString(daysAgo, true);
        var upToDateISOString = Rally.util.DateTime.toIsoString(currentDate, true);
        //var startOnISOString = new lumenize.Time("2013-09-28").getISOStringInTZ(config.tz)
        //var upToDateISOString = new lumenize.Time("2013-10-28").getISOStringInTZ(config.tz)

        // create the c alculator and add snapshots to it.
        //calculator = new Rally.data.lookback.Lumenize.TimeSeriesCalculator(config);
        calculator = new Rally.data.lookback.Lumenize.TimeSeriesCalculator(config);

        calculator.addSnapshots(snapShotData, startOnISOString, upToDateISOString);

        // create a high charts series config object, used to get the hc series data

        var hcConfig = []
        _.each(this.severityValues, function(value) {
            hcConfig.push({name: value});
        });

        //var hcConfig = [ { name : "defectMajor" }, { name : "defectMinor"},{name:"defectCosmetic"}];
        var hcData = Rally.data.lookback.Lumenize.arrayOfMaps_To_HighChartsSeries(calculator.getResults().seriesData, hcConfig);

        var dt;

        _.each(hcData, function(seriesObj) {
            dt = Ext.Date.format(daysAgo, 'Y-m-d').split("-");
            seriesObj.pointStart = Date.UTC(dt[0], dt[1] - 1, dt[2]);
            seriesObj.pointInterval = 24 * 3600 * 1000;
        });

        var myChart = Ext.create("Rally.ui.chart.Chart", {
            chartConfig: this._getChartConfiguration(),
            chartData: {
                series: hcData
            },
            itemId: 'myChart'
        });
        this.add(myChart);
        debugger;
        /*
        Ext.util.Observable.capture(myChart, function(e)
        {
          console.log('chart %s - %s', myChart.getId(), e);
          return true;
        });
        */
    }
});
<|endoftext|>