[英]Azure DevOps Server Widget don't load if configuration is added
I created a Azure DevOps Server widget.我创建了一个 Azure DevOps Server 小部件。 When I tried to integrate the settings, the widget suddenly stopped loading.当我尝试集成设置时,小部件突然停止加载。 I checked my configuration with the example from Microsoft but did not find the solution.我使用 Microsoft 的示例检查了我的配置,但没有找到解决方案。
My vss-extension.json:我的 vss-extension.json:
"manifestVersion": 1,
"id": "ado-report-tfs-addon",
"version": "1.0.0",
"name": "ADO Report Widget",
"description": "You can see at a glance if a team has free capacity for new features.",
"publisher": "bci",
"icons": {
"default": "img/icon.png"
},
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"tags": [
"ado-report",
"report",
"widgets",
"dashboard"
],
"screenshots": [
{
"path": "img/sampleImage1.png"
},
{
"path": "img/sampleImage2.png"
}
],
"content": {
"details": {
"path": "README.md"
}
},
"links": {
"getstarted": {
"uri": "https://rb-tfsbci.de.bosch.com/tfs/OpConDev/Nx_Base/_git/ado-widgets"
},
"learn": {
"uri": "https://rb-tfsbci.de.bosch.com/tfs/OpConDev/Nx_Base/_git/ado-widgets"
},
"license": {
"uri": "https://rb-tfsbci.de.bosch.com/tfs/OpConDev/Nx_Base/_git/ado-widgets"
},
"support": {
"uri": "https://rb-tfsbci.de.bosch.com/tfs/OpConDev/Nx_Base/_git/ado-widgets"
}
},
"repository": {
"type": "git",
"uri": "https://rb-tfsbci.de.bosch.com/tfs/OpConDev/Nx_Base/_git/ado-widgets"
},
"branding": {
"color": "87C2E1",
"theme": "light"
},
"categories": [
"Collaborate"
],
"contributions": [
{
"id": "ADOReport1",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"bci.ado-report-tfs-addon.ADOReport.Configuration"
],
"properties": {
"name": "ADO Report Widget",
"description": "You can see at a glance if a team has free capacity for new features.",
"catalogIconUrl": "img/icon.png",
"previewImageUrl": "img/icon.png",
"uri": "widget1.html",
"supportedSizes": [
{
"rowSpan": 5,
"columnSpan": 5
}
],
"supportedScopes": [
"project_team"
]
}
},
{
"id": "ADOReport.Configuration",
"type": "ms.vss-dashboards-web.widget-configuration",
"targets": [
"ms.vss-dashboards-web.widget-configuration"
],
"properties": {
"name": "ADO Report Configuration",
"description": "Configures ADOReport1",
"uri": "configuration.html"
}
}
],
"files": [
{
"path": "widget1.html",
"addressable": true
},
{
"path": "configuration.html",
"addressable": true
},
{
"path": "styles",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
],
"galleryFlags": [
"Preview"
],
"scopes": [
"vso.work",
"vso.code_write",
"vso.build_execute",
"vso.test",
"vso.build",
"vso.extension.data"
]
}
My widget1.html:我的小部件1.html:
<!DOCTYPE html>
<html>
<head>
<!--<meta http-equiv="refresh" content="5">-->
<link rel="stylesheet" href="styles/main-style.css" />
<script src="sdk/scripts/VSS.SDK.min.js" type="text/javascript"></script>
<script src="sdk/scripts/main.js" type="text/javascript"></script>
</head>
<body>
<div class="widget">
<div class="title-wrapper">
<h2 class="title">ADO Widget</h2>
</div>
<div class="team-select-wrapper">
<div class="team-select-wrapper-select">
<div class="dropdown">
<label>
Team auswählen:
</label>
<div class="wrapper">
<select class="team-select-selector" id="teamSelect"> </select>
</div>
</div>
</div>
<div class="team-select-wrapper-loading">
<div class="loader" id="loading-icon"></div>
</div>
</div>
<div class="feature">
<div class="feature-wrapper">
<div class="feature-name-container" id="feature-name-container"></div>
<div class="feature-time-container" id="feature-time-container"></div>
</div>
<div class="feature-split-wrapper">
<hr class="feature-splitter" />
</div>
<div class="feature-evaluation-wrapper">
<div class="feature-evaluation-summ">
Summe
</div>
<div class="feature-evaluation-value" id="feature-evaluation-value">
</div>
</div>
</div>
<div class="kappa">
<div class="kappa-wrapper">
<div class="kappa-sprint-wrapper" id="sprint-wrapper"></div>
<div class="kappa-evaluation-wrapper">
<div class="kappa-splitter">
<hr class="kappa-splitter-item" />
</div>
<div class="kappa-evaluation">
<div class="kappa-evaluation-text">
Summe:
</div>
<div class="kappa-evaluation-evaluation" id="gesKappa"></div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
My main.js:我的 main.js:
var selectedTeam = "team1";
var teams = [];
var gesKapa = 0;
var loader;
function changeGesKapa(newVal) {
gesKapa = newVal;
var gesKapaNote = document.getElementById("gesKappa");
while (gesKapaNote.lastElementChild) {
gesKapaNote.removeChild(gesKapaNote.lastElementChild);
}
gesKapaNote.innerHTML = "";
gesKapaNote.append(document.createTextNode(gesKapa + "h"));
}
function startLoading() {
if (loader !== undefined) {
loader.classList.remove("hidden");
}
}
function stopLoading() {
if (loader !== undefined) {
loader.classList.add("hidden");
}
}
function getSelectedTeam() {
var mySelect = document.getElementById("teamSelect");
return mySelect.value;
}
function treatAsUTC(date) {
var result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}
function daysBetween(startDate, endDate) {
var millisecondsPerDay = 24 * 60 * 60 * 1000;
return (treatAsUTC(endDate) - treatAsUTC(startDate)) / millisecondsPerDay;
}
function getBusinessDatesCount(startDate, endDate) {
var count = 0;
var curDate = startDate;
while (curDate <= endDate) {
var dayOfWeek = curDate.getDay();
if (!(dayOfWeek == 6 || dayOfWeek == 0)) count++;
curDate.setDate(curDate.getDate() + 1);
}
return count;
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
document.addEventListener("DOMContentLoaded", () => {
loader = document.getElementById("loading-icon");
var sel = document.getElementById("teamSelect");
sel.addEventListener("change", async () => {
startLoading();
await loadOverlay();
});
});
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true,
usePlatformScripts: true,
});
VSS.require(["TFS/Dashboards/WidgetHelpers"], async function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("ADOReport1", function () {
return {
load: function () {
return WidgetHelpers.WidgetStatusHelper.Success();
},
};
});
VSS.notifyLoadSucceeded();
});
VSS.require(["TFS/Core/RestClient"], async function loadTeams(TFS_Core_WebApi) {
TFS_Core_WebApi.getClient()
.getProjects(null, null, null)
.then(async (teamList) => {
await asyncForEach(teamList, async (teamListItem) => {
teams.push({
teams: await TFS_Core_WebApi.getClient().getTeams(
teamListItem.id,
null,
null
),
project: teamListItem,
});
});
teams.sort();
teams.forEach((element) => {
element.teams.sort();
});
var select = document.getElementById("teamSelect");
teams.forEach((element) => {
element.teams.forEach((teamsItem) => {
var option = document.createElement("option");
option.classList.add("team-select-item");
option.appendChild(
document.createTextNode(
element.project.name + " : " + teamsItem.name
)
);
option.value = teamsItem.id + ";" + element.project.id;
select.appendChild(option);
});
});
await loadOverlay();
},
(error) => {
console.log(error);
});
});
async function loadOverlay() {
document.getElementById("feature-name-container").innerHTML = "";
document.getElementById("feature-time-container").innerHTML = "";
gesKapa = 0;
VSS.require(["TFS/WorkItemTracking/RestClient"], async function loadWorkItems(
TFS_WorkItemTracking_WebApi
) {
var e = document.getElementById("teamSelect");
if (
e.options[e.selectedIndex] == undefined ||
e.options[e.selectedIndex] == null
) {
return;
}
var teamId = e.options[e.selectedIndex].value.split(";")[0];
var projectId = e.options[e.selectedIndex].value.split(";")[1];
if (teamId == undefined || teamId == null) {
return;
}
VSS.require(["TFS/Work/RestClient"], async function loadTeamIterations(
TFS_Work_WebApi
) {
TFS_Work_WebApi.getClient()
.getTeamIterations({
projectId: projectId,
teamId: teamId,
})
.then((sprints) => {
TFS_Work_WebApi.getClient()
.getTeamFieldValues({
projectId: projectId,
teamId: teamId,
})
.then((resultValues) => {
// It can happen that the Path Area is null
if (resultValues.defaultValue !== null) {
TFS_WorkItemTracking_WebApi.getClient()
.queryByWiql(
{
query:
"SELECT [System.Id] FROM WorkItems WHERE [Work Item Type] = 'Feature' AND [Board Column] = 'New' AND [Area Path] = '" +
resultValues.defaultValue +
"'",
},
projectId,
teamId
)
.then((workItemIds) => {
var ids = [];
workItemIds.workItems.forEach((workItemId) => {
ids.push(workItemId.id);
});
// It can be that no WorkItems are available
if (Array.isArray(ids) && ids.length) {
TFS_WorkItemTracking_WebApi.getClient()
.getWorkItems(
ids,
[
"System.Id",
"System.Title",
"Microsoft.VSTS.Scheduling.Effort",
],
null,
null
)
.then((workItemObject) => {
var summFeature = 0;
workItemObject.forEach((elementeNew) => {
if (
elementeNew.fields[
"Microsoft.VSTS.Scheduling.Effort"
] != undefined
) {
summFeature +=
elementeNew.fields[
"Microsoft.VSTS.Scheduling.Effort"
];
}
});
var summFeatureNode = document.getElementById(
"feature-evaluation-value"
);
summFeatureNode.innerHTML = "";
summFeatureNode.appendChild(
document.createTextNode(summFeature + "h")
);
var workItemWrapper = document.getElementById(
"feature-name-container"
);
workItemWrapper.innerHTML = "";
workItemObject.forEach((idsnew) => {
var workItemNameWrapper = document.createElement(
"div"
);
workItemNameWrapper.classList.add(
"feature-name-container-item"
);
var linkItem = document.createElement("a");
linkItem.classList.add(
"feature-name-container-link",
"animated-link"
);
linkItem.appendChild(
document.createTextNode(
idsnew.fields["System.Title"]
)
);
workItemNameWrapper.appendChild(linkItem);
workItemWrapper.appendChild(workItemNameWrapper);
});
var workItemTimeWrapper = document.getElementById(
"feature-time-container"
);
workItemTimeWrapper.innerHTML = "";
workItemObject.forEach((idsnew) => {
var workItemTimeSubContainer = document.createElement(
"div"
);
workItemTimeSubContainer.classList.add(
"feature-time-container-item"
);
if (
idsnew.fields[
"Microsoft.VSTS.Scheduling.Effort"
] != undefined
) {
workItemTimeSubContainer.appendChild(
document.createTextNode(
idsnew.fields[
"Microsoft.VSTS.Scheduling.Effort"
] + "h"
)
);
} else {
workItemTimeSubContainer.appendChild(
document.createTextNode("-")
);
}
workItemTimeWrapper.appendChild(
workItemTimeSubContainer
);
});
});
}
});
}
});
var sprintWrapper = document.getElementById("sprint-wrapper");
while (sprintWrapper.lastElementChild) {
sprintWrapper.removeChild(sprintWrapper.lastElementChild);
}
sprints.forEach((sprint) => {
// load kappa
TFS_Work_WebApi.getClient()
.getCapacities(
{
projectId: projectId,
teamId: teamId,
},
sprint.id
)
.then((result) => {
var kapa = 0;
result.forEach((teamMembers) => {
teamMembers.activities.forEach((activity) => {
kapa += activity.capacityPerDay;
});
});
kapa =
kapa *
getBusinessDatesCount(
sprint.attributes.startDate,
sprint.attributes.finishDate
);
changeGesKapa(gesKapa + kapa);
// create header
var sprintItem = document.createElement("div");
sprintItem.classList.add("kappa-sprint-item");
var sprintTitle = document.createElement("div");
sprintTitle.classList.add("kappa-sprint-title");
var sprintTitleLink = document.createElement("a");
sprintTitleLink.classList.add("kappa-sprint-title-link");
sprintTitleLink.classList.add("animated-link");
sprintTitleLink.text = sprint.name;
sprintTitleLink.href = sprint.url;
sprintTitle.appendChild(sprintTitleLink);
sprintItem.appendChild(sprintTitle);
// create sprint content
var sprintcontent = document.createElement("div");
sprintcontent.classList.add("kappa-sprint-content");
var yeStart = new Intl.DateTimeFormat("en", {
year: "numeric",
}).format(sprint.attributes.startDate);
var moStart = new Intl.DateTimeFormat("en", {
month: "short",
}).format(sprint.attributes.startDate);
var daStart = new Intl.DateTimeFormat("en", {
day: "2-digit",
}).format(sprint.attributes.startDate);
var yeEnde = new Intl.DateTimeFormat("en", {
year: "numeric",
}).format(sprint.attributes.finishDate);
var moEnde = new Intl.DateTimeFormat("en", {
month: "short",
}).format(sprint.attributes.finishDate);
var daEnde = new Intl.DateTimeFormat("en", {
day: "2-digit",
}).format(sprint.attributes.finishDate);
sprintcontent.appendChild(
document.createTextNode(
daStart +
"." +
moStart +
"." +
yeStart +
" - " +
daEnde +
"." +
moEnde +
"." +
yeEnde
)
);
sprintItem.appendChild(sprintcontent);
// create sprint evaluation
var sprintEvaluation = document.createElement("div");
sprintEvaluation.classList.add("kappa-sprint-evaluation");
sprintEvaluation.append(
document.createTextNode("Kapa: " + kapa + "h")
);
stopLoading();
sprintItem.appendChild(sprintEvaluation);
sprintWrapper.appendChild(sprintItem);
});
});
});
});
});
}
My configuration.html:我的配置。html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="sdk/scripts/VSS.SDK.min.js" type="text/javascript"></script>
<script>
VSS.init({
explicitNotifyLoaded: false,
usePlatformStyles: true,
});
VSS.require("TFS/Dashboards/WidgetHelpers", function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetConfigurationStyles();
VSS.register(VSS.getContribution().id, function () {
return {
load: function (widgetSettings, widgetConfigurationContext) {
return WidgetHelpers.WidgetStatusHelper.Success();
},
};
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="container">
</div>
</body>
</html>
Can someone help me with this problem?有人可以帮我解决这个问题吗?
In main.js, you're missing the widgetSettings parameter in the load parameter, eg在 main.js 中,您在加载参数中缺少 widgetSettings 参数,例如
return {
load: function (widgetSettings) {
return YourLoadFunction(widgetSettings);
},
reload: function (widgetSettings) {
return YourReloadFunction(widgetSettings);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.