It's all about the answers!

Ask a question

How to add Links to a Workitem in RTC 5.x (JS/Dojo)


Jonas Studer (207816) | asked Oct 29 '14, 9:06 a.m.
Hy there fellas,

Does someone know how to add a "parentLink" to an existing Workitem.
The Idea is to clone a WI and then add the parent link to the cloned WI.

Maybe I can relate the WI on creation with the Link?

I use this class to get the Item:
com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory
           var params = {
               includeHistory: false,
               newWorkItem: true,
               projectAreaItemId: pid,
               typeId: "com.ibm.team.apt.workItemType.story"
           }
          
           var newProxy = WorkItemProxyFactory.getWorkItemProxy(params);

//Create new Item:
newProxy.initialize(projectArea, type, newWorkitem, includeHistory) //Maybe it's possible to add links here?

//Before I add some attributes like name, description etc
//My Idea here was, to extract the Links, and add it in the same way to the new Item.
workItemToSave.storedObject.linkTypes = parentLink; //itemToSave is "newProxy"

//Store, save it on the DB
newProxy.storeWorkItem();


Accepted answer


permanent link
Jonas Studer (207816) | answered Oct 31 '14, 8:35 a.m.
edited Oct 31 '14, 11:36 a.m.
Hy Ralph,
I don't really like blogging.
But I'll describe it here.

First you should read this Post about how the whole Workitem-System works.
https://jazz.net/wiki/bin/view/Main/WorkItemWebItemProxyDesign
Long story short:
With store and fetch you interact direct with the REST-Client (Store on DB)
Store = Save it on DB
Fetch = Get it from DB
Everything in this "workItemproxy" is kinda like a runtime copy of the actual WI.

Now I gonna try to clarify how to interact with those Workitems.
First, get the workItemProxy class.
dojo.require("com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory");

I instantiate it for easier use:
var WorkItemProxyFactory = com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory;

Now we gonna create a new WIProxy:
var params = {createIfNeeded: true};
var newProxy = WorkItemProxyFactory.getWorkItemProxy(params);

//If you want an WIProxy of an existing WI:
var params = { id: "itemId of the wished WI",
                        createIfNeeded: true,
                       doNotCache: true,
                       doNotGetFromCache:true};
var workingCopyProxy = WorkItemProxyFactory.getWorkItemProxy(params);

//Initialize the WI
//After the initialization, you'll see an unsaved WI in the MenuBar "Work Items".
var params = {projectAreaItemId: "The ItemId of your project",
                       type: "com.ibm.team.apt.workItemType.story", //Story, epic, whatever you need
                       newWorkItem: true,
                       includeHistory: false};
newProxy.initialize(params);

//Get the Links from the workingCopy
var linkTypeArray = workingCopyProxy.object.linkTypes //Here are all Links to this actual WI stored.
//Otherwise you could use:
var linkTypeArray = workingCopyProxy.getLinkTypesToWorkItem(workingCopyProxy);

//If you search specific LinkTypes, use the endpointId
//I.E. linkTypeArray[x].endpointId == 'parent' //To get the parentLink

//Now HOW TO ADD THE WISHED LINKS
                   var param = {
                           addLinkType: linkTypeArray, //It has to be an Array
                           addLinkedProjectAreaItemId: null, //I don't know what this shold do.
                           addLinkedItemId: newProxy.object.itemId, // It's the ItemId of itself
                           addLinkIsSource: linkTypeArray[0].isSource, //Mostly this is "false"
                   }
                   newProxy.addLinkTarget(param);

//At this point ONLY your runtime copy is actualized! You have to store now your WI to save it on the DB
                   newProxy.storeWorkItem({
                       self: this,
                       operationMsg: "Saving",
                       applyDelta: true,
                       onSuccess: function(param) {
                            //Do what you need
                       }
                   });

Et Voilà the Item is created and saved with the wished links.
Ralph Schoon selected this answer as the correct answer

Comments
Ralph Schoon commented Oct 31 '14, 10:05 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

One last comment Jonas.

To make it easier for the forum users to understand the context, please clarify next time that you are not talking about attribute customization, but that you create a web UI extension.


Jonas Studer commented Oct 31 '14, 10:49 a.m.

Ok, sory for that!
I'll do it better next time


vinitha dsouza commented Jul 19 '16, 4:27 a.m. | edited Nov 27 '17, 12:45 p.m.

Hello,

I just followed the above code but it seems to be existing work item is not Fetched.

dojo.provide("net.jazz.example.workitem.web.ui.LinkedDefectEditorToolbar"); //$NON-NLS-1$

dojo.require("com.ibm.team.workitem.web.ui2.internal.action.AbstractAction"); //$NON-NLS-1$

dojo.require("com.ibm.team.workitem.web.client.util"); //$NON-NLS-1$

dojo.require("com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory");


(function() {

    //I instantiate it for easier use:
    var WorkItemProxyFactory = com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory;

    dojo.declare("net.jazz.example.workitem.web.ui.LinkedDefectEditorToolbar", [com.ibm.team.workitem.web.ui2.internal.action.AbstractAction,com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory],
     {
        constructor: function(){
           
            // Calculate current Project Area and Work Item Type

            this._existingid = new String(this.workingCopy.getItemId());
            this._projectAreaItemId = new String(this.workingCopy.getValue({ path: "attributes.projectArea.id"}));
           
            console.log(this._existingid);
            console.log(this._projectAreaItemId);
       

        },
       
        run: function(parms) {

            //I instantiate it for easier use:
            var WorkItemProxyFactory = com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory;

            //Now we gonna create a new WIProxy:
            var params = {createIfNeeded: true};
            var newProxy = WorkItemProxyFactory.getWorkItemProxy(params);

            //If you want an WIProxy of an existing WI:
            var exparams = { id: this._existingid,
                                   createIfNeeded: true,
                                   doNotCache: true,
                                   doNotGetFromCache:true};
            var workingCopyProxy = WorkItemProxyFactory.getWorkItemProxy(exparams);

            //Initialize the WI
            //After the initialization, you'll see an unsaved WI in the MenuBar "Work Items".
            var newparams = {projectAreaItemId:this._projectAreaItemId,
                                   type: "com.ibm.team.apt.workItemType.story", //Story, epic, whatever you need
                                   newWorkItem: true,
                                   includeHistory: false};
            console.log("projectArea:"+projectAreaItemId);
            newProxy.initialize(newparams);

            //Get the Links from the workingCopy
            //var linkTypeArray = workingCopyProxy.object.linkTypes //Here are all Links to this actual WI stored.
            //Otherwise you could use:
            var linkTypeArray = workingCopyProxy.getLinkTypesToWorkItem(workingCopyProxy);
            console.log("linktype:"+linkTypeArray);

            //If you search specific LinkTypes, use the endpointId
            //I.E. linkTypeArray[x].endpointId == 'parent' //To get the parentLink

            //Now HOW TO ADD THE WISHED LINKS
                               var linkparam = {
                                       addLinkType: linkTypeArray, //It has to be an Array
                                       addLinkedProjectAreaItemId: null, //I don't know what this shold do.
                                       addLinkedItemId: newProxy.object.itemId, // It's the ItemId of itself
                                       addLinkIsSource: linkTypeArray[0].isSource, //Mostly this is "false"
                               }
                               newProxy.addLinkTarget(linkparam);

            //At this point ONLY your runtime copy is actualized! You have to store now your WI to save it on the DB
                               newProxy.storeWorkItem({
                                   self: this,
                                   operationMsg: "Saving",
                                   applyDelta: true,
                                   onSuccess: function(param) {
                                        //Do what you need
                                   }
                               });
   
        }   

    });

})();

Not sure what went wrong!!



Jonas Studer commented Jul 20 '16, 4:39 a.m. | edited Nov 27 '17, 12:46 p.m.

Hello Vinitha,

I'll try my best to clarify this :)

First thing, which would be nice is, where does your code crash.
But I take now some wild guessings.

1:
You've double instanciated the factory.

outside the declare and inside (since the declare statement marks the class boundaries and we need the factory inside)

2:
You're using methods inside the constructor where he doesn't know what to do.
this._existingid = new String(this.workingCopy.getItemId());
Workingcopy is nothing there. Probably here fires the "not fetched" error.

3: Because there are some missing infos, your "var exparams" are not correct. The ID at least.

4: What are the params you've send to the run method?
Because that's where the fetch should happen.
var newProxy = WorkItemProxyFactory.getWorkItemProxy(params);

If it's not one of this this, let me know what happens and where the code went through. So I might recreate the problem you have.


Marcin Blacha commented Nov 27 '17, 3:03 a.m. | edited Nov 27 '17, 12:46 p.m.
HI,
did you resolve your problem? I'm trying to button for create children workitem and on StoreWorkitem I'm getting error:
Uncaught TypeError: Cannot read property 'id' of undefined
at Object._getSaveAppArgs_$77 [as _getSaveAppArgs] (com.ibm.team.workitem.web.cache.internal.WorkItemProxyClient.js?debug=true&etag=aT34qru&locale=en-us&_proxyURL=%2Fjazz:2020)
at Object.storeWorkItem_$64 [as storeWorkItem] (com.ibm.team.workitem.web.cache.internal.WorkItemProxyClient.js?debug=true&etag=aT34qru&locale=en-us&_proxyURL=%2Fjazz:1515)
at Object.run_$1 [as run] (corp.bury.webui.findingButton.ui.createFindingAction.js?debug=true&locale=en-us&_proxyURL=%2Fjazz:65)
at Object._doRun_$2 [as _doRun] (com.ibm.team.workitem.web.ui2.internal.action.AbstractAction.js?debug=true&etag=aT34qru&locale=en-us&_proxyURL=%2Fjazz:59)
at Object.method_$16 [as onClick] (dojo._base.lang.js?debug=true&etag=aL4Yoz2&locale=en-us&_proxyURL=%2Fjazz:375)
at Object._onClick_$3 [as _onClick] (jazz.ui.toolbar.Button.js?debug=true&etag=aT18Sli&locale=en-us&_proxyURL=%2Fjazz:126)
at Object.onClick_$9 (net.jazz.ajax.ui.ScenarioRegistry.js?debug=true&etag=aT174Ja&locale=en-us&_proxyURL=%2Fjazz:204)
at Object.<anonymous> (dojo._base.lang.js?debug=true&etag=aL4Yoz2&locale=en-us&_proxyURL=%2Fjazz:327)
at HTMLAnchorElement.method_$16 (dojo._base.lang.js?debug=true&etag=aL4Yoz2&locale=en-us&_proxyURL=%2Fjazz:375)

My code is here:
        
dojo.provide("corp.bury.webui.findingButton.ui.createFindingAction"); //$NON-NLS-1$    
dojo.require("com.ibm.team.workitem.web.ui2.internal.action.AbstractAction"); //$NON-NLS-1$  
dojo.require("com.ibm.team.workitem.web.client.util"); //$NON-NLS-1$    
dojo.require("com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory"); 
(function() 
    
// WorkItem Types list of entities that for which the actions apply    
var workItemEnabledType = "review";      
// Link Type to use    
var linkType = "com.ibm.team.workitem.linktype.parentworkitem";
// WorkItem Type to generate    
var workItem2Gen = "finding";      
var WorkItemUtil = com.ibm.team.workitem.web.client.util; 
dojo.declare("corp.bury.webui.findingButton.ui.createFindingAction",     
com.ibm.team.workitem.web.ui2.internal.action.AbstractAction,    
constructor: function() 
      
// Calculate current Project Area and Work Item Type    
this._currentWIType = new String(this.workingCopy.getValue(
path: "attributes.workItemType.id"
}));
this._currentPArea = new String(this.workingCopy.getValue(
path: "attributes.projectArea.id"
}));
this._currentWIId = this.workingCopy.getItemId();
},  
run: function(parms) 
    

var WorkItemProxyFactory = com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory;
            var params = {createIfNeeded: true};
            var newProxy = WorkItemProxyFactory.getWorkItemProxy(params); 
            
var initializeParams = 
{
projectAreaItemId: this._currentPArea,
                    type: workItem2Gen, 
                    newWorkItem: true,
                    includeHistory: false
            }; 
newProxy.initialize(initializeParams);
var addTargetLinkParams = 
addLinkIsSource: false, 
addLinkType: linkType, 
addLinkedProjectAreaItemId: this._currentPArea, 
addLinkedItemId: newProxy.object.itemId    
};
newProxy.addLinkTarget(addTargetLinkParams);
var attributesToAdd = 
{
attributeList : { description : "Test", summary : "Test Summary" }
};
newProxy.setAttributes(attributesToAdd);
newProxy.storeWorkItem(
{
                                self: this,
                                operationMsg: "Saving",
                                applyDelta: true,
                                onSuccess: function(param) {
                                     //Do what you need
                                }
});
},   
isEnabled: function() 
    
// Our action is to be only enabled in the Story Work Item and when no change in "on-fly"      
return !this.workingCopy.isNew() && !this.workingCopy.isChanged() && (this._currentWIType==workItemEnabledType);
},   
isVisible: function(parms)   
    
// The action is visible just in workItemEnabledType Work Item    
return this._currentWIType==workItemEnabledType;   
   
}); 
})();
    </pre>
</div>
Where I'm making mistake?

One other answer



permanent link
sam detweiler (12.4k6173200) | answered Oct 29 '14, 9:35 a.m.
I don't think you can create or follow links in the javascript api.

Comments
Jonas Studer commented Oct 29 '14, 10:21 a.m.

Hy Sam,

But under Version 4.x it worked for me.
Was there a mayor change within the Link system?

A guess:
If I use the "Create WorkItem Copy" it doesn't copy the ParentLink, but it adds the "Copied from" Link, which is in the same Hierarchy as a parent link.


sam detweiler commented Oct 29 '14, 10:30 a.m.

No idea.. never got links to work (list, create, delete, or follow) in javascript.

the 'copied from' is a side effect by the server side code, cause you did a 'copy' operation



Ralph Schoon commented Oct 29 '14, 10:37 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

There is a distinction between JavaScript in workitemCustomization, where you can't even access links and creating your own web pages and contributions to them, where you potentially could (as the tool has such capabilities as well)


sam detweiler commented Oct 29 '14, 10:40 a.m.

thanks for that clarification.. I've never done the latter.. (UI is not my thing!)


Jonas Studer commented Oct 29 '14, 11:57 a.m. | edited Oct 29 '14, 12:00 p.m.

So I got in a bit deeper.
But I need your help now.

I've found "addLinkTarget()" in workitemProxy

addLinkTarget: function addLinkTarget_$79(parms / addLinkType addLinkedProjectAreaItemId addLinkedItemId addLinkIsSource/) {}

But the params are a bit confusing.
addLinkType: com.ibm.team.workitem.linktype.parentworkitem
addLinkedProjectAreaItemId: //I don't know so I set it to "null"
addLinkedItemId:I don't know, itemId of the Parent won't work.
addLinkIsSource: What's the meaning of this?

Always get this message:
WorkItemProxy: Could not find source for new link item [object Object]

Maybe this could be a timing error.
Because I use it between
newProxy.initialize()
newProxy.storeWorkItem();

Maybe I can only use the addFunction when it's stored?


Ralph Schoon commented Oct 29 '14, 12:29 p.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

This is beyond my expertise as well. Sorry.


Ralph Schoon commented Oct 31 '14, 8:41 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

It would be great is this could be shared somewhere. If it was my work and I knew how it works, I would blog about it. If you really want to it would be cool if you blogged about it e.g. on DeveloperWorks and link that back here.

showing 5 of 7 show 2 more comments

Your answer


Register or to post your answer.