in src/PortfolioPlanning/Common/Services/PortfolioPlanningDataService.ts [144:245]
public async getWorkItemProjectIds(
workItemIds: number[],
telemetryService?: PortfolioTelemetry
): Promise<WorkItemProjectIdsQueryResult> {
if (!telemetryService) {
telemetryService = PortfolioTelemetry.getInstance();
}
if (!workItemIds || workItemIds.length === 0) {
return Promise.resolve({
exceptionMessage: null,
Results: null,
QueryInput: workItemIds
});
}
// Can't use OData service to get work item information just based on Ids.
// OData requires a project id or name filter to check security, and we don't have it.
// Using WIQL query service to get project name and work item type for each work item id,
// then using OData service to get project ids based on project names.
// Unfortunately, WIQL doesn't support System.ProjectId :-(.
const workItemIdsMap: { [workitemId: number]: number } = {};
workItemIds.forEach(id => {
workItemIdsMap[id.toString()] = true;
});
const workItemIdsSet = Object.keys(workItemIdsMap).map(idStr => Number(idStr));
const workItemInfo = await PageWorkItemHelper.pageWorkItems(workItemIdsSet, null /** projectName */, [
"System.Id",
"System.WorkItemType",
"System.TeamProject"
]);
const projectIdsByName: { [projectNameKey: string]: string } = {};
workItemInfo.forEach(wi => {
const projectNameKey = (wi.fields["System.TeamProject"] as string).toLowerCase();
// will add project id later.
projectIdsByName[projectNameKey] = null;
});
const projectNamesSet = Object.keys(projectIdsByName).map(name => name);
const projectIdQueryResult: ProjectIdsQueryResult = await PortfolioPlanningDataService.getInstance().getProjectIds(
projectNamesSet
);
if (projectIdQueryResult.exceptionMessage && projectIdQueryResult.exceptionMessage.length > 0) {
throw new Error(
`runDependencyQuery: Exception running project ids query. Inner exception: ${
projectIdQueryResult.exceptionMessage
}`
);
}
if (!projectIdQueryResult.Results || projectIdQueryResult.Results.length === 0) {
const exceptionMessage = `Could not retrieve project ids for linked work items: ${workItemIdsSet.join(
", "
)}. Project names found: ${projectNamesSet.join(", ")}`;
telemetryService.TrackException(new Error(exceptionMessage));
return {
exceptionMessage,
Results: [],
QueryInput: workItemIdsSet
};
}
projectIdQueryResult.Results.forEach(res => {
const projectNameKey = res.ProjectName.toLowerCase();
if (!projectIdsByName[projectNameKey]) {
projectIdsByName[projectNameKey] = res.ProjectSK;
}
});
const Results: WorkItemProjectId[] = [];
workItemInfo.forEach(wi => {
const projectNameKey = (wi.fields["System.TeamProject"] as string).toLowerCase();
if (!projectIdsByName[projectNameKey]) {
// Couldn't find the project id for this linked work item, so ignoring it.
const telemetryData = {
["ProjectName"]: projectNameKey,
["WorkItemId"]: wi.id
};
telemetryService.TrackAction(
"PortfolioPlanningDataService/GetWorkItemProjectIds/MissingProjectId",
telemetryData
);
} else {
Results.push({
WorkItemId: wi.fields["System.Id"],
WorkItemType: wi.fields["System.WorkItemType"],
ProjectSK: projectIdsByName[projectNameKey]
});
}
});
return {
exceptionMessage: null,
Results,
QueryInput: workItemIdsSet
};
}