@elisra-devops/docgen-data-provider 1.42.0 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/helpers/helper.d.ts +26 -3
- package/bin/helpers/helper.js +124 -39
- package/bin/helpers/helper.js.map +1 -1
- package/package.json +1 -1
- package/src/helpers/helper.ts +183 -62
package/bin/helpers/helper.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Query, Workitem } from
|
|
1
|
+
import { Query, Workitem } from '../models/tfs-data';
|
|
2
2
|
export declare class suiteData {
|
|
3
3
|
name: string;
|
|
4
4
|
id: string;
|
|
@@ -29,9 +29,32 @@ export declare class Trace {
|
|
|
29
29
|
export declare class Helper {
|
|
30
30
|
static level: number;
|
|
31
31
|
static first: boolean;
|
|
32
|
-
static buildSuiteslevel(dataSuites: any): any;
|
|
33
32
|
static suitList: Array<suiteData>;
|
|
33
|
+
static buildSuiteslevel(dataSuites: any): any;
|
|
34
|
+
/**
|
|
35
|
+
* Find suites recursively - O(n) complexity optimization with parent-child lookup map
|
|
36
|
+
* @param planId - The plan identifier
|
|
37
|
+
* @param url - Base URL
|
|
38
|
+
* @param project - Project name
|
|
39
|
+
* @param suits - Array of suite objects
|
|
40
|
+
* @param foundId - ID to search for
|
|
41
|
+
* @param recursive - Whether to search recursively
|
|
42
|
+
* @returns Array of suite data
|
|
43
|
+
*/
|
|
34
44
|
static findSuitesRecursive(planId: string, url: string, project: string, suits: any, foundId: string, recursive: boolean): Array<suiteData>;
|
|
35
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Optimized recursive helper using lookup maps - O(d) where d is depth
|
|
47
|
+
*/
|
|
48
|
+
private static findSuitesRecursiveOptimized;
|
|
49
|
+
/**
|
|
50
|
+
* Optimized level builder without static state
|
|
51
|
+
* @param results - Query results containing work items
|
|
52
|
+
* @param foundId - ID to start building from
|
|
53
|
+
* @returns Array of work items with levels assigned
|
|
54
|
+
*/
|
|
36
55
|
static LevelBuilder(results: Query, foundId: string): Array<Workitem>;
|
|
56
|
+
/**
|
|
57
|
+
* Internal recursive method for building levels
|
|
58
|
+
*/
|
|
59
|
+
private static buildLevelsRecursive;
|
|
37
60
|
}
|
package/bin/helpers/helper.js
CHANGED
|
@@ -24,60 +24,145 @@ class Trace {
|
|
|
24
24
|
exports.Trace = Trace;
|
|
25
25
|
class Helper {
|
|
26
26
|
static buildSuiteslevel(dataSuites) { }
|
|
27
|
+
/**
|
|
28
|
+
* Find suites recursively - O(n) complexity optimization with parent-child lookup map
|
|
29
|
+
* @param planId - The plan identifier
|
|
30
|
+
* @param url - Base URL
|
|
31
|
+
* @param project - Project name
|
|
32
|
+
* @param suits - Array of suite objects
|
|
33
|
+
* @param foundId - ID to search for
|
|
34
|
+
* @param recursive - Whether to search recursively
|
|
35
|
+
* @returns Array of suite data
|
|
36
|
+
*/
|
|
27
37
|
static findSuitesRecursive(planId, url, project, suits, foundId, recursive) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"&_a=tests";
|
|
40
|
-
this.suitList.push(suit);
|
|
41
|
-
if (recursive == false) {
|
|
42
|
-
return this.suitList;
|
|
43
|
-
}
|
|
44
|
-
this.findSuitesRecursive(planId, url, project, suits, suits[i].id, true);
|
|
45
|
-
this.level--;
|
|
46
|
-
}
|
|
38
|
+
// Early return if no suits provided
|
|
39
|
+
if (!suits || suits.length === 0) {
|
|
40
|
+
return this.suitList;
|
|
41
|
+
}
|
|
42
|
+
// Build parent-child lookup map once - O(n) complexity
|
|
43
|
+
const parentChildMap = new Map();
|
|
44
|
+
const suiteById = new Map();
|
|
45
|
+
for (const suit of suits) {
|
|
46
|
+
// Skip if suit is null/undefined or missing required properties
|
|
47
|
+
if (!suit || suit.id == null || suit.parentSuiteId == null) {
|
|
48
|
+
continue;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
// Store suite by ID for quick lookup
|
|
51
|
+
suiteById.set(suit.id.toString(), suit);
|
|
52
|
+
// Group by parent ID
|
|
53
|
+
const parentId = suit.parentSuiteId.toString();
|
|
54
|
+
if (!parentChildMap.has(parentId)) {
|
|
55
|
+
parentChildMap.set(parentId, []);
|
|
56
|
+
}
|
|
57
|
+
parentChildMap.get(parentId).push(suit);
|
|
58
|
+
}
|
|
59
|
+
// Check for single child optimization at the top level
|
|
60
|
+
const directChildren = parentChildMap.get(foundId.toString()) || [];
|
|
61
|
+
const shouldSkipSingleChild = directChildren.length === 1;
|
|
62
|
+
if (shouldSkipSingleChild) {
|
|
63
|
+
// Skip the single child and promote its children to level 1
|
|
64
|
+
const singleChild = directChildren[0];
|
|
65
|
+
const grandChildren = parentChildMap.get(singleChild.id.toString()) || [];
|
|
66
|
+
// Add each grandchild as a level 1 suite (promoted from level 2)
|
|
67
|
+
for (const grandChild of grandChildren) {
|
|
68
|
+
const suite = new suiteData(grandChild.title || '', grandChild.id, foundId, this.level++);
|
|
69
|
+
suite.url = `${url}${project}/_testManagement?planId=${planId}&suiteId=${grandChild.id}&_a=tests`;
|
|
70
|
+
this.suitList.push(suite);
|
|
71
|
+
if (!recursive) {
|
|
72
|
+
this.level--; // Restore level before returning
|
|
73
|
+
return this.suitList;
|
|
56
74
|
}
|
|
75
|
+
// Now recursively process this grandchild's children
|
|
76
|
+
this.findSuitesRecursiveOptimized(planId, url, project, grandChild.id, recursive, parentChildMap, suiteById);
|
|
77
|
+
this.level--;
|
|
57
78
|
}
|
|
58
79
|
}
|
|
80
|
+
else {
|
|
81
|
+
// Normal processing - start recursion from the found ID
|
|
82
|
+
this.findSuitesRecursiveOptimized(planId, url, project, foundId, recursive, parentChildMap, suiteById);
|
|
83
|
+
}
|
|
59
84
|
return this.suitList;
|
|
60
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Optimized recursive helper using lookup maps - O(d) where d is depth
|
|
88
|
+
*/
|
|
89
|
+
static findSuitesRecursiveOptimized(planId, url, project, foundId, recursive, parentChildMap, suiteById) {
|
|
90
|
+
const targetId = foundId.toString();
|
|
91
|
+
// Handle root suite (parentSuiteId === 0) - check if foundId is a root suite
|
|
92
|
+
const rootSuites = parentChildMap.get('0') || [];
|
|
93
|
+
const rootSuite = rootSuites.find((s) => s.id.toString() === targetId);
|
|
94
|
+
if (rootSuite && Helper.first) {
|
|
95
|
+
const suite = new suiteData(rootSuite.title || '', rootSuite.id, foundId, this.level);
|
|
96
|
+
suite.url = `${url}${project}/_workitems/edit/${rootSuite.id}`;
|
|
97
|
+
Helper.first = false;
|
|
98
|
+
if (!recursive) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Process child suites using the lookup map - O(children count)
|
|
103
|
+
const childSuites = parentChildMap.get(targetId) || [];
|
|
104
|
+
// Normal processing - add all children
|
|
105
|
+
for (const childSuite of childSuites) {
|
|
106
|
+
const suite = new suiteData(childSuite.title || '', childSuite.id, foundId, this.level++);
|
|
107
|
+
suite.url = `${url}${project}/_testManagement?planId=${planId}&suiteId=${childSuite.id}&_a=tests`;
|
|
108
|
+
this.suitList.push(suite);
|
|
109
|
+
if (!recursive) {
|
|
110
|
+
this.level--; // Restore level before returning
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Recursively process children
|
|
114
|
+
this.findSuitesRecursiveOptimized(planId, url, project, childSuite.id, true, parentChildMap, suiteById);
|
|
115
|
+
this.level--;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Optimized level builder without static state
|
|
120
|
+
* @param results - Query results containing work items
|
|
121
|
+
* @param foundId - ID to start building from
|
|
122
|
+
* @returns Array of work items with levels assigned
|
|
123
|
+
*/
|
|
61
124
|
static LevelBuilder(results, foundId) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
125
|
+
var _a, _b;
|
|
126
|
+
const levelList = [];
|
|
127
|
+
const processedIds = new Set();
|
|
128
|
+
const workItemMap = new Map();
|
|
129
|
+
// Create lookup map for better performance
|
|
130
|
+
for (const workItem of results.workItems) {
|
|
131
|
+
workItemMap.set(((_a = workItem.fields[0]) === null || _a === void 0 ? void 0 : _a.value) || ((_b = workItem.id) === null || _b === void 0 ? void 0 : _b.toString()) || '', workItem);
|
|
132
|
+
}
|
|
133
|
+
this.buildLevelsRecursive(results, foundId, 0, levelList, processedIds, workItemMap);
|
|
134
|
+
return levelList;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Internal recursive method for building levels
|
|
138
|
+
*/
|
|
139
|
+
static buildLevelsRecursive(results, foundId, currentLevel, levelList, processedIds, workItemMap) {
|
|
140
|
+
var _a, _b, _c;
|
|
141
|
+
for (const workItem of results.workItems) {
|
|
142
|
+
const workItemId = ((_a = workItem.fields[0]) === null || _a === void 0 ? void 0 : _a.value) || ((_b = workItem.id) === null || _b === void 0 ? void 0 : _b.toString()) || '';
|
|
143
|
+
// Skip if already processed
|
|
144
|
+
if (processedIds.has(workItemId)) {
|
|
145
|
+
continue;
|
|
67
146
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
147
|
+
// Handle root items (Source === 0)
|
|
148
|
+
if (workItem.Source === 0) {
|
|
149
|
+
workItem.level = 0;
|
|
150
|
+
levelList.push(workItem);
|
|
151
|
+
processedIds.add(workItemId);
|
|
152
|
+
}
|
|
153
|
+
// Handle items with matching source
|
|
154
|
+
else if (((_c = workItem.Source) === null || _c === void 0 ? void 0 : _c.toString()) === foundId) {
|
|
155
|
+
workItem.level = currentLevel;
|
|
156
|
+
levelList.push(workItem);
|
|
157
|
+
processedIds.add(workItemId);
|
|
158
|
+
// Recursively process children
|
|
159
|
+
this.buildLevelsRecursive(results, workItemId, currentLevel + 1, levelList, processedIds, workItemMap);
|
|
73
160
|
}
|
|
74
161
|
}
|
|
75
|
-
return this.levelList;
|
|
76
162
|
}
|
|
77
163
|
}
|
|
78
164
|
exports.Helper = Helper;
|
|
79
165
|
Helper.level = 1;
|
|
80
166
|
Helper.first = true;
|
|
81
167
|
Helper.suitList = new Array();
|
|
82
|
-
Helper.levelList = new Array();
|
|
83
168
|
//# sourceMappingURL=helper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../../src/helpers/helper.ts"],"names":[],"mappings":";;;AAEA,MAAa,SAAS;IAMpB,YAAY,IAAY,EAAE,EAAU,EAAE,MAAc,EAAE,KAAa;QACjE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAZD,8BAYC;AACD,MAAa,SAAS;IAAtB;QAEE,SAAI,GAAkB,IAAI,KAAK,EAAU,CAAC;IAC5C,CAAC;CAAA;AAHD,8BAGC;AAED,MAAa,KAAK;CAOjB;AAPD,sBAOC;AACD,MAAa,KAAK;
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../../src/helpers/helper.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/helpers/helper.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Query, Workitem } from
|
|
1
|
+
import { Query, Workitem } from '../models/tfs-data';
|
|
2
2
|
|
|
3
3
|
export class suiteData {
|
|
4
4
|
name: string;
|
|
@@ -32,15 +32,25 @@ export class Trace {
|
|
|
32
32
|
url: string;
|
|
33
33
|
customerId: string;
|
|
34
34
|
links: Array<Links>;
|
|
35
|
-
|
|
36
|
-
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
export class Helper {
|
|
40
38
|
static level: number = 1;
|
|
41
39
|
static first: boolean = true;
|
|
42
|
-
static buildSuiteslevel(dataSuites: any): any { }
|
|
43
40
|
public static suitList: Array<suiteData> = new Array<suiteData>();
|
|
41
|
+
|
|
42
|
+
static buildSuiteslevel(dataSuites: any): any {}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Find suites recursively - O(n) complexity optimization with parent-child lookup map
|
|
46
|
+
* @param planId - The plan identifier
|
|
47
|
+
* @param url - Base URL
|
|
48
|
+
* @param project - Project name
|
|
49
|
+
* @param suits - Array of suite objects
|
|
50
|
+
* @param foundId - ID to search for
|
|
51
|
+
* @param recursive - Whether to search recursively
|
|
52
|
+
* @returns Array of suite data
|
|
53
|
+
*/
|
|
44
54
|
public static findSuitesRecursive(
|
|
45
55
|
planId: string,
|
|
46
56
|
url: string,
|
|
@@ -49,71 +59,182 @@ export class Helper {
|
|
|
49
59
|
foundId: string,
|
|
50
60
|
recursive: boolean
|
|
51
61
|
): Array<suiteData> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
62
|
+
// Early return if no suits provided
|
|
63
|
+
if (!suits || suits.length === 0) {
|
|
64
|
+
return this.suitList;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Build parent-child lookup map once - O(n) complexity
|
|
68
|
+
const parentChildMap = new Map<string, any[]>();
|
|
69
|
+
const suiteById = new Map<string, any>();
|
|
70
|
+
|
|
71
|
+
for (const suit of suits) {
|
|
72
|
+
// Skip if suit is null/undefined or missing required properties
|
|
73
|
+
if (!suit || suit.id == null || suit.parentSuiteId == null) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Store suite by ID for quick lookup
|
|
78
|
+
suiteById.set(suit.id.toString(), suit);
|
|
79
|
+
|
|
80
|
+
// Group by parent ID
|
|
81
|
+
const parentId = suit.parentSuiteId.toString();
|
|
82
|
+
if (!parentChildMap.has(parentId)) {
|
|
83
|
+
parentChildMap.set(parentId, []);
|
|
84
|
+
}
|
|
85
|
+
parentChildMap.get(parentId)!.push(suit);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check for single child optimization at the top level
|
|
89
|
+
const directChildren = parentChildMap.get(foundId.toString()) || [];
|
|
90
|
+
const shouldSkipSingleChild = directChildren.length === 1;
|
|
91
|
+
|
|
92
|
+
if (shouldSkipSingleChild) {
|
|
93
|
+
// Skip the single child and promote its children to level 1
|
|
94
|
+
const singleChild = directChildren[0];
|
|
95
|
+
const grandChildren = parentChildMap.get(singleChild.id.toString()) || [];
|
|
96
|
+
|
|
97
|
+
// Add each grandchild as a level 1 suite (promoted from level 2)
|
|
98
|
+
for (const grandChild of grandChildren) {
|
|
99
|
+
const suite: suiteData = new suiteData(grandChild.title || '', grandChild.id, foundId, this.level++);
|
|
100
|
+
suite.url = `${url}${project}/_testManagement?planId=${planId}&suiteId=${grandChild.id}&_a=tests`;
|
|
101
|
+
this.suitList.push(suite);
|
|
102
|
+
|
|
103
|
+
if (!recursive) {
|
|
104
|
+
this.level--; // Restore level before returning
|
|
105
|
+
return this.suitList;
|
|
96
106
|
}
|
|
107
|
+
|
|
108
|
+
// Now recursively process this grandchild's children
|
|
109
|
+
this.findSuitesRecursiveOptimized(
|
|
110
|
+
planId,
|
|
111
|
+
url,
|
|
112
|
+
project,
|
|
113
|
+
grandChild.id,
|
|
114
|
+
recursive,
|
|
115
|
+
parentChildMap,
|
|
116
|
+
suiteById
|
|
117
|
+
);
|
|
118
|
+
this.level--;
|
|
97
119
|
}
|
|
120
|
+
} else {
|
|
121
|
+
// Normal processing - start recursion from the found ID
|
|
122
|
+
this.findSuitesRecursiveOptimized(planId, url, project, foundId, recursive, parentChildMap, suiteById);
|
|
98
123
|
}
|
|
124
|
+
|
|
99
125
|
return this.suitList;
|
|
100
126
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Optimized recursive helper using lookup maps - O(d) where d is depth
|
|
130
|
+
*/
|
|
131
|
+
private static findSuitesRecursiveOptimized(
|
|
132
|
+
planId: string,
|
|
133
|
+
url: string,
|
|
134
|
+
project: string,
|
|
135
|
+
foundId: string,
|
|
136
|
+
recursive: boolean,
|
|
137
|
+
parentChildMap: Map<string, any[]>,
|
|
138
|
+
suiteById: Map<string, any>
|
|
139
|
+
): void {
|
|
140
|
+
const targetId = foundId.toString();
|
|
141
|
+
|
|
142
|
+
// Handle root suite (parentSuiteId === 0) - check if foundId is a root suite
|
|
143
|
+
const rootSuites = parentChildMap.get('0') || [];
|
|
144
|
+
const rootSuite = rootSuites.find((s) => s.id.toString() === targetId);
|
|
145
|
+
|
|
146
|
+
if (rootSuite && Helper.first) {
|
|
147
|
+
const suite: suiteData = new suiteData(rootSuite.title || '', rootSuite.id, foundId, this.level);
|
|
148
|
+
suite.url = `${url}${project}/_workitems/edit/${rootSuite.id}`;
|
|
149
|
+
Helper.first = false;
|
|
150
|
+
|
|
151
|
+
if (!recursive) {
|
|
152
|
+
return;
|
|
114
153
|
}
|
|
115
154
|
}
|
|
116
155
|
|
|
117
|
-
|
|
156
|
+
// Process child suites using the lookup map - O(children count)
|
|
157
|
+
const childSuites = parentChildMap.get(targetId) || [];
|
|
158
|
+
|
|
159
|
+
// Normal processing - add all children
|
|
160
|
+
for (const childSuite of childSuites) {
|
|
161
|
+
const suite: suiteData = new suiteData(childSuite.title || '', childSuite.id, foundId, this.level++);
|
|
162
|
+
suite.url = `${url}${project}/_testManagement?planId=${planId}&suiteId=${childSuite.id}&_a=tests`;
|
|
163
|
+
this.suitList.push(suite);
|
|
164
|
+
|
|
165
|
+
if (!recursive) {
|
|
166
|
+
this.level--; // Restore level before returning
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Recursively process children
|
|
171
|
+
this.findSuitesRecursiveOptimized(planId, url, project, childSuite.id, true, parentChildMap, suiteById);
|
|
172
|
+
|
|
173
|
+
this.level--;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Optimized level builder without static state
|
|
179
|
+
* @param results - Query results containing work items
|
|
180
|
+
* @param foundId - ID to start building from
|
|
181
|
+
* @returns Array of work items with levels assigned
|
|
182
|
+
*/
|
|
183
|
+
public static LevelBuilder(results: Query, foundId: string): Array<Workitem> {
|
|
184
|
+
const levelList: Array<Workitem> = [];
|
|
185
|
+
const processedIds = new Set<string>();
|
|
186
|
+
const workItemMap = new Map<string, Workitem>();
|
|
187
|
+
|
|
188
|
+
// Create lookup map for better performance
|
|
189
|
+
for (const workItem of results.workItems) {
|
|
190
|
+
workItemMap.set(workItem.fields[0]?.value || workItem.id?.toString() || '', workItem);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.buildLevelsRecursive(results, foundId, 0, levelList, processedIds, workItemMap);
|
|
194
|
+
return levelList;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Internal recursive method for building levels
|
|
199
|
+
*/
|
|
200
|
+
private static buildLevelsRecursive(
|
|
201
|
+
results: Query,
|
|
202
|
+
foundId: string,
|
|
203
|
+
currentLevel: number,
|
|
204
|
+
levelList: Array<Workitem>,
|
|
205
|
+
processedIds: Set<string>,
|
|
206
|
+
workItemMap: Map<string, Workitem>
|
|
207
|
+
): void {
|
|
208
|
+
for (const workItem of results.workItems) {
|
|
209
|
+
const workItemId = workItem.fields[0]?.value || workItem.id?.toString() || '';
|
|
210
|
+
|
|
211
|
+
// Skip if already processed
|
|
212
|
+
if (processedIds.has(workItemId)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Handle root items (Source === 0)
|
|
217
|
+
if (workItem.Source === 0) {
|
|
218
|
+
workItem.level = 0;
|
|
219
|
+
levelList.push(workItem);
|
|
220
|
+
processedIds.add(workItemId);
|
|
221
|
+
}
|
|
222
|
+
// Handle items with matching source
|
|
223
|
+
else if (workItem.Source?.toString() === foundId) {
|
|
224
|
+
workItem.level = currentLevel;
|
|
225
|
+
levelList.push(workItem);
|
|
226
|
+
processedIds.add(workItemId);
|
|
227
|
+
|
|
228
|
+
// Recursively process children
|
|
229
|
+
this.buildLevelsRecursive(
|
|
230
|
+
results,
|
|
231
|
+
workItemId,
|
|
232
|
+
currentLevel + 1,
|
|
233
|
+
levelList,
|
|
234
|
+
processedIds,
|
|
235
|
+
workItemMap
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
118
239
|
}
|
|
119
240
|
}
|