Related
I want to put 'mqtt' value in span. But it doesn't work.
I think the loading method is wrong, but I don't know how to do it.
I don't know if the code below will suffice. Any help would be greatly appreciated.
Someone else coded similar to one page. Someone else's code has a value in 'detail', but my code doesn't. Why?
HTML
span{{ detail }}span //empty with nothing
Front script1
export default {
props: {
detail: {
type: Object
},
isAdd: {
type: Boolean,
default: false
},
},
data() {
return {};
},
mounted() {
this.$mqtt.subscribe('#');
},
methods: {
SendData() {
var temp = [];
var name = Number(document.getElementsByClassName('name').innerHTML);
temp.push(name);
var temp_current = data.payload.Temp_Current;
var error = data.payload.Error;
var data = {
//workcd: this.detail.namemodel,
Temp_Current: temp_current,
Error: error,
};
data = JSON.stringify(data);
var pub_name_arr = this.detail.name.split(' ');
var pub_name = 'CCComandTopic';
this.$mqtt.publish(
pub_name + '/' + pub_name_arr[1] + '/' + pub_name_arr[2],
data,
);
},
}
}
Front script 2
showHotrunner(namemodel, name, data) {
this.$modal.show(
Hotrunner,
{detail: {namemodel, name, data}, isAdd: true},
{width: '1040', height: '700', draggable: true},
);
const canvas = document.getElementById('three-canvas');
canvas.classList.add('noclick');
}
Back
var device = msg.topic.split("/")[2]
if(device == "hopper")
{
var temp_current = msg.payload.Temp_Current
var error = msg.payload.error
msg = {
topic : "CCComandTopic/hopper/1",
payload : {
ID: id,
"Error": error,
Temp_Current: temp_current,
}
}.
node.send(msg)
}
I have this react native application which imports the phone contacts to database. I have about 100 contacts in my phone and it's taking ages...like 1 import per second which is. I'm sure, a mistake I'm doing somewhere even though the code is simple.
realm.write(() => {
for (let i = 0, len = contacts.length; i < len; i++) {
Contact.saveOrUpdate(contacts[i].name, contacts[i].recordID, contacts[i].phoneNumbers);
}
});
saveOrUpdate method:
class Contact {
static saveOrUpdate(name, recordId, phones) {
const save = () => {
let c;
try {
// try an update first
c = realm.create('Contact', {
name: name.toString(),
recordID: recordId.toString()
}, true);
} catch (e) {
// if that fails, create a new contact
console.log("Created " + recordId);
c = realm.create('Contact', {
name: name.toString(),
recordID: recordId.toString()
});
}
c.phones = [];
for (let i = 0, len = phones.length; i < len; i++) {
c.phones.push({
number: phones[i].toString()
});
}
// now run an update with the phone numbers
return realm.create('Contact', c, true);
};
return save();
}
}
My realm schema:
const PhoneNumberSchema = {
name: 'PhoneNumber',
properties: {
number: 'string'
}
};
const ContactSchema = {
name: 'Contact',
primaryKey: 'recordID',
properties: {
recordID: 'string',
name: {
type: 'string',
indexed: true
},
phones: {
type: 'list',
objectType: 'PhoneNumber'
}
}
};
Can anyone spot what am I doing wrong here that it takes so long for 100 contacts to be stored?
I am creating custom HTML page in rally tool to write the code to get the total number of days each story stayed in each state in the kanban board from the day it entered the state and till it leaves the state as shown below:[In the image, uid12 stayed in "ready state" State for 10 days and currently staying in "development state " state from last 2 days.. In story uid34,total number of days it took to complete all states is 32]. Can anyone please help me with this as i am new to rally.
1
Here is a js code based on AppSDK2 that can be compiled to html using rally-app-builder
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function(){
var context = this.getContext();
var project = context.getProject()['ObjectID'];
console.log(project);
var that = this;
var panel = Ext.create('Ext.panel.Panel', {
layout: 'hbox',
itemId: 'parentPanel',
componentCls: 'panel',
items: [
{
xtype: 'panel',
width: 600,
itemId: 'childPanel1'
},
{
xtype: 'panel',
width: 600,
itemId: 'childPanel2'
}
],
});
this.add(panel);
Ext.create('Rally.data.lookback.SnapshotStore', {
fetch : ['Name','c_KanbanState','_UnformattedID', '_TypeHierarchy'],
filters : [{
property : '__At',
value : 'current'
},
{
property : '_TypeHierarchy',
value : 'HierarchicalRequirement'
},
{
property : '_ProjectHierarchy',
value: project
},
{
property : 'c_KanbanState',
operator : 'exists',
value : true
}
],
hydrate: ['_TypeHierarchy', 'c_KanbanState'],
listeners: {
load: this.onStoriesLoaded,
scope: this
}
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
}
});
},
onStoriesLoaded: function(store, data){
var that = this;
var stories = [];
var id;
_.each(data, function(record) {
var artifactType = record.get('_TypeHierarchy');
if (artifactType[artifactType.length - 1] == "HierarchicalRequirement") {
id = 'US' + record.get('_UnformattedID');
} else if (artifactType[artifactType.length - 1] == "Defect") {
id = 'DE' + record.get('_UnformattedID');
}
stories.push({
Name: record.get('Name'),
FormattedID: id,
UnformattedID: record.get('_UnformattedID'),
c_KanbanState: record.get('c_KanbanState')
});
console.log(stories);
});
var myStore = Ext.create('Rally.data.custom.Store', {
data: stories
});
if (!this.down('#allStoriesGrid')) {
this.down('#childPanel1').add({
xtype: 'rallygrid',
id: 'allStoriesGrid',
store: myStore,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID',
},
{
text: 'Name', dataIndex: 'Name', flex: 1,
},
{
text: 'Current Kanban State', dataIndex: 'c_KanbanState'
}
],
listeners: {
cellclick: function( grid, td, cellIndex, record, tr, rowIndex){
id = grid.getStore().getAt(rowIndex).get('UnformattedID');
console.log('id', id);
that.getStoryModel(id);//to build a grid of Kanban allowed values
}
}
});
}else{
this.down('#allStoriesGrid').reconfigure(myStore);
}
},
getStoryModel:function(id){
var workspace = this.getContext().getWorkspaceRef();
var project = this.getContext().getProjectRef();
console.log('workspace',workspace);
console.log('project',project);
console.log('get story model');
var that = this;
this.arr=[];
Rally.data.ModelFactory.getModel({
type: 'User Story',
success: function(model){
var allowedValuesStore = model.getField('c_KanbanState').getAllowedValueStore( );
that.getDropdownValues(allowedValuesStore, id);
}
});
},
getDropdownValues:function(allowedValuesStore, id){
var that = this;
allowedValuesStore.load({
scope: this,
callback: function(records, operation, success){
_.each(records, function(val){
//AllowedAttributeValue object in WS API has StringValue
var v = val.get('StringValue');
that.arr.push(v);
});
console.log('arr', this.arr);
that.getStoryById(id);
}
});
},
getStoryById:function(id){
var that = this;
var snapStore = Ext.create('Rally.data.lookback.SnapshotStore', {
fetch: ['c_KanbanState', 'Blocked'],
hydrate:['c_KanbanState','Blocked'],
filters : [
{
property : '_UnformattedID',
value : id
}
],
sorters:[
{
property : '_ValidTo',
direction : 'ASC'
}
]
});
snapStore.load({
params: {
compress: true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
that.onDataLoaded(records, id);
}
});
},
onDataLoaded:function(records, id){
var times = [];
var measure = 'second';
//-----------------------ready
var ready = _.filter(records, function(record) {
return record.get('c_KanbanState') === 'ready';
});
var cycleTimeFromReadyToDev = '';
if (_.size(ready) > 0) {
var ready1 = _.first(ready);
var ready2 = _.last(ready);
var readyDate1 = new Date(ready1.get('_ValidFrom'));
if (ready2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
readyDate2 = new Date(); //now
}
else{
var readyDate2 = new Date(ready2.get('_ValidTo'));
}
cycleTimeFromReadyToDev = Rally.util.DateTime.getDifference(readyDate2,readyDate1, measure );
}
times.push(cycleTimeFromReadyToDev);
//----------------------dev
var dev = _.filter(records, function(record) {
return record.get('c_KanbanState') === 'dev';
});
var cycleTimeFromDevToDone = '';
if (_.size(dev) > 0) {
var dev1 = _.first(dev);
var dev2 = _.last(dev);
var devDate1 = new Date(dev1.get('_ValidFrom'));
if (dev2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
devDate2 = new Date(); //now
}
else{
var devDate2 = new Date(dev2.get('_ValidTo'));
}
cycleTimeFromInProgressToDone = Rally.util.DateTime.getDifference(devDate2,devDate1, measure );
}
times.push(cycleTimeFromDevToDone);
//------------------------done
var done = _.filter(records, function(record) {
return record.get('c_KanbanState') === 'done';
});
console.log('done',done);
var cycleTimeFromDoneToReleased = '';
if (_.size(done) > 0) {
var done1 = _.first(done);
var done2 = _.last(done);
var doneDate1 = new Date(done1.get('_ValidFrom'));
if (done2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
doneDate2 = new Date(); //now
}
else{
var doneDate2 = new Date(done2.get('_ValidTo'));
}
cycleTimeFromDoneToReleased = Rally.util.DateTime.getDifference(doneDate2,doneDate1, measure );
}
times.push(cycleTimeFromDoneToReleased);
//skip first '' element of the this.arr and last 'released' element of this.arr because
//do not care for cycle times in first and last kanban states
this.arrShortened = _.without(this.arr, _.first(this.arr),_.last(this.arr)) ;
cycleTimes = _.zip(this.arrShortened, times);
cycleTimes = _.object(cycleTimes);
var cycleTimesArray = [];
cycleTimesArray.push(cycleTimes);
var store = Ext.create('Rally.data.custom.Store',{
data: cycleTimesArray,
pageSize: 100
});
var columnConfig = [];
_.each(cycleTimes,function(c,key){
var columnConfigElement = _.object(['text', 'dataIndex', 'flex'], ['time spent in ' + key, key, 1]);
columnConfig.push(columnConfigElement);
});
var title = 'KanbanState cycle time for US' + id + ' in ' + measure + 's'
if (!this.grid) {
this.grid = this.down('#childPanel2').add({
xtype: 'rallygrid',
title: title,
itemId: 'grid2',
store: store,
columnCfgs: columnConfig
});
}
else{
this.down('#grid2').reconfigure(store);
}
}
});
You can use this example as a starting point. It builds a second grid of cycle times when a row in a first grid is clicked. The KanbanState field in my example has 'ready','dev' and 'done' allowed values
I'm new to Dojo and I'm making my first widget to be used in EPiServer CMS.
The widget is supposed to dynamically add contacts when clicking on a button. This means that the only control my templateString has is a button. When clicking on it I call a function that creates all of the other controls that will contain the contact infomation, such as name, email etc. This is working fine, I use domConstruct.create without a problem.
Thing is, when I want to create the existing contacts based on the value that comes from the server I can't manage to use domConstruct.create, it just returns "undefined". I'm making the call in the postCreate event which happens after the DOM is ready. (I've tested this as well). Does anyone have a clue what could be wrong? Like I said creating the controls when clicking on the Add button works like a charm.
The function that throws the error is:
postCreate: function () {
// call base implementation
this.inherited(arguments);
//this._loadContacts(this.value);
var node = domConstruct.create("fieldset", { id: "test" }, "cccp"); //this simple create instruction returns undefined here.
//Bind button
this.connect(this.btnAdd, "onclick", dojo.partial(this._createContact, new Object()));
},
Exactly on the line that does the domConstruct.create. Below is the entire code for the widget:
define([
"dojo/_base/array",
"dojo/_base/connect",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/dom-construct",
"dojo/on",
"dijit/_CssStateMixin",
"dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"epi/epi",
"epi/shell/widget/_ValueRequiredMixin"
],
function (
array,
connect,
declare,
lang,
domConstruct,
on,
_CssStateMixin,
_Widget,
_TemplatedMixin,
_WidgetsInTemplateMixin,
epi,
_ValueRequiredMixin
) {
var amountContacts = 0;
var contactContainerPrefixName = "contactInfo";
return declare("meridian.editors.StringList", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _CssStateMixin, _ValueRequiredMixin], {
templateString: "<div class=\"dijitInline\">\
<form id=\"cccp\" action=\"\">\
</form>\
<button id=\"btnAdd\" data-dojo-attach-point=\"btnAdd\" type=\"button\" class=\"\">Add Contact</button><br/> \
<span>${helptext}</span>\
</div>",
baseClass: "epiStringList",
helptext: "Place items on separate lines",
intermediateChanges: false,
value: null,
multiple: true,
onChange: function (value) { },
_onChange: function (value) {
this.onChange(value);
},
postCreate: function () {
// call base implementation
this.inherited(arguments);
//this._loadContacts(this.value);
var node = domConstruct.create("fieldset", { id: "test" }, "cccp"); //this simple create instruction returns undefined here.
//Bind button
this.connect(this.btnAdd, "onclick", dojo.partial(this._createContact, new Object()));
},
isValid: function () {
// summary:
// Check if widget's value is valid.
// tags:
// protected, override
return !this.required || lang.isArray(this.value) && this.value.length > 0 && this.value.join() != "";
},
_loadContacts:function(data)
{
for (var i = 0; i < data.length; i++) {
this._createContact(data[i]);
}
},
_createContact:function(data)
{
//increase the number of contacts
amountContacts++;
var contactInfoContainer = contactContainerPrefixName+amountContacts;
//Create container for contact data
var contactInfo = domConstruct.create("fieldset", { id: contactInfoContainer }, "cccp");
//Create container for PROPERTIES
var contactInfoProperties = domConstruct.create("div", {class: "properties"}, contactInfoContainer);
//Name
this._createTextbox("name", data.fullName, "Name", contactInfoProperties, false, false);
/*//Email
this._createTextbox("email", "Email", contactInfoProperties, false);
//Phone 1
this._createTextbox("phoneOne", "Phone 1", contactInfoProperties, true);
//Phone 2
this._createTextbox("phoneTwo", "Phone 2", contactInfoProperties, true);
//Fax
this._createTextbox("fax", "Fax", contactInfoProperties, false);
//Organization
this._createTextbox("organization", "Organization", contactInfoProperties, false);
//Department
this._createTextbox("department", "Department/Unit", contactInfoProperties, false);
//Role
this._createTextbox("role", "Role/Job title", contactInfoProperties, false);*/
//Website
this._createTextbox("website", data.website, "Website", contactInfoProperties, false, false);
//Address
//this._createTextbox("address", "Address", contactInfoProperties, false);
//TLP
this._createTLP_DDL("tlp", "TLP", contactInfoProperties);
//Create container for CATEGORIES
var contactInfoCategories = domConstruct.create("div", { class: "categories" }, contactInfoContainer);
//Categories heading
var p=domConstruct.create("p", { class: "heading" }, contactInfoCategories);
p.innerHTML = "Categories";
//Alert, Warning & Incident Response
this._createCategory("alert", contactInfoCategories, "Alert, Warning & Incident Response");
//Threat
this._createCategory("threat", contactInfoCategories, "Threat");
//Vulnerability
this._createCategory("vulnerability", contactInfoCategories, "Vulnerability");
//Industry
this._createCategory("industry", contactInfoCategories, "Industry");
//Policy
this._createCategory("policy", contactInfoCategories, "Policy");
//R & D
this._createCategory("rd", contactInfoCategories, "R & D");
//Sharing
this._createCategory("sharing", contactInfoCategories, "Sharing");
//Crime
this._createCategory("crime", contactInfoCategories, "Crime");
//SCADA/Process Control
this._createCategory("scada", contactInfoCategories, "SCADA/Process Control");
//Assurance
this._createCategory("assurance", contactInfoCategories, "Assurance");
//Standards
this._createCategory("standards", contactInfoCategories, "Standards");
//Resilience
this._createCategory("resilience", contactInfoCategories, "Resilience");
//Exercises
this._createCategory("exercises", contactInfoCategories, "Exercises");
//Defence
this._createCategory("defence", contactInfoCategories, "Defence");
//Media handling
this._createCategory("media", contactInfoCategories, "Media handling");
//General PoC
this._createCategory("poc", contactInfoCategories, "General PoC");
//Add remove button
var btnRemove = domConstruct.create("input", { type: "button", id: "btnRemove" + amountContacts, value: "Remove"/*,onclick:"_deleteContact(this)"*/ }, contactInfo);
this.connect(btnRemove, "onclick", dojo.partial(this._deleteContact, btnRemove.id));
},
_createTextbox:function(id, textBoxValue, labelText, parent, checkbox, checkboxChecked)
{
var currentId = id+amountContacts;
var textboxContainer = domConstruct.create("div", {class:"form-item"}, parent);
this._createLabel(currentId, textboxContainer, labelText);
//Create textbox and attach update handler
var textbox = domConstruct.create("input", { type: "text", id: currentId, name: currentId }, textboxContainer);
if (textBoxValue)
textbox.value = textBoxValue;
this.connect(textbox, "onchange", this._updateValue);
if (checkbox) {
this._createCheckbox("inline", textboxContainer, currentId + "_24", "24/7?");
}
},
_createTLP_DDL:function(id, labelText, parent)
{
var currentId = id+amountContacts;
var ddlContainer = domConstruct.create("div", { class: "form-item" }, parent);
this._createLabel(currentId, ddlContainer, labelText);
var ddl = domConstruct.create("select", { name: currentId, id: currentId }, ddlContainer);
//Add options
var option1 = domConstruct.create("option", { val: "-1" }, ddl);
option1.innerHTML = "None";
var option1 = domConstruct.create("option", { val: "1" }, ddl);
option1.innerHTML = "Yes";
var option1 = domConstruct.create("option", { val: "0" }, ddl);
option1.innerHTML = "No";
},
_createCategory:function(id, parent, checkboxText)
{
var currentId = id + amountContacts;
var categoryContainer = domConstruct.create("div", { class: "form-item inline" }, parent);
this._createCheckbox("", categoryContainer, currentId, checkboxText);
},
_createLabel:function(forId, container, labelText)
{
var label = domConstruct.create("label", { for: forId }, container);
label.innerHTML = labelText;
},
_createCheckbox:function(labelClass, container, checkboxId, checkboxText){
var labelCheckbox = domConstruct.create("label", { class: labelClass }, container);
//Create checkbox and attach update handler
var checkbox = domConstruct.create("input", { type: "checkbox", id: checkboxId, name: checkboxId }, labelCheckbox);
this.connect(checkbox, "onchange", this._updateValue);
var span = domConstruct.create("span", {}, labelCheckbox);
span.innerHTML = checkboxText;
},
_deleteContact:function(targetBtnId)
{
var userInput = window.confirm("Are you sure you want to delete this contact?");
if (userInput) {
dojo.destroy(contactContainerPrefixName+targetBtnId[targetBtnId.length-1]);
}
},
_updateValue: function () {
//TODO: Delete test data
var contacts = [];
//The amount of contacts can have changed after deletions, so the global variables might not hold the real value
var actualAmountContacts = 0;
for (var i = 1; i <= amountContacts; i++) {
if (this._isValidContact(i)) {
var currentContact = new Object();
currentContact.fullName = this._getValueById("name" + i);
currentContact.website = this._getValueById("website" + i);
contacts[actualAmountContacts] = currentContact;
actualAmountContacts++;
}
}
this._set("value", contacts);
this.onChange(contacts);
},
_getValueById: function (id) {
var node = dojo.byId(id);
var textValue = (node != null) ? node.value : "";
return textValue;
},
_isValidContact:function(itemNumber){
//If there's no name or telephone then it's not a valid contact
return (this._getValueById("name" + itemNumber) != "" || this._getValueById("phoneOne" + itemNumber) != "" || this._getValueById("phoneTwo" + itemNumber) != "");
},
});
});
UPDATE:
After a lot of test I've realized it's not the domConstruct.create statement which causes the error, the problem is that the form element that has "id:cccp" and to which I want to attach the created elements is null at this point. It is defined in the templateString as you can see in the source code but it's still null in the postCreate method. So the question is now, what event gets triggered when the HTML in the templateString is loaded?
In the end I solved the problem, so I write the workaround here and I hope it helps somebody!
I changed the templateString and added the attribute data-dojo-attach-point=\"form\" to the form that was not being found. Then in the postCreate method I accessed the form using this (this.form ), which worked without a problem. The final implementation for the function turned out as follows:
postCreate: function () {
// call base implementation
this.inherited(arguments);
//this._loadContacts(this.value);
var node = domConstruct.create("fieldset", { id: "test" }, this.form); //this simple create instruction returns undefined here.
//Bind button
this.connect(this.btnAdd, "onclick", dojo.partial(this._createContact, new Object()));
},
I still don't understand why dojo.byId("cccp") would return null, but I'm happy I found a workaround that solved the problem. Cheers!
Is there a way to calculate the number of days since the card has been in the first state? Lets use say I use a custom field \for the kanban states. 1,2,3,4 If a card is in state 3 then how long has it been since # 1?
I am not sure of a way to automate it or flag items but if you review the US/DE in question just take a quick look at the revision history.
Any changes in state should be logged in the history.
Use Lookback API to access historic data.
Lookback API allows to see what any work item or collection of work items looked like in the past. This is different from using WS API directly, which can provide you with the current state of objects, but does not have historical data.
LBAPI documentation is available here
Here is an example that builds a grid of stories with a Kanban state. When a story's row is double-clicked, the time this story has spent in three Kanban states is calculated and a grid is built to show the values:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function(){
var x = Ext.create('Rally.data.lookback.SnapshotStore', {
fetch : ['Name','c_Kanban','_UnformattedID', '_TypeHierarchy'],
filters : [{
property : '__At',
value : 'current'
},
{
property : '_TypeHierarchy',
value : 'HierarchicalRequirement'
},
{
property : '_ProjectHierarchy',
value : 22222
},
{
property : 'c_Kanban', //get stories with Kanban state
operator : 'exists',
value : true
}
],
hydrate: ['_TypeHierarchy', 'c_Kanban'],
listeners: {
load: this.onStoriesLoaded,
scope: this
}
}).load({
params : {
compress : true,
removeUnauthorizedSnapshots : true
}
});
},
//make grid of stories with Kanban state
onStoriesLoaded: function(store, data){
var that = this;
var stories = [];
var id;
Ext.Array.each(data, function(record) {
var artifactType = record.get('_TypeHierarchy');
if (artifactType[artifactType.length - 1] == "HierarchicalRequirement") {
id = 'US' + record.get('_UnformattedID');
} else if (artifactType[artifactType.length - 1] == "Defect") {
id = 'DE' + record.get('_UnformattedID');
}
stories.push({
Name: record.get('Name'),
FormattedID: id,
UnformattedID: record.get('_UnformattedID'),
c_Kanban: record.get('c_Kanban')
});
console.log(stories);
});
var myStore = Ext.create('Rally.data.custom.Store', {
data: stories
});
if (!this.down('#allStoriesGrid')) {
this.add({
xtype: 'rallygrid',
id: 'allStoriesGrid',
store: myStore,
width: 500,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID',
},
{
text: 'Name', dataIndex: 'Name', flex: 1,
},
{
text: 'Kanban', dataIndex: 'c_Kanban'
}
],
listeners: {
celldblclick: function( grid, td, cellIndex, record, tr, rowIndex){
id = grid.getStore().getAt(rowIndex).get('UnformattedID');
console.log('id', id);
that.getStoryModel(id); //to eventually build a grid of Kanban allowed values
}
}
});
}else{
this.down('#allStoriesGrid').reconfigure(myStore);
}
},
getStoryModel:function(id){
console.log('get story model');
var that = this;
this.arr=[];
//get a model of user story
Rally.data.ModelFactory.getModel({
type: 'User Story',
context: {
workspace: '/workspace/11111',
project: 'project/22222'
},
success: function(model){
//Get store instance for the allowed values
var allowedValuesStore = model.getField('c_Kanban').getAllowedValueStore( );
that.getDropdownValues(allowedValuesStore, id);
}
});
},
getDropdownValues:function(allowedValuesStore, id){
var that = this;
//load data into the store
allowedValuesStore.load({
scope: this,
callback: function(records, operation, success){
_.each(records, function(val){
//AllowedAttributeValue object in WS API has StringValue
var v = val.get('StringValue');
that.arr.push(v);
});
console.log('arr', this.arr);
that.getStoryById(id); //former makeStore
}
});
},
getStoryById:function(id){
var that = this;
var snapStore = Ext.create('Rally.data.lookback.SnapshotStore', {
fetch: ['c_Kanban', 'Blocked'],
hydrate:['c_Kanban','Blocked'],
filters : [
{
property : '_UnformattedID',
value : id //15
}
],
sorters:[
{
property : '_ValidTo',
direction : 'ASC'
}
]
});
snapStore.load({
params: {
compress: true,
removeUnauthorizedSnapshots : true
},
callback : function(records, operation, success) {
that.onDataLoaded(records, id);
}
});
},
onDataLoaded:function(records, id){
var times = [];
var measure = 'second';
//-----------------------backlog
var backlog = _.filter(records, function(record) {
return record.get('c_Kanban') === 'backlog';
});
console.log('backlog',backlog);
var cycleTimeFromBacklogToInProgress = '';
if (_.size(backlog) > 0) {
var backlog1 = _.first(backlog);
var backlog2 = _.last(backlog);
var backlogDate1 = new Date(backlog1.get('_ValidFrom'));
if (backlog2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
backlogDate2 = new Date(); //now
}
else{
var backlogDate2 = new Date(backlog2.get('_ValidTo'));
}
cycleTimeFromBacklogToInProgress = Rally.util.DateTime.getDifference(backlogDate2,backlogDate1, measure );
}
times.push(cycleTimeFromBacklogToInProgress);
//console.log(cycleTimeFromBacklogToInProgress);
//----------------------in progress
var inProgress = _.filter(records, function(record) {
return record.get('c_Kanban') === 'in-progress';
});
console.log('in-progress',inProgress);
var cycleTimeFromInProgressToDone = '';
if (_.size(inProgress) > 0) {
var inProgress1 = _.first(inProgress);
var inProgress2 = _.last(inProgress);
var inProgressDate1 = new Date(inProgress1.get('_ValidFrom'));
if (inProgress2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
inProgressDate2 = new Date(); //now
}
else{
var inProgressDate2 = new Date(inProgress2.get('_ValidTo'));
}
cycleTimeFromInProgressToDone = Rally.util.DateTime.getDifference(inProgressDate2,inProgressDate1, measure );
}
times.push(cycleTimeFromInProgressToDone);
//console.log(cycleTimeFromInProgressToDone);
//------------------------done
var done = _.filter(records, function(record) {
return record.get('c_Kanban') === 'done';
});
console.log('done',done);
var cycleTimeFromDoneToReleased = '';
if (_.size(done) > 0) {
var done1 = _.first(done);
var done2 = _.last(done);
var doneDate1 = new Date(done1.get('_ValidFrom'));
if (done2.get('_ValidTo') === "9999-01-01T00:00:00.000Z") { //infinity
doneDate2 = new Date(); //now
}
else{
var doneDate2 = new Date(done2.get('_ValidTo'));
}
cycleTimeFromDoneToReleased = Rally.util.DateTime.getDifference(doneDate2,doneDate1, measure );
}
times.push(cycleTimeFromDoneToReleased);
//console.log(cycleTimeFromDoneToReleased);
/**********
skip first '' element of the this.arr and last 'released' element of this.arr because
do not care for cycle times in first and last kanban states
Originally: arr ["", "backlog", "in-progress", "done", "released"] ,shorten to: ["backlog", "in-progress", "done"]
**********/
this.arrShortened = _.without(this.arr, _.first(this.arr),_.last(this.arr)) ;
console.log('this.arrShortened with first and last skipped', this.arrShortened); //["backlog", "in-progress", "done"]
cycleTimes = _.zip(this.arrShortened, times);
//console.log('cycleTimes as multi-dimentional array', cycleTimes);
cycleTimes = _.object(cycleTimes);
//console.log('cycleTimes as object', cycleTimes); //cycleTimes as object Object {backlog: 89, in-progress: 237, done: 55}
var cycleTimesArray = [];
cycleTimesArray.push(cycleTimes);
console.log('cycleTimesArray',cycleTimesArray);
var store = Ext.create('Rally.data.custom.Store',{
data: cycleTimesArray,
pageSize: 100
});
var columnConfig = [];
_.each(cycleTimes,function(c,key){
var columnConfigElement = _.object(['text', 'dataIndex', 'flex'], ['time spent in ' + key, key, 1]);
columnConfig.push(columnConfigElement);
});
var title = 'Kanban cycle time for US' + id + ' in ' + measure + 's'
if (!this.grid) {
this.grid = this.add({
xtype: 'rallygrid',
title: title,
width: 500,
itemId: 'grid2',
store: store,
columnCfgs: columnConfig
});
}
else{
this.down('#grid2').reconfigure(store);
}
}
});