From 74461c147d0d48a119908bce001864ddae8a5353 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Fri, 18 Jul 2025 14:29:21 -0700 Subject: [PATCH] Added ts file for bun testing Added http to text area box Moved CoD column to match query Alignment --- .gitignore | 3 + Adaptation/.vscode/download-work-items.http | 21 - Adaptation/.vscode/launch.json | 32 +- Adaptation/.vscode/settings.json | 5 +- Adaptation/.vscode/tfs.http | 160 +++++++ Adaptation/FileHandlers/APC/FileRead.cs | 2 +- Adaptation/FileHandlers/Archive/FileRead.cs | 2 +- Adaptation/FileHandlers/IQSSi/FileRead.cs | 2 +- .../FileHandlers/OpenInsight/FileRead.cs | 2 +- .../OpenInsightMetrologyViewer/FileRead.cs | 2 +- .../FileRead.cs | 2 +- Adaptation/FileHandlers/Processed/FileRead.cs | 2 +- Adaptation/FileHandlers/SPaCe/FileRead.cs | 2 +- .../json/StaticSite/js/cod-1-123-0-.ts | 433 ++++++++++++++++++ .../json/StaticSite/js/cod-1-123-0.js | 267 ++++++----- Adaptation/MESAFIBACKLOG.yml | 36 ++ Adaptation/Shared/FileRead.cs | 27 +- .../Shared/ProcessDataStandardFormat.cs | 103 ++++- Adaptation/package.json | 10 + Adaptation/tsconfig.json | 29 ++ 20 files changed, 973 insertions(+), 169 deletions(-) delete mode 100644 Adaptation/.vscode/download-work-items.http create mode 100644 Adaptation/.vscode/tfs.http create mode 100644 Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0-.ts create mode 100644 Adaptation/tsconfig.json diff --git a/.gitignore b/.gitignore index ad9f179..ca6301e 100644 --- a/.gitignore +++ b/.gitignore @@ -339,6 +339,9 @@ ASALocalRun/ !**/.vscode/tasks.json !**/.vscode/mklink.md !**/.vscode/*.http +**/.vscode/2025-*.http +**/.vscode/2026-*.http + *.lnk diff --git a/Adaptation/.vscode/download-work-items.http b/Adaptation/.vscode/download-work-items.http deleted file mode 100644 index 65b90e2..0000000 --- a/Adaptation/.vscode/download-work-items.http +++ /dev/null @@ -1,21 +0,0 @@ -@host = https://tfs.intra.infineon.com -@pat = asdf -@ids = 126018, 224543 - -GET {{host}}/tfs/FactoryIntegration/_apis/wit/workitems?ids={{ids}}&$expand=Relations -Accept: application/json -Authorization: Basic {{pat}} - -### - -GET {{host}}/tfs/FactoryIntegration/_apis/wit/workitems/{{ids}}/updates -Accept: application/json -Authorization: Basic {{pat}} - -### Iterations - -GET {{host}}/tfs/FactoryIntegration/ART%20SPS/cea9f426-6fb1-4d65-93d5-dbf471056212/_apis/work/teamsettings/iterations? -Accept: application/json -Authorization: Basic {{pat}} - -### \ No newline at end of file diff --git a/Adaptation/.vscode/launch.json b/Adaptation/.vscode/launch.json index 9d6ce3e..b879e76 100644 --- a/Adaptation/.vscode/launch.json +++ b/Adaptation/.vscode/launch.json @@ -7,10 +7,30 @@ "processId": 22868 }, { - "type": "node", - "request": "launch", - "name": "node Launch Current Opened File", - "program": "${file}" - } + "type": "node", + "request": "launch", + "name": "node Launch Current Opened File", + "program": "${file}" + }, + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "launch", + "name": "Debug File", + "program": "${file}", + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "watchMode": false + }, + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "launch", + "name": "Run File", + "program": "${file}", + "cwd": "${workspaceFolder}", + "noDebug": true, + "watchMode": false + }, ] -} +} \ No newline at end of file diff --git a/Adaptation/.vscode/settings.json b/Adaptation/.vscode/settings.json index 245954e..fb141b9 100644 --- a/Adaptation/.vscode/settings.json +++ b/Adaptation/.vscode/settings.json @@ -22,9 +22,12 @@ "Rcpe", "RESIMAPCDE", "Rsens", + "signalr", "Smpl", "Villach", - "Vrng" + "Vrng", + "Weightest", + "WSJF" ], "coverage-gutters.coverageBaseDir": "../../../../MESAFIBACKLOG/05_TestResults/TestResults/**", "workbench.colorCustomizations": { diff --git a/Adaptation/.vscode/tfs.http b/Adaptation/.vscode/tfs.http new file mode 100644 index 0000000..aac41b7 --- /dev/null +++ b/Adaptation/.vscode/tfs.http @@ -0,0 +1,160 @@ +@Manufacturing-IT = https://tfs.intra.infineon.com/tfs/ManufacturingIT +@Factory-Integration = https://tfs.intra.infineon.com/tfs/FactoryIntegration +@userId = phares +@ids = 126018, 224543 +@Unauthorized-Chase = asdf +@Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E = asdf + +### Work Items Expand Relations + +GET {{Factory-Integration}}/_apis/wit/workitems?ids={{ids}}&$expand=Relations +Accept: application/json +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} + +### Work Items Updates + +GET {{Factory-Integration}}/_apis/wit/workitems/{{ids}}/updates +Accept: application/json +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} + +### Iterations + +GET {{Factory-Integration}}/ART%20SPS/cea9f426-6fb1-4d65-93d5-dbf471056212/_apis/work/teamsettings/iterations? +Accept: application/json +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} + +### User Entitlements + +GET {{Factory-Integration}}/_apis/userEntitlements/{{userId}}?api-version=6.0-preview.3 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Accept: application/json + +### User Entitlements + +GET {{Factory-Integration}}/_apis/userEntitlements?api-version=5.1-preview.2 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Accept: application/json + +### Work Item Patch + +patch {{Manufacturing-IT}}/Mesa_FI/_apis/wit/workitems/382290?api-version=7.0 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Content-Type: application/json-patch+json + +[ + { + "op": "test", + "path": "/rev", + "value": 1 + }, + { + "op": "test", + "path": "/fields/System.CreatedDate", + "value": "2023-10-07T18:51:52.783Z" + }, + { + "op": "replace", + "path": "/fields/System.CreatedDate", + "value": "2023-10-07T18:41:52.783Z" + } +] + +### Post Comment + +POST {{Manufacturing-IT}}/Mesa_FI/_apis/wit/workitems/382005/comments?api-version=5.1-preview.3 +Authorization: Basic {{Unauthorized-Chase}} +Content-Type: application/json + +{ + "text": "Force updated by" +} + +### Delete Comment + +DELETE {{Manufacturing-IT}}/Mesa_FI/_apis/wit/workitems/382005/comments?api-version=5.1-preview.3 +Authorization: Basic {{Unauthorized-Chase}} +Content-Type: application/json + +### Work Item Patch WSJF + +patch {{Factory-Integration}}/_apis/wit/workitems/292309?api-version=7.0 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Content-Type: application/json-patch+json + +[ + { + "op": "replace", + "path": "/fields/Custom.WSJF", + "value": "5" + } +] + +### Work Item Patch WSJF-B 100+300+400=800 800/200=4 + +patch {{Factory-Integration}}/_apis/wit/workitems/292309?api-version=7.0 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Content-Type: application/json-patch+json + +[ + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Common.BusinessValue", + "value": "100" + }, + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Scheduling.Effort", + "value": "200" + }, + { + "op": "replace", + "path": "/fields/Custom.RRminusOE", + "value": "300" + }, + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Common.TimeCriticality", + "value": "400" + }, + { + "op": "replace", + "path": "/fields/Custom.WSJF", + "value": "4" + } +] + +### Work Item Patch WSJF-B 400+400+400=1200 1200/200=6 + +patch {{Factory-Integration}}/_apis/wit/workitems/110781?api-version=7.0 +Authorization: Basic {{Factory-Integration-Phares-1CB1AEFED90C2A4A9A96F9ED9140A95E}} +Content-Type: application/json-patch+json + +[ + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Common.BusinessValue", + "value": "400" + }, + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Scheduling.Effort", + "value": "200" + }, + { + "op": "replace", + "path": "/fields/Custom.RRminusOE", + "value": "400" + }, + { + "op": "replace", + "path": "/fields/Microsoft.VSTS.Common.TimeCriticality", + "value": "400" + }, + { + "op": "replace", + "path": "/fields/Custom.WSJF", + "value": "6" + } +] + +### \ No newline at end of file diff --git a/Adaptation/FileHandlers/APC/FileRead.cs b/Adaptation/FileHandlers/APC/FileRead.cs index a9ed0b0..a90c002 100644 --- a/Adaptation/FileHandlers/APC/FileRead.cs +++ b/Adaptation/FileHandlers/APC/FileRead.cs @@ -128,7 +128,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/Archive/FileRead.cs b/Adaptation/FileHandlers/Archive/FileRead.cs index 80325c0..5cdb4f2 100644 --- a/Adaptation/FileHandlers/Archive/FileRead.cs +++ b/Adaptation/FileHandlers/Archive/FileRead.cs @@ -153,7 +153,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) MoveArchive(reportFullPath, dateTime); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/IQSSi/FileRead.cs b/Adaptation/FileHandlers/IQSSi/FileRead.cs index a60ec91..ebd71ad 100644 --- a/Adaptation/FileHandlers/IQSSi/FileRead.cs +++ b/Adaptation/FileHandlers/IQSSi/FileRead.cs @@ -127,7 +127,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/OpenInsight/FileRead.cs b/Adaptation/FileHandlers/OpenInsight/FileRead.cs index fd9bc9c..93013ce 100644 --- a/Adaptation/FileHandlers/OpenInsight/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsight/FileRead.cs @@ -126,7 +126,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) SaveOpenInsightFile(reportFullPath, dateTime, descriptions, tests); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs index 45c54dd..d1339bf 100644 --- a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs @@ -137,7 +137,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) SendData(reportFullPath, dateTime, descriptions); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs b/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs index 4e3a1ea..33ecb6c 100644 --- a/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs @@ -154,7 +154,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) PostOpenInsightMetrologyViewerAttachments(descriptions); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/Processed/FileRead.cs b/Adaptation/FileHandlers/Processed/FileRead.cs index d1d1c84..aa7b774 100644 --- a/Adaptation/FileHandlers/Processed/FileRead.cs +++ b/Adaptation/FileHandlers/Processed/FileRead.cs @@ -173,7 +173,7 @@ public class FileRead : Shared.FileRead, IFileRead JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List descriptions = json.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) DirectoryMove(reportFullPath, dateTime, descriptions); else if (!_IsEAFHosted) diff --git a/Adaptation/FileHandlers/SPaCe/FileRead.cs b/Adaptation/FileHandlers/SPaCe/FileRead.cs index 2e0f55a..e258bd6 100644 --- a/Adaptation/FileHandlers/SPaCe/FileRead.cs +++ b/Adaptation/FileHandlers/SPaCe/FileRead.cs @@ -125,7 +125,7 @@ public class FileRead : Shared.FileRead, IFileRead Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); + results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0-.ts b/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0-.ts new file mode 100644 index 0000000..86f7b56 --- /dev/null +++ b/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0-.ts @@ -0,0 +1,433 @@ +var _b = {}; +var _c = {}; +var _e = {}; +var _r = {}; +var _t = {}; +var _w = {}; +var _page = ''; +var _site = ''; +var _apiUrl = ''; +var _toggle = true; +var _username = ''; +var _machineId = ''; +var _sessionId = ''; +var _windowLocationHRef = ''; + +function compareFunctionSortOrder(a: any, b: any) { + return a.SortOrder - b.SortOrder; +} + +function compareFunctionParentId(a: any, b: any) { + return a.ParentId - b.ParentId || a.Id - b.Id; +} + +function compareFunctionWeightedShortestJobFirst(a: any, b: any) { + if (b.WeightedShortestJobFirst === ' ') { + return -1; + } + return b.WeightedShortestJobFirst - a.WeightedShortestJobFirst; +} + +function getState(state: any) { + let result; + if (state == undefined) + result = '9-Null'; + else if (state === 'New') + result = `1-${state}`; + else if (state === 'Active') + result = `2-${state}`; + else if (state === 'Resolved') + result = `3-${state}`; + else if (state === 'Closed') + result = `4-${state}`; + else if (state === 'Removed') + result = `5-${state}`; + else + result = `8-${state}`; + return result; +} + +function getPriority(workItemType: any, priority: any, sortPriorityGroup: any) { + let result; + if (workItemType === 'Bug') + result = '0-Bug {0}'; + else if (priority == undefined || priority === 0) + result = '9-Null {0}'; + else if (priority === 1) + result = `${priority}-High {${sortPriorityGroup}}`; + else if (priority === 2) + result = `${priority}-Med {${sortPriorityGroup}}`; + else if (priority === 3) + result = `${priority}-Low {${sortPriorityGroup}}`; + else if (priority === 4) + result = `${priority}-TBD {4}`; + else + result = '8-Not {0}'; + return result; +} + +function getNotifications(x: any, aggregation: any) { + let result: any; + if (aggregation == undefined || aggregation.Notifications == undefined || aggregation.Notifications.length === 0) + result = ' '; + else { + result = ''; + aggregation.Notifications.forEach((element: any) => { + const username = element.username == null ? 'user' : element.username; + if (element.value === '1') { + result += 'Highest:' + username + ';|'; + } + else if (element.value === '2') { + result += 'High:' + username + ';|'; + } + else if (element.value === '3') { + result += 'Medium:' + username + ';|'; + } + else if (element.value === '4') { + result += 'Low:' + username + ';|'; + } + else if (element.value === '5') { + result += 'Lowest:' + username + ';|'; + } + else { + result += element.value + ':' + username + ';|'; + } + }); + result = result.substring(0, result.length - 1); + result = result.replaceAll('|', '
'); + } + return result; +} + +function round(value: any, factor: number) { + return (Math.round((value + Number.EPSILON) * factor) / factor).toFixed(2); +} + +function roundMultiply(value: any, factor: number, multiply: number) { + return (Math.round((value + Number.EPSILON) * factor) / factor) * multiply; +} + +function sum(collection: any) { + let sum = 0; + if (collection != undefined) { + for (let i = 0; i < collection.length; i++) { + sum += collection[i]; + } + } + return sum; +} + +function updateRecordCoD(b: any, r: any, t: any, c: any, e: any, w: any, workItem: any, highestTotalStoryPoints: any, dataB: any, totalStoryPoints: any) { + if (workItem != undefined) { + let data = dataB == undefined ? undefined : dataB[workItem.Id]; + if (data == undefined) { + 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.SortOrder = 0; + } + else { + 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 ? ' ' : 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.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}" + } + ]`; + } + } + } +} + +function updateRecordParent(parent: any, workItem: any) { + if (parent == undefined) { + workItem.ParentId = 9999999; + workItem.ParentTitle = null; + workItem.ParentState = null; + workItem.ParentCoD = 9999999; + } + else { + workItem.ParentId = parent.Id; + workItem.ParentCoD = parent.CoD; + workItem.ParentTitle = parent.Title; + workItem.ParentState = getState(parent.State); + } +} + +function getRecords(b: any, r: any, t: any, c: any, e: any, w: any, data: any, dataB: any, workItems: any) { + let parent; + let workItem; + let storyPoints; + let records = []; + let totalStoryPoints; + let highestTotalStoryPoints = 0; + for (let i = 0; i < data.length; i++) { + workItem = data[i].WorkItem; + if (workItem.WorkItemType !== 'Feature') + continue; + if (workItem.State !== 'Active' && workItem.State !== 'New') + continue; + 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); + if (totalStoryPoints > highestTotalStoryPoints) + highestTotalStoryPoints = totalStoryPoints; + } + for (let i = 0; i < data.length; i++) { + parent = data[i].Parent; + workItem = data[i].WorkItem; + if (workItem.WorkItemType !== 'Feature') + continue; + if (workItem.State !== 'Active' && workItem.State !== 'New') + continue; + 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); + if ((_windowLocationHRef.indexOf('=LEO') > -1 && workItem.AreaPath !== 'ART SPS\\LEO') || (_windowLocationHRef.indexOf('=MES') > -1 && workItem.AreaPath !== 'ART SPS\\MES')) + continue; + updateRecordParent(parent, workItem); + updateRecordCoD(b, r, t, c, e, w, parent, highestTotalStoryPoints, null, null); + updateRecordCoD(b, r, t, c, e, w, workItem, highestTotalStoryPoints, dataB, totalStoryPoints); + workItem.State = getState(workItem.State); + records.push(workItem); + } + if (_windowLocationHRef.indexOf('=WSJF') > -1) { + records.sort(compareFunctionWeightedShortestJobFirst); + } + else if (_windowLocationHRef.indexOf('=LIVE') > -1) { + records.sort(compareFunctionSortOrder); + } + else { + records.sort(compareFunctionParentId); + } + return records; +} + +function getHtmlTextAndHttp(fromHtml: any, b: any, r: any, t: any, c: any, e: any, w: any, records: any) { + let record; + 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 = 'Parent IdParent TitleIdRequesterTitleAssigned ToSystem(s)StatePriorityRisk Reduction and/or Opportunity EnablementTime CriticalityBusiness ValueCost of Delay (CoD)EffortWSJF'; + 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.Effort + '\t' + + record.WeightedShortestJobFirst + '\t' + + record.CoD + '\t' + + record.TotalStoryPoints.split(' ')[0] + '\t' + + record.AbsoluteDelta + '\t' + + record.State.split('-')[0] + '\t' + + record.Requester + '\t' + + record.AssignedTo + '\t' + + record.IterationPath + '\t' + + record.Tags + '\t' + + record.Title + '\r\n'; + lineA = '' + '' + record.ParentId + "" + + '' + record.ParentTitle + + '' + '' + record.Id + "" + + '' + record.Requester + + '' + record.Title + + '' + record.AssignedTo + + '' + record.Tags + + '' + record.State + + '' + record.Priority + + '' + record.RiskReductionMinusOpportunityEnablementNotifications + '
' + + '' + + '' + record.TimeCriticalityNotifications + '
' + + '' + + '' + record.BusinessValueNotifications + '
' + + '' + + '' + record.CoD + '' + + '' + record.EffortNotifications + '
'; + if (!fromHtml || _windowLocationHRef.indexOf('=EFFORT') === -1) { + lineB = ''; + } + else { + lineB = '
'; + } + lineC = '' + record.TotalStoryPoints + '' + + '' + record.WeightedShortestJobFirst + '
' + record.CumulativeStoryPoints + '
' + + ''; + if (!fromHtml) + console.log(text); + html += lineA + lineB + lineC; + } + return { html, text, http }; +} + +const username = ''; +const machineId = ''; +const fromHtml = false; +const baseUri = 'http://eaf-dev.mes.infineon.com:5054'; +const apiUrl = baseUri + '/api/v1/ado/'; +const windowLocationHRef = baseUri + '/html/cod.html?site=MES'; +const signalRUrl = baseUri + '/signalr'; +const workItems = { + a: baseUri + '/markdown/bugs-features-with-parents.json?v=2025-04-14-08-10', + b: baseUri + '/markdown/{}.json?v=2025-04-14-08-10', + timeout: 3000, +}; +const b = { + page: 'business', + description: 'Value', + th: 'Business Value', + span: 'What is the relative value to the Customer or business?
• Do our users prefer this over that?
• What is the revenue impact on our business?
• 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?
• Reduce the risk of this or future delivery?
• Is there value in the information we will receive?
• Enable new business opportunities?' +}; +const t = { + page: 'time', + description: 'Critical', + th: 'Time Criticality', + span: 'How does user/business value decay over time?
• Is there a fixed deadline?
• Will they wait for us or move to another Solution?
• What is the current effect on Customer satisfaction?' +}; +const c = { + 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' +}; +const w = { + 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) + .then((res) => res.text()) + .then((textB) => { + fetch(workItems.a) + .then((res) => res.text()) + .then((textA) => { + const dataA = JSON.parse(textA); + const dataB = JSON.parse(textB); + if (dataA.length > 0) + console.log(dataA[0]); + const records = getRecords(b, r, t, c, e, w, dataA, dataB, workItems); + let result = getHtmlTextAndHttp(fromHtml, b, r, t, c, e, w, records); + if (result == undefined) { } + }) + .catch((e) => console.error(e)); + }) + .catch((e) => console.error(e)); \ No newline at end of file diff --git a/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0.js b/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0.js index bcd0c5c..0919331 100644 --- a/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0.js +++ b/Adaptation/FileHandlers/json/StaticSite/js/cod-1-123-0.js @@ -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 = 'Parent IdParent TitleIdRequesterTitleAssigned ToSystem(s)StatePriorityRisk Reduction and/or Opportunity EnablementTime CriticalityBusiness ValueCost of Delay (CoD)EffortWSJF'; 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<', '> <'); - if (_windowLocationHRef.indexOf('=WSJF') === -1) { - document.getElementById('AllTextarea').value = text.replaceAll('null', '').replaceAll(' ', ''); - } - 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<', '> <'); + if (_windowLocationHRef.indexOf('=WSJF') === -1) { + document.getElementById('AllTextarea').value = result.text.replaceAll('null', '').replaceAll(' ', '') + 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("") + el.before('') 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?
• Do our users prefer this over that?
• What is the revenue impact on our business?
• 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?
• Do our users prefer this over that?
• What is the revenue impact on our business?
• 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?
• Reduce the risk of this or future delivery?
• Is there value in the information we will receive?
• Enable new business opportunities?" + page: 'risk', + description: 'Risk', + th: 'Risk Reduction and/or Opportunity Enablement', + span: 'What else does this do for our business?
• Reduce the risk of this or future delivery?
• Is there value in the information we will receive?
• Enable new business opportunities?' }; const t = { - page: "time", - description: "Critical", - th: "Time Criticality", - span: "How does user/business value decay over time?
• Is there a fixed deadline?
• Will they wait for us or move to another Solution?
• What is the current effect on Customer satisfaction?" + page: 'time', + description: 'Critical', + th: 'Time Criticality', + span: 'How does user/business value decay over time?
• Is there a fixed deadline?
• Will they wait for us or move to another Solution?
• 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)); diff --git a/Adaptation/MESAFIBACKLOG.yml b/Adaptation/MESAFIBACKLOG.yml index 1f9bda1..5265473 100644 --- a/Adaptation/MESAFIBACKLOG.yml +++ b/Adaptation/MESAFIBACKLOG.yml @@ -41,6 +41,24 @@ stages: displayName: "Nuget Clear" enabled: false + - task: CopyFiles@2 + displayName: 'Copy GhostPCL Files to: D:\EAF-Mesa-Integration\copy' + inputs: + Contents: "*" + SourceFolder: '\\mesfs.infineon.com\EC_EAFRepository\Staging\DeploymentStorage\GhostPCL' + TargetFolder: 'D:\EAF-Mesa-Integration\copy\GhostPCL' + OverWrite: true + enabled: true + + - task: CopyFiles@2 + displayName: 'Copy LincPDFC Files to: D:\EAF-Mesa-Integration\copy' + inputs: + Contents: "*" + SourceFolder: '\\mesfs.infineon.com\EC_EAFRepository\Staging\DeploymentStorage\LincPDFC' + TargetFolder: 'D:\EAF-Mesa-Integration\copy\LincPDFC' + OverWrite: true + enabled: true + - script: | "C:\program files\dotnet\dotnet.exe" user-secrets init "C:\program files\dotnet\dotnet.exe" user-secrets set "BuildNumber" "$(Build.BuildId)" @@ -184,6 +202,24 @@ stages: displayName: "Nuget Clear" enabled: false + - task: CopyFiles@2 + displayName: 'Copy GhostPCL Files to: D:\EAF-Mesa-Integration\copy' + inputs: + Contents: "*" + SourceFolder: '\\mestsa003.infineon.com\EC_EAFRepository\Staging\DeploymentStorage\GhostPCL' + TargetFolder: 'D:\EAF-Mesa-Integration\copy\GhostPCL' + OverWrite: true + enabled: true + + - task: CopyFiles@2 + displayName: 'Copy LincPDFC Files to: D:\EAF-Mesa-Integration\copy' + inputs: + Contents: "*" + SourceFolder: '\\mestsa003.infineon.com\EC_EAFRepository\Staging\DeploymentStorage\LincPDFC' + TargetFolder: 'D:\EAF-Mesa-Integration\copy\LincPDFC' + OverWrite: true + enabled: true + - script: | "C:\program files\dotnet\dotnet.exe" user-secrets init "C:\program files\dotnet\dotnet.exe" user-secrets set "BuildNumber" "$(Build.BuildId)" diff --git a/Adaptation/Shared/FileRead.cs b/Adaptation/Shared/FileRead.cs index 49a4526..03b4109 100644 --- a/Adaptation/Shared/FileRead.cs +++ b/Adaptation/Shared/FileRead.cs @@ -478,27 +478,14 @@ public class FileRead : Properties.IFileRead } } - protected void WritePDSF(IFileRead fileRead, JsonElement[] jsonElements) + protected static void WritePDSF(IFileRead fileRead, JsonElement[] jsonElements) { - string directory; - string day = $"{_Logistics.DateTimeFromSequence:yyyy-MM-dd}"; - string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - string weekDirectory = $"{_Logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}"; - if (!_CellInstanceConnectionName.StartsWith(_CellInstanceName) && _CellInstanceConnectionNameBase == _EquipmentType) - directory = Path.Combine(_TracePath, _EquipmentType, "Target", weekDirectory, day, _CellInstanceName, _CellInstanceConnectionName); - else - directory = Path.Combine(_TracePath, _EquipmentType, "Source", weekDirectory, day, _CellInstanceName, _CellInstanceConnectionName); - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - string file = Path.Combine(directory, string.Concat(_Logistics.MesEntity, "_", _Logistics.Sequence, ".ipdsf")); - string lines = ProcessDataStandardFormat.GetPDSFText(fileRead, _Logistics, jsonElements, logisticsText: string.Empty); - File.WriteAllText(file, lines); - if (_Logistics.TotalSecondsSinceLastWriteTimeFromSequence > 600) - { - try - { File.SetLastWriteTime(file, _Logistics.DateTimeFromSequence); } - catch (Exception) { } - } +#pragma warning disable CA1510 + if (fileRead is null) + throw new ArgumentNullException(nameof(fileRead)); + if (jsonElements is null) + throw new ArgumentNullException(nameof(jsonElements)); +#pragma warning restore CA1510 } protected void WaitForThread(Thread thread, List threadExceptions) diff --git a/Adaptation/Shared/ProcessDataStandardFormat.cs b/Adaptation/Shared/ProcessDataStandardFormat.cs index a86241d..1596264 100644 --- a/Adaptation/Shared/ProcessDataStandardFormat.cs +++ b/Adaptation/Shared/ProcessDataStandardFormat.cs @@ -136,6 +136,7 @@ internal class ProcessDataStandardFormat internal static ProcessDataStandardFormat GetProcessDataStandardFormat(string reportFullPath, string[]? lines = null, int columnsLine = 6) { ProcessDataStandardFormat result; + long? sequence; string segment; string[] segments; bool addToFooter = false; @@ -186,13 +187,25 @@ internal class ProcessDataStandardFormat } string? linesOne = lines.Length > 0 && body.Count == 0 && columns.Count == 0 ? lines[1] : null; logistics = GetLogistics(footer, linesOne: linesOne); + if (logistics.Count == 0) + sequence = null; + else + { + segments = logistics[0].Split(new string[] { "SEQUENCE=" }, StringSplitOptions.None); + sequence = segments.Length < 2 || !long.TryParse(segments[1].Split(';')[0], out long s) ? null : s; + } + if (sequence is null && !string.IsNullOrEmpty(reportFullPath)) + { + FileInfo fileInfo = new(reportFullPath); + sequence = fileInfo.LastWriteTime.Ticks; + } result = new(body: body.AsReadOnly(), columns: columns.AsReadOnly(), footer: footer.AsReadOnly(), header: header.AsReadOnly(), inputPDSF: null, logistics: logistics, - sequence: null); + sequence: sequence); return result; } @@ -236,7 +249,7 @@ internal class ProcessDataStandardFormat private static ProcessDataStandardFormat GetProcessDataStandardFormat(DateTime lastWriteTime, int columnsLine, string path, string[]? lines) { ProcessDataStandardFormat result; - long sequence; + long? sequence; string[] segments; bool addToFooter = false; List body = new(); @@ -268,12 +281,13 @@ internal class ProcessDataStandardFormat } logistics = GetLogistics(footer, linesOne: null); if (logistics.Count == 0) - sequence = lastWriteTime.Ticks; + sequence = null; else { segments = logistics[0].Split(new string[] { "SEQUENCE=" }, StringSplitOptions.None); - sequence = segments.Length < 2 || !long.TryParse(segments[1].Split(';')[0], out long s) ? lastWriteTime.Ticks : s; + sequence = segments.Length < 2 || !long.TryParse(segments[1].Split(';')[0], out long s) ? null : s; } + sequence ??= lastWriteTime.Ticks; result = new(body: body.AsReadOnly(), columns: new(columns), footer: footer.AsReadOnly(), @@ -302,7 +316,7 @@ internal class ProcessDataStandardFormat segments = bodyLine.Split('\t').ToList(); for (int c = 0; c < segments.Count; c++) { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + value = segments[c].Replace("\\", "\\\\").Replace("\"", "\\\""); _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":\"").Append(value).Append("\","); } _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); @@ -378,19 +392,26 @@ internal class ProcessDataStandardFormat break; for (int c = 0; c < segments.Length; c++) { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + value = segments[c].Replace("\\", "\\\\").Replace("\"", "\\\""); line += string.Concat('"', processDataStandardFormat.InputPDSF.Columns[c].Trim('"'), '"', ':', '"', value, '"', ','); } line = string.Concat(line.Substring(0, line.Length - 1), '}'); lines.Add(line); } + string? json = null; + if (processDataStandardFormat.Footer is not null && processDataStandardFormat.Footer.Count > 0) { + Dictionary footerKeyValuePairs = GetFooterKeyValuePairs(processDataStandardFormat.Footer); + Dictionary> logisticKeyValuePairs = GetLogisticKeyValuePairs(processDataStandardFormat.Footer, footerKeyValuePairs); + json = JsonSerializer.Serialize(logisticKeyValuePairs, DictionaryStringDictionaryStringStringSourceGenerationContext.Default.DictionaryStringDictionaryStringString); + } + string footerText = string.IsNullOrEmpty(json) || json == "{}" ? string.Empty : $",{Environment.NewLine}\"PDSF\":{Environment.NewLine}{json}"; result = string.Concat( '{', Environment.NewLine, '"', "Count", '"', - ": ", + ": ", processDataStandardFormat.Body.Count, ',', Environment.NewLine, @@ -409,12 +430,67 @@ internal class ProcessDataStandardFormat '"', "Sequence", '"', - ": ", + ": ", processDataStandardFormat.Sequence, Environment.NewLine, + footerText, + Environment.NewLine, '}'); return result; -#pragma warning restore CA1845, IDE0057 + } + + private static Dictionary GetFooterKeyValuePairs(ReadOnlyCollection footerLines) { + Dictionary results = new(); + string[] segments; + foreach (string footerLine in footerLines) { + segments = footerLine.Split('\t'); + if (segments.Length != 2 || string.IsNullOrEmpty(segments[1].Trim())) { + continue; + } + if (segments[1].Contains(';')) { + continue; + } else { + results.Add(segments[0], segments[1]); + } + } + return results; + } + + private static Dictionary> GetLogisticKeyValuePairs(ReadOnlyCollection footerLines, Dictionary footerKeyValuePairs) { + Dictionary> results = new(); + string[] segments; + string[] subSegments; + string[] subSubSegments; + Dictionary? keyValue; + results.Add("Footer", footerKeyValuePairs); + foreach (string footerLine in footerLines) { + segments = footerLine.Split('\t'); + if (segments.Length != 2 || string.IsNullOrEmpty(segments[1].Trim())) { + continue; + } + if (!segments[1].Contains(';') || !segments[1].Contains('=')) { + continue; + } else { + subSegments = segments[1].Split(';'); + if (subSegments.Length < 1) { + continue; + } + if (!results.TryGetValue(segments[0], out keyValue)) { + results.Add(segments[0], new()); + if (!results.TryGetValue(segments[0], out keyValue)) { + throw new Exception(); + } + } + foreach (string segment in subSegments) { + subSubSegments = segment.Split('='); + if (subSubSegments.Length != 2) { + continue; + } + keyValue.Add(subSubSegments[0], subSubSegments[1]); + } + } + } + return results; } internal static void Write(string path, ProcessDataStandardFormat processDataStandardFormat, List? wsResults) @@ -518,7 +594,7 @@ internal class ProcessDataStandardFormat { for (int c = 1; c < segments.Length; c++) { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + value = segments[c].Replace("\\", "\\\\").Replace("\"", "\\\""); _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":\"").Append(value).Append("\","); } } @@ -526,7 +602,7 @@ internal class ProcessDataStandardFormat { for (int c = 1; c < segments.Length; c++) { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + value = segments[c].Replace("\\", "\\\\").Replace("\"", "\\\""); if (string.IsNullOrEmpty(value)) _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":").Append(value).Append("null,"); else if (value.All(char.IsDigit)) @@ -763,4 +839,9 @@ internal class ProcessDataStandardFormat [JsonSerializable(typeof(JsonElement[]))] internal partial class JsonElementCollectionSourceGenerationContext : JsonSerializerContext { +} + +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(Dictionary>))] +internal partial class DictionaryStringDictionaryStringStringSourceGenerationContext : JsonSerializerContext { } \ No newline at end of file diff --git a/Adaptation/package.json b/Adaptation/package.json index 854c2dc..6f6511c 100644 --- a/Adaptation/package.json +++ b/Adaptation/package.json @@ -1,4 +1,14 @@ { + "name": "adaptation", + "module": "index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + }, "scripts": { "AA-CreateSelfDescription.Staging.v2_43_0-BACKLOG_EQPT": "dotnet test --runtime win-x64 --no-build --filter \"FullyQualifiedName~Adaptation._Tests.CreateSelfDescription.Staging.v2_43_0 & ClassName~BACKLOG_EQPT\" -- TestRunParameters.Parameter(name=\\\"WaitFor\\\", value=\\\"Debugger.IsAttached\\\")", "BA-CreateSelfDescription.Staging.v2_43_0-BACKLOG": "dotnet test --runtime win-x64 --no-build --filter \"FullyQualifiedName~Adaptation._Tests.CreateSelfDescription.Staging.v2_43_0 & ClassName~BACKLOG\" -- TestRunParameters.Parameter(name=\\\"WaitFor\\\", value=\\\"Debugger.IsAttached\\\")", diff --git a/Adaptation/tsconfig.json b/Adaptation/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/Adaptation/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}