microsoft / microsoft/azure-devops-extension-sdk
SDK saving wrong workitem when saving
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 159
- Forks
- 53
- PR merge metrics
- No merged PRs in 30d
Description
Hi!
We have an extension designed to send the workitem data to an API whenever the user saves it.
But if the user opens another workitem and save it, the SDK still send the old item, not the current one.
This happens in two places:
- In the backlogs page:
- In any project, go to Backlogs, click an item, edit and then save it: it saves correctly;
- In the same backlog page, open another item and save it: it sends the first workitem, not the current one.
- In the child/parents list inside workitems:
- Open an item that has a parent or child item, edit and save it: it saves correctly;
- In the same item, open a parent or child item, edit and save it: it still saves the one you first opened.
I’m not sure if it’s actually a bug in ADO or my code, so I’ll put it here for reference.
The extension is a Vue.js project.
App.vue:
try {
await SDK.init({
usePlatformScripts: true
}).then(() => {
SDK.register('{removed id}', function () { // This register handles a tab inside the workitem. The issue is in the one below
return {
onLoaded() {
const workkitemService = SDK.getService("ms.vss-work-web.work-item-form");
workkitemService.then(function (service) {
service.getFieldValue("System.WorkItemType").then(function (value) {
if (value !== "Task") {
wrongItemType.value = true;
isLoading.value = false;
return;
}
loadItemData()
.finally(() => isLoading.value = false);
});
});
}
}
});
SDK.register('{another id}', function () { // This is the observer that handles the workitem saving
return {
onSaved: function () {
const workkitemService = SDK.getService("ms.vss-work-web.work-item-form");
workkitemService.then(function (service) {
service.getFieldValue("System.WorkItemType").then(function (workType) {
loadItemData()
.then(() => handleSave(workType))
.catch(e => {
[...]
});
});
});
},
}
});
SDK.notifyLoadSucceeded();
});
} catch (e) {
ErrorUtils.handleError(e)
}
function loadItemData() {
return new Promise((resolve, reject) => {
const workkitemService = SDK.getService("ms.vss-work-web.work-item-form");
workkitemService.then(function (service) {
service.getId()
.then(id => {
service.getWorkItemResourceUrl(id)
.then(url => {
const itemNumber = getItemNumber(url, id);
item.value = {
numero: itemNumber
};
const fieldsMap = new Map();
fieldsMap.set('System.Title', ['title']);
[... a bunch of other fields here]
service.getFields()
.then(fields => {
const promises = fields.map(field => {
return service.getFieldValue(field.referenceName)
.then(value => {
const fieldName = field.referenceName;
const fieldTasks = fieldsMap.get(fieldName);
if (!fieldTasks) {
return;
}
fieldTasks.forEach(field => {
if (!value) {
return;
}
if (field === 'parent') {
value = getItemNumber(url, value);
}
item.value[field] = value;
});
})
.catch(e => ErrorUtils.handleError(e));
});
Promise.all(promises)
.then(() => resolve())
.catch(e => {
ErrorUtils.handleError(e);
reject(e);
});
})
.catch(e => {
ErrorUtils.handleError(e);
reject(e);
});
});
})
.catch(e => {
ErrorUtils.handleError(e);
reject(e);
});
});
});
This is my vss-extension.json:
{
"manifestVersion": 1,
"id": "my-id",
"publisher": "my-publisher",
"version": "1.0.1",
"name": "Name",
"description": "Description",
"categories": [
"Azure Boards"
],
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"files": [
{
"path": "public",
"addressable": true
},
{
"path": "dist",
"addressable": true
}
],
"scopes": [
"vso.work"
],
"contributions": [
{
"id": "my-tab-workitem-id",
"type": "ms.vss-work-web.work-item-form-page",
"description": "Description",
"targets": [
"ms.vss-work-web.work-item-form"
],
"properties": {
"name": "Name",
"uri": "dist/index.html"
}
},
{
"id": "my-observer-id",
"type": "ms.vss-work-web.work-item-notifications",
"description": "Observe work item changes",
"targets": [
"ms.vss-work-web.work-item-form"
],
"properties": {
"uri": "dist/index.html"
}
}
]
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with App.vue, especially the work-item observer's onSaved callback and loadItemData, then trace each SDK.getService call and service.getId() lookup while switching between work items in the two reported contexts. Done means the saved item data corresponds to the currently opened work item in both backlogs and parent/child lists, with the behavior verified against the reproduction steps.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- devtools, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100