Added ts file for bun testing

Added http to text area box

Moved CoD column to match query

Alignment
This commit is contained in:
2025-07-18 14:29:21 -07:00
parent c5d86f3c43
commit 74461c147d
20 changed files with 973 additions and 169 deletions

View File

@ -31,16 +31,16 @@ function compareFunctionWeightedShortestJobFirst(a, b) {
function getState(state) {
let result;
if (state == undefined)
result = "9-Null";
else if (state === "New")
result = '9-Null';
else if (state === 'New')
result = `1-${state}`;
else if (state === "Active")
else if (state === 'Active')
result = `2-${state}`;
else if (state === "Resolved")
else if (state === 'Resolved')
result = `3-${state}`;
else if (state === "Closed")
else if (state === 'Closed')
result = `4-${state}`;
else if (state === "Removed")
else if (state === 'Removed')
result = `5-${state}`;
else
result = `8-${state}`;
@ -49,10 +49,10 @@ function getState(state) {
function getPriority(workItemType, priority, sortPriorityGroup) {
let result;
if (workItemType === "Bug")
result = "0-Bug {0}";
if (workItemType === 'Bug')
result = '0-Bug {0}';
else if (priority == undefined || priority === 0)
result = "9-Null {0}";
result = '9-Null {0}';
else if (priority === 1)
result = `${priority}-High {${sortPriorityGroup}}`;
else if (priority === 2)
@ -62,31 +62,31 @@ function getPriority(workItemType, priority, sortPriorityGroup) {
else if (priority === 4)
result = `${priority}-TBD {4}`;
else
result = "8-Not {0}";
result = '8-Not {0}';
return result;
}
function getNotifications(x, aggregation) {
let result;
if (aggregation == undefined || aggregation.Notifications == undefined || aggregation.Notifications.length === 0)
result = " ";
result = ' ';
else {
result = '';
aggregation.Notifications.forEach(element => {
const username = element.username == null ? 'user' : element.username;
if (element.value === "1") {
if (element.value === '1') {
result += 'Highest:' + username + ';|';
}
else if (element.value === "2") {
else if (element.value === '2') {
result += 'High:' + username + ';|';
}
else if (element.value === "3") {
else if (element.value === '3') {
result += 'Medium:' + username + ';|';
}
else if (element.value === "4") {
else if (element.value === '4') {
result += 'Low:' + username + ';|';
}
else if (element.value === "5") {
else if (element.value === '5') {
result += 'Lowest:' + username + ';|';
}
else {
@ -103,6 +103,10 @@ function round(value, factor) {
return (Math.round((value + Number.EPSILON) * factor) / factor).toFixed(2);
}
function roundMultiply(value, factor, multiply) {
return (Math.round((value + Number.EPSILON) * factor) / factor) * multiply;
}
function sum(collection) {
let sum = 0;
if (collection != undefined) {
@ -117,38 +121,91 @@ function updateRecordCoD(b, r, t, c, e, w, workItem, highestTotalStoryPoints, da
if (workItem != undefined) {
let data = dataB == undefined ? undefined : dataB[workItem.Id];
if (data == undefined) {
workItem.CumulativeStoryPoints = " ";
workItem.TotalStoryPoints = " ";
workItem.AbsoluteDelta = " ";
workItem.Effort = " ";
workItem.BusinessValue = " ";
workItem.TimeCriticality = " ";
workItem.RiskReductionMinusOpportunityEnablement = " ";
workItem.CoD = " ";
workItem.WeightedShortestJobFirst = " ";
workItem.api = '';
workItem.CumulativeStoryPoints = ' ';
workItem.TotalStoryPoints = ' ';
workItem.AbsoluteDelta = ' ';
workItem.Effort = ' ';
workItem.BusinessValue = ' ';
workItem.TimeCriticality = ' ';
workItem.RiskReductionMinusOpportunityEnablement = ' ';
workItem.CoD = ' ';
workItem.WeightedShortestJobFirst = ' ';
workItem.Priority = getPriority(workItem.WorkItemType, 4, 0);
workItem.EffortNotifications = " ";
workItem.BusinessValueNotifications = " ";
workItem.TimeCriticalityNotifications = " ";
workItem.RiskReductionMinusOpportunityEnablementNotifications = " ";
workItem.EffortNotifications = ' ';
workItem.BusinessValueNotifications = ' ';
workItem.TimeCriticalityNotifications = ' ';
workItem.RiskReductionMinusOpportunityEnablementNotifications = ' ';
workItem.SortOrder = 0;
}
else {
workItem.CumulativeStoryPoints = " ";
let effort = workItem.Effort;
let businessValue = workItem.BusinessValue;
let timeCriticality = workItem.TimeCriticality;
let riskReductionMinusOpportunityEnablement = workItem.RiskReductionMinusOpportunityEnablement;
let weightedShortestJobFirst = workItem.WeightedShortestJobFirst == undefined ? null : workItem.WeightedShortestJobFirst.toFixed(2);
workItem.CumulativeStoryPoints = ' ';
workItem.TotalStoryPoints = totalStoryPoints + ' User Story Point(s)';
workItem.AbsoluteDelta = data.Effort == undefined || data.Effort.FibonacciAverage == undefined || totalStoryPoints == undefined || totalStoryPoints === 0 ? " " : round(Math.abs(data.Effort.FibonacciAverage - ((totalStoryPoints / highestTotalStoryPoints) * 5)), 1);
workItem.Effort = data.Effort == undefined || data.Effort.FibonacciAverage == undefined ? " " : round(data.Effort.FibonacciAverage, 100);
workItem.BusinessValue = data.BusinessValue == undefined || data.BusinessValue.FibonacciAverage == undefined ? " " : round(data.BusinessValue.FibonacciAverage, 100);
workItem.TimeCriticality = data.TimeCriticality == undefined || data.TimeCriticality.FibonacciAverage == undefined ? " " : round(data.TimeCriticality.FibonacciAverage, 100);
workItem.RiskReductionMinusOpportunityEnablement = data.RiskReductionOpportunityEnablement == undefined || data.RiskReductionOpportunityEnablement.FibonacciAverage == undefined ? " " : round(data.RiskReductionOpportunityEnablement.FibonacciAverage, 100);
workItem.CoD = data.CostOfDelay == undefined ? " " : round(data.CostOfDelay, 100);
workItem.WeightedShortestJobFirst = data.WeightedShortestJobFirst == undefined ? " " : round(data.WeightedShortestJobFirst, 100);
workItem.AbsoluteDelta = data.Effort == undefined || data.Effort.FibonacciAverage == undefined || totalStoryPoints == undefined || totalStoryPoints === 0 ? ' ' : round(Math.abs(data.Effort.FibonacciAverage - ((totalStoryPoints / highestTotalStoryPoints) * 5)), 1);
workItem.Effort = data.Effort == undefined || data.Effort.FibonacciAverage == undefined ? ' ' : roundMultiply(data.Effort.FibonacciAverage, 100, 100);
workItem.BusinessValue = data.BusinessValue == undefined || data.BusinessValue.FibonacciAverage == undefined ? ' ' : roundMultiply(data.BusinessValue.FibonacciAverage, 100, 100);
workItem.TimeCriticality = data.TimeCriticality == undefined || data.TimeCriticality.FibonacciAverage == undefined ? ' ' : roundMultiply(data.TimeCriticality.FibonacciAverage, 100, 100);
workItem.RiskReductionMinusOpportunityEnablement = data.RiskReductionOpportunityEnablement == undefined || data.RiskReductionOpportunityEnablement.FibonacciAverage == undefined ? ' ' : roundMultiply(data.RiskReductionOpportunityEnablement.FibonacciAverage, 100, 100);
workItem.CoD = data.CostOfDelay == undefined ? ' ' : roundMultiply(data.CostOfDelay, 100, 100);
workItem.WeightedShortestJobFirst = data.WeightedShortestJobFirst == undefined ? ' ' : round(data.WeightedShortestJobFirst, 100);
workItem.Priority = data.SortPriority == undefined ? getPriority(workItem.WorkItemType, 4, 0) : getPriority(workItem.WorkItemType, data.SortPriority, data.SortPriorityGroup);
workItem.EffortNotifications = data.Effort == undefined ? " " : getNotifications(e, data.Effort);
workItem.BusinessValueNotifications = data.BusinessValue == undefined ? " " : getNotifications(b, data.BusinessValue);
workItem.TimeCriticalityNotifications = data.TimeCriticality == undefined ? " " : getNotifications(t, data.TimeCriticality);
workItem.RiskReductionMinusOpportunityEnablementNotifications = data.RiskReductionOpportunityEnablement == undefined ? " " : getNotifications(r, data.RiskReductionOpportunityEnablement);
workItem.EffortNotifications = data.Effort == undefined ? ' ' : getNotifications(e, data.Effort);
workItem.BusinessValueNotifications = data.BusinessValue == undefined ? ' ' : getNotifications(b, data.BusinessValue);
workItem.TimeCriticalityNotifications = data.TimeCriticality == undefined ? ' ' : getNotifications(t, data.TimeCriticality);
workItem.RiskReductionMinusOpportunityEnablementNotifications = data.RiskReductionOpportunityEnablement == undefined ? ' ' : getNotifications(r, data.RiskReductionOpportunityEnablement);
workItem.SortOrder = data.SortOrder == undefined ? 0 : data.SortOrder;
let check = effort == workItem.Effort
&& businessValue === workItem.BusinessValue
&& timeCriticality === workItem.TimeCriticality
&& riskReductionMinusOpportunityEnablement === workItem.RiskReductionMinusOpportunityEnablement;
if (check && weightedShortestJobFirst == workItem.WeightedShortestJobFirst) {
workItem.api = '';
} else {
workItem.api = `
### Work Item Patch ${check} WSJF ${workItem.Id} ${weightedShortestJobFirst} != ${workItem.WeightedShortestJobFirst}
patch {{Factory-Integration}}/_apis/wit/workitems/${workItem.Id}?api-version=7.0
Authorization: Basic {{PAT}}
Content-Type: application/json-patch+json
[
{
"op": "replace",
"path": "/fields/Microsoft.VSTS.Common.BusinessValue",
"value": "${workItem.BusinessValue}"
},
{
"op": "replace",
"path": "/fields/Microsoft.VSTS.Scheduling.Effort",
"value": "${workItem.Effort}"
},
{
"op": "replace",
"path": "/fields/Custom.RRminusOE",
"value": "${workItem.RiskReductionMinusOpportunityEnablement}"
},
{
"op": "replace",
"path": "/fields/Microsoft.VSTS.Common.TimeCriticality",
"value": "${workItem.TimeCriticality}"
},
{
"op": "replace",
"path": "/fields/Custom.WSJF",
"value": "${workItem.WeightedShortestJobFirst}"
},
{
"op": "replace",
"path": "/fields/Custom.WSJFFib",
"value": "${workItem.WeightedShortestJobFirst}"
}
]`;
}
}
}
}
@ -181,7 +238,7 @@ function getRecords(b, r, t, c, e, w, data, dataB, workItems) {
continue;
if (workItem.State !== 'Active' && workItem.State !== 'New')
continue;
if (workItem.Tags != null && workItem.Tags.includes("Ignore"))
if (workItem.Tags != null && workItem.Tags.includes('Ignore'))
continue;
storyPoints = data[i].Tag?.StoryPoints == undefined ? null : JSON.parse(data[i].Tag.StoryPoints);
totalStoryPoints = sum(storyPoints);
@ -195,7 +252,7 @@ function getRecords(b, r, t, c, e, w, data, dataB, workItems) {
continue;
if (workItem.State !== 'Active' && workItem.State !== 'New')
continue;
if (workItem.Tags != null && workItem.Tags.includes("Ignore"))
if (workItem.Tags != null && workItem.Tags.includes('Ignore'))
continue;
storyPoints = data[i].Tag?.StoryPoints == undefined ? null : JSON.parse(data[i].Tag.StoryPoints);
totalStoryPoints = sum(storyPoints);
@ -236,12 +293,12 @@ function sendValue(fromHtml, element, page, id) {
username: _username,
value: element.value,
};
if (fromHtml && notification.value !== "9") {
$("#AllTextarea").hide();
if (fromHtml && notification.value !== '9') {
$('#AllTextarea').hide();
document.getElementById('AllTextarea').value = '';
$.post(_apiUrl, notification)
.done(function (msg) {
console.log("Posted value of " + notification.value + " for " + id + " on page " + page + " " + msg);
console.log('Posted value of ' + notification.value + ' for ' + id + ' on page ' + page + ' ' + msg);
})
.fail(function (_, textStatus, _) {
warn(textStatus);
@ -249,22 +306,26 @@ function sendValue(fromHtml, element, page, id) {
}
}
function setRecords(fromHtml, b, r, t, c, e, w, records) {
function getHtmlTextAndHttp(fromHtml, b, r, t, c, e, w, records) {
let record;
let lineA = "";
let lineB = "";
let lineC = "";
let text = 'Id\tRisk Reduction and/or Opportunity Enablement\tTime Criticality\tBusiness Value\tCoD\tEffort\tWSJF\tFeature Total Story Points\tAbsolute Delta\tState\tRequester\tAssigned To\tIteration Path\tSystem\tTitle\r\n';
let http = '';
let lineA = '';
let lineB = '';
let lineC = '';
let text = 'Id\tRisk Reduction and/or Opportunity Enablement\tTime Criticality\tBusiness Value\tEffort\tWSJF\tCoD\tFeature Total Story Points\tAbsolute Delta\tState\tRequester\tAssigned To\tIteration Path\tSystem\tTitle-123\r\n';
let html = '<tr><th>Parent Id</th><th>Parent Title</th><th>Id</th><th>Requester</th><th>Title</th><th>Assigned To</th><th>System(s)</th><th>State</th><th>Priority</th><th>Risk Reduction and/or Opportunity Enablement</th><th>Time Criticality</th><th>Business Value</th><th>Cost of Delay (CoD)</th><th>Effort</th><th>WSJF</th></tr>';
for (let i = 0; i < records.length; i++) {
record = records[i];
if (record.api !== '') {
http += record.api + '\r\n';
}
text += record.Id + '\t' +
record.RiskReductionMinusOpportunityEnablement + '\t' +
record.TimeCriticality + '\t' +
record.BusinessValue + '\t' +
record.CoD + '\t' +
record.Effort + '\t' +
record.WeightedShortestJobFirst + '\t' +
record.CoD + '\t' +
record.TotalStoryPoints.split(' ')[0] + '\t' +
record.AbsoluteDelta + '\t' +
record.State.split('-')[0] + '\t' +
@ -331,17 +392,7 @@ function setRecords(fromHtml, b, r, t, c, e, w, records) {
console.log(text);
html += lineA + lineB + lineC;
}
if (fromHtml) {
document.getElementById('HeaderGrid').innerHTML = html.replaceAll('>null<', '>&nbsp;<');
if (_windowLocationHRef.indexOf('=WSJF') === -1) {
document.getElementById('AllTextarea').value = text.replaceAll('null', '').replaceAll('&nbsp;', '');
}
else {
_toggle = !_toggle;
$(".select").hide();
$("#AllTextarea").hide();
}
}
return { html, text, http };
}
function updateSite(c, w) {
@ -379,25 +430,36 @@ function setDocument(fromHtml, b, r, t, c, e, w, dataA, dataB, workItems) {
console.log(dataA.length);
if (dataA.length > 0)
console.log(dataA[0]);
setRecords(fromHtml, b, r, t, c, e, w, records);
$("#toggle").click(function () {
let result = getHtmlTextAndHttp(fromHtml, b, r, t, c, e, w, records);
if (fromHtml) {
document.getElementById('HeaderGrid').innerHTML = result.html.replaceAll('>null<', '>&nbsp;<');
if (_windowLocationHRef.indexOf('=WSJF') === -1) {
document.getElementById('AllTextarea').value = result.text.replaceAll('null', '').replaceAll('&nbsp;', '') + result.http;
}
else {
_toggle = !_toggle;
$('.select').hide();
$('#AllTextarea').hide();
}
}
$('#toggle').click(function () {
if (_toggle)
$(".select").hide();
$('.select').hide();
else
$(".select").show();
$('.select').show();
_toggle = !_toggle;
});
}
function highlight(el, i) {
el.before("<tr/>")
el.before('<tr/>')
el.prev()
.width(el.width())
.height(el.height())
.css({
"position": "absolute",
"background-color": "#ffff99",
"opacity": ".9"
'position': 'absolute',
'background-color': '#ffff99',
'opacity': '.9'
})
.fadeOut(1000 * i);
}
@ -423,9 +485,9 @@ function updateWorkItem(b, r, t, c, e, w, page, workItem) {
aggregation = workItem.Effort;
}
if (x == undefined)
warn("Error with page!");
warn('Error with page!');
else if (aggregation.FibonacciAverage == undefined)
warn("FibonacciAverage not set!");
warn('FibonacciAverage not set!');
else {
$('#' + x.page + workItem.Id).text('!' + round(aggregation.FibonacciAverage, 100));
if (workItem.WeightedShortestJobFirst != undefined) {
@ -437,7 +499,7 @@ function updateWorkItem(b, r, t, c, e, w, page, workItem) {
if (_windowLocationHRef.indexOf('=LIVE') > -1) {
if (workItem.SortBeforeId != undefined) {
let found = 0;
let row = element.parents("tr:first");
let row = element.parents('tr:first');
let next = row;
for (let i = 0; i < 150; i++) {
next = next.next();
@ -445,7 +507,7 @@ function updateWorkItem(b, r, t, c, e, w, page, workItem) {
break;
if (next.attr('id') != 'tr' + workItem.SortBeforeId)
continue;
console.log("Moved " + i + " down");
console.log('Moved ' + i + ' down');
row.insertAfter(next);
found = i;
break;
@ -458,7 +520,7 @@ function updateWorkItem(b, r, t, c, e, w, page, workItem) {
break;
if (prev.attr('id') != 'tr' + workItem.SortBeforeId)
continue;
console.log("Moved " + i + " up");
console.log('Moved ' + i + ' up');
row.insertAfter(prev);
found = i;
break;
@ -468,7 +530,7 @@ function updateWorkItem(b, r, t, c, e, w, page, workItem) {
highlight(row, found);
}
else {
console.log("Not found!");
console.log('Not found!');
}
}
}
@ -519,7 +581,7 @@ function initIndex(fromHtml, username, machineId, windowLocationHRef, workItems,
console.log(r);
console.log(t);
console.log(c);
console.log("Done :)");
console.log('Done :)');
}
else {
updateSite(c, w);
@ -550,40 +612,40 @@ if (typeof document == 'undefined') {
timeout: 3000,
};
const b = {
page: "business",
description: "Value",
th: "Business Value",
span: "What is the relative value to the Customer or business?<br>• Do our users prefer this over that?<br>• What is the revenue impact on our business?<br>• Is there a potential penalty or other negative effects if we delay?"
page: 'business',
description: 'Value',
th: 'Business Value',
span: 'What is the relative value to the Customer or business?<br>• Do our users prefer this over that?<br>• What is the revenue impact on our business?<br>• Is there a potential penalty or other negative effects if we delay?'
};
const r = {
page: "risk",
description: "Risk",
th: "Risk Reduction and/or Opportunity Enablement",
span: "What else does this do for our business?<br>• Reduce the risk of this or future delivery?<br>• Is there value in the information we will receive?<br>• Enable new business opportunities?"
page: 'risk',
description: 'Risk',
th: 'Risk Reduction and/or Opportunity Enablement',
span: 'What else does this do for our business?<br>• Reduce the risk of this or future delivery?<br>• Is there value in the information we will receive?<br>• Enable new business opportunities?'
};
const t = {
page: "time",
description: "Critical",
th: "Time Criticality",
span: "How does user/business value decay over time?<br>• Is there a fixed deadline?<br>• Will they wait for us or move to another Solution?<br>• What is the current effect on Customer satisfaction?"
page: 'time',
description: 'Critical',
th: 'Time Criticality',
span: 'How does user/business value decay over time?<br>• Is there a fixed deadline?<br>• Will they wait for us or move to another Solution?<br>• What is the current effect on Customer satisfaction?'
};
const c = {
page: "cod",
description: "CoD",
th: "Cost of Delay (CoD)",
page: 'cod',
description: 'CoD',
th: 'Cost of Delay (CoD)',
span: "Cost of Delay (CoD) is the money lost by delaying or not doing a job for a specific time. It's a measure of the economic value of a job over time."
};
const e = {
page: "effort",
description: "Effort",
th: "Effort",
span: "Effort"
page: 'effort',
description: 'Effort',
th: 'Effort',
span: 'Effort'
};
const w = {
page: "wsjf",
description: "WSJF",
th: "Weightest Shortest Job First calculation (WSJF)",
span: "Weightest Shortest Job First calculation (see @SCALE formula)"
page: 'wsjf',
description: 'WSJF',
th: 'Weightest Shortest Job First calculation (WSJF)',
span: 'Weightest Shortest Job First calculation (see @SCALE formula)'
};
_windowLocationHRef = windowLocationHRef;
fetch(workItems.b, { _: new Date().getTime() })
@ -597,7 +659,8 @@ if (typeof document == 'undefined') {
if (dataA.length > 0)
console.log(dataA[0]);
const records = getRecords(b, r, t, c, e, w, dataA, dataB, workItems);
setRecords(fromHtml, b, r, t, c, e, w, records);
let result = getHtmlTextAndHttp(fromHtml, b, r, t, c, e, w, records);
if (result == undefined) { }
initIndex(fromHtml, username, machineId, windowLocationHRef, workItems, b, r, t, c, e, w, apiUrl, signalRUrl);
})
.catch((e) => console.error(e));