Unable to access Work Item Tracking services Azure DevOps Extensions - tfs

I am rendering extension on the Work item page using
<WebpageControlOptions AllowScript="true" ReloadOnParamChange="true">
<Link UrlRoot="http://.../extension/Validate-extension/1.0.69/assetbyname/workItemNotifications.html"/>
</WebpageControlOptions>
Following is the html/js code:
var workItemID = 0;
VSS.init({
explicitNotifyLoaded: true,
usePlatformScripts: true
});
VSS.ready(function () {
var currentContext = VSS.getWebContext();
VSS.register(VSS.getContribution().id, function (context) {
return {
// event handlers, called when the active work item is loaded/unloaded/modified/saved
onFieldChanged: function (args) {
if (!changedFields[args.id]) {
changedFields[args.id] = [];
changedFieldCount[args.id] = 0;
}
$.each(args.changedFields, function (key, value) {
if (!changedFields[args.id][key]) {
changedFields[args.id][key] = value;
changedFieldCount[args.id]++;
}
});
},
onLoaded: function (args) {
console.log("OnloadNotification");
VSS.require(["TFS/WorkItemTracking/Services"], function (workItemServices) {
workItemServices.WorkItemFormService.getService().then(function (workItemFormSvc) {
if (workItemFormSvc.hasActiveWorkItem()) {
console.log("Active work item is available.");
workItemFormSvc.getFieldValues(["System.Id"]).then(
function (value) {
var val = JSON.stringify(value);
$.each(value, function (key, values) {
if(key == "System.Id"){
workItemID = values;
}
});
});
}
else {
console.log("Active work item is NOT available.");
}
});
});
},
onUnloaded: function (args) {
},
onSaved: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onReset: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onRefreshed: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
}
};
});
VSS.notifyLoadSucceeded();
});
$(document).ready(function () {
$("#btnValidate").click(function () {
var getResponse = ValidateUser();
VSS.require(["TFS/WorkItemTracking/Services"], function (_WorkItemServices) {
var wiServiceNew = _WorkItemServices.WorkItemFormService.getService();
wiServiceNew.setFieldValue("System.Title", "Title set from your group extension!");
});
});
});
2 things which I am trying to achieve
After button click event to validate user, I have to access the Work Item fields after successful validation. Unable to access _WorkItemServices.
Not able to to get the Work Item fields.
When I set workItemID variable OnLoad event, it resets to 0 when a tab is clicked, value is not getting retained which is set OnLoad.

You may try to interact with the IWorkItemFormService service. For example:
import {
IWorkItemChangedArgs,
IWorkItemFieldChangedArgs,
IWorkItemFormService,
IWorkItemLoadedArgs,
WorkItemTrackingServiceIds
} from "azure-devops-extension-api/WorkItemTracking";
Check the sample here:
https://github.com/microsoft/azure-devops-extension-sample/blob/master/src/Samples/WorkItemFormGroup/WorkItemFormGroup.tsx

Related

OData V2 SetProperty in onInit

I need to set the property to DataSet during onInit, to change the visiblity of some controls in my View. I could solve this problem with setting the visibility dynamically in controller. But I want to use the expression binding and the visible property in the View to set visibilites.
I'm getting an error in the function OnStartSetVisibilites. self.getView().getBindingContext() returns UNDEFINED. Without the sPath, I can't use setProperty. And without setProperty, my View-Controls don't know the visible-value.
How to fix this?
View:
<uxap:ObjectPageSubSection visible="{= ${Responsible} === '1'}" id="leader">
</uxap:ObjectPageSubSection>
OnInit in View-Controller:
onInit: function () {
var startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
var sWorkitem = startupParameters.TASK[0];
this.setModel(this.getOwnerComponent().getModel());
this.getModel().metadataLoaded().then(function () {
var sObjectPath = this.getModel().createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: "/" + sObjectPath
});
}.bind(this));
var self = this;
var model = this.getOwnerComponent().getModel();
this.getModel().read("/CharSet", {
success: function (response) {
$.sap.Chars = response.results;
self.onStartSetVisibilities(model, self);
}
});
// self.getView().attachAfterRendering(function () {
// self.onStartSetVisibilities(model, self);
// });
}
OnStartSetVisibilities:
onStartSetVisibilities: function (model, self) {
var char = model.getProperty(ā€˛GeneralData/Char");
if (char !== "" || char !== null) {
model.setProperty(self.getView().getBindingContext().sPath + "/Responsible",
this.getResponsibleForChar(char));
}
}
I put together some code which might solve your issue (it's untested so it may contain syntax errors!).
I introduced the concept of Promises which simplifies the asynchronous behavior of JS. I also replaced some of the inner functions with Arrow functions so you don't have to deal with that or self. Arrow functions basically use the this of the scope they are defined within.
Your app should now have a proper flow.
First you bind the view.
After the view is bound you read the CharSet.
After the data is read you set the visibility stuff
onInit: function () {
const startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
const sWorkitem = startupParameters.TASK[0];
this._bindView(sWorkitem)
.then(() => this._readCharSet())
.then(() => this._setVisibilities())
},
_bindView: function (sWorkitem) {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.metadataLoaded().then(() => {
const sPath = "/" + oModel.createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: sPath,
events: {
change: resolve,
dataReceived: resolve
}
});
});
});
},
_readCharSet: function () {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.read("/CharSet", {
success: resolve
});
});
},
_setVisibilities: function () {
const oModel = this.getOwnerComponent().getModel();
const sChar = oModel.getProperty("GeneralData/Char");
if (sChar) {
// ...
}
}

Code 141 (error: success/error was not called) on Parse Cloud Code nested queries

Background:
I have a Parse database of images. Simply, my code does this:
A user, through a Parse Cloud call requests an image ("getNewPicture"). Nested within I check if he has seen any pictures before (alongside other requirements) and if so deliver one specific picture (getSpecifiedPicture). If he has not, then I deliver a new picture (getNewPicture).
Issue:
Calling "getNewPicture" through Parse Cloud Code function I get an error code 141. What's strange is that it works through Android but not iOS.
My code:
Parse.Cloud.define("getNewPicture", function(request, response) {
var SeenPictures = Parse.Object.extend("SeenPictures");
var query = new Parse.Query(SeenPictures);
var username = request.params.username;
var notWantedPics = [];
query.ascending("createdAt");
query.equalTo("username", username);
query.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].get("likes") == 1 || results[i].get("dislikes") == 1) {
notWantedPics.push(results[i].get("pictureId"));
results.splice(i, 1);
i--;
}
}
if (results != 0) {
getSpecifiedPicture(results[0].get("pictureId"), {
success: function(returnValue) {
response.success(returnValue);
},
error: function(error) {
response.error(error);
}
});
} else {
getNewPicture(username, notWantedPics, {
success: function(returnValue) {
response.success(returnValue);
},
error: function(error) {
response.error(error);
}
});
}
},
error: function() {
response.error(error);
}
});
});
function getSpecifiedPicture(specifiedPic, callback) {
var Pictures = Parse.Object.extend("Pictures");
var pictures = new Parse.Query(Pictures);
pictures.get(specifiedPic, {
success: function(picture) {
callback.success(picture);
},
error: function(error) {
callback.error(error);
}
});
}
function getNewPicture(username, notWantedPics, callback) {
var Pictures = Parse.Object.extend("Pictures");
var pictures = new Parse.Query(Pictures);
pictures.notEqualTo("photographerUserName", username);
pictures.notContainedIn("objectId", notWantedPics);
pictures.ascending("createdAt");
pictures.find({
success: function(results) {
if (results.length > 0) {
var object = results[0];
//Some other fancy stuff
object.save();
callback.success(object);
}
},
error: function(error) {
callback.error(error);
}
});
}
Why am I getting code 141? Any help is appreciated.
Thanks.
Your callbacks are a mess. I rewrote it to follow more of a promise chain style. Much easier to follow. Also, underscore.js is your friend. Hopefully I got your idea right.
var _ = require('underscore'); // Javascript Library
Parse.Cloud.define("getNewPicture", function(request, response) {
var username = request.params.username;
var notWantedPics = [];
if (!username) {
return response.error('No username.');
}
var query1 = new Parse.Query("SeenPictures");
query1.ascending("createdAt");
query1.equalTo("username", username);
var SeenPictures = query1.find();
return Parse.Promise.when([SeenPictures]).then(function (SeenPictures) {
SeenPictures = _.filter(SeenPictures, function (SeenPicture) {
if (SeenPicture.get("likes") == 1 || SeenPicture.get("dislikes") == 1) {
notWantedPics.push(SeenPicture.get("pictureId"));
return false;
}
else {
return true;
}
});
// notWantedPics?
if (SeenPictures > 0) {
var query2 = new Parse.Query("Pictures");
var Pictures = [query2.get(SeenPictures[0].get('pictureId'))];
}
else {
var query2 = new Parse.Query("Pictures");
query2.notEqualTo("photographerUserName", username);
query2.notContainedIn("objectId", notWantedPics);
query2.ascending("createdAt");
var Pictures = query2.find();
}
return Parse.Promise.when([Pictures]);
}).then(function (Pictures) {
if (Pictures > 0) {
// Success
return response.success(Pictures[0]);
} else {
return Parse.Promise.error("No pictures.");
}
}, function (error) {
// Error
return response.error(error);
});
});

AngularJS with JQuery validation

I'm using angularjs to bring some data from server,
it's works perfectly.
Here is the code:
myAppcontroller("AgentCtrl", function ($scope, leadsService) {
$scope.showUsers = false;
$scope.cityName = { 'query': ''};
$scope.findAgent = function() {
leadsService.get("/api/usersapi/agents/" + $scope.cityName.query).then(function(out) {
$scope.agents = out;
$scope.showUsers = true;
$scope.selectedOption = $scope.agents[0];
});
};
$scope.init = function (cityName) {
$scope.cityName.query = cityName;
if ((typeof cityName !== "undefined")) {
$scope.findAgent();
}
};
$scope.$watch('cityName.query', function (newValue, oldValue) {
$scope.cityName.query.watch = newValue;
});
});
Now I have a validation error in Chrome... (I'm using jQuery validation).
Here is the code I'm using to disable this error:
$.validator.addMethod('date', function (value, element, params) {
if (this.optional(element)) {
return true;
}
var isValid = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2} \d{2}:\d{1,2}:\d{1,2}$/.test(value);
alert(isValid);
return isValid;
}, '');
But when I use the jquery code angularjs stops working...
Some one have met this issue??? If so how to solve it?

How to call isValid() function in the viewmodel using knockout-validation

I have a viewmodel defined following:
var ViewModel = function() {
var self = this;
self.property1 = ko.observable().extend({ required: true });
self.property2 = ko.computed(function() {
return self.property1();
});
self.form_onsubmit = function (form) {
if (!self.isValid()) {
console.log("error");
}
return false;
};
};
$(function () {
ko.applyBindingsWithValidation(new ViewModel());
});
when i call the form_onsubmit function, an error occured:
TypeError: self.isValid is not a function
if (!self.isValid()) {
how to solve it, thanks^^^
add
self.errors = ko.validation.group(self);
to your viewmodel

Private_pub : How to unsubscribe from a channel

I am making a private chatting application using private_pub, my question is how to unsubscribe from a channel using private_pub?
thanks for your help
if you are using pjax or ajax a lot in your site and the page you are loading with ajax you have private_pub subscribe method there you will find that It's subscribing many times
after searching a lot about that I found these fork from privat_pub javascript file which solved these problem
var PrivatePub = (function (doc) {
var self = {
connecting: false,
fayeClient: null,
fayeCallbacks: [],
subscriptions: {},
subscriptionCallbacks: {},
faye: function(callback) {
if (self.fayeClient) {
callback(self.fayeClient);
} else {
self.fayeCallbacks.push(callback);
if (self.subscriptions.server && !self.connecting) {
self.connecting = true;
if (typeof Faye === 'undefined') {
var script = doc.createElement("script");
script.type = "text/javascript";
script.src = self.subscriptions.server + ".js";
script.onload = self.connectToFaye;
doc.documentElement.appendChild(script);
} else {
self.connectToFaye();
}
}
}
},
connectToFaye: function() {
self.fayeClient = new Faye.Client(self.subscriptions.server);
self.fayeClient.addExtension(self.fayeExtension);
for (var i=0; i < self.fayeCallbacks.length; i++) {
self.fayeCallbacks[i](self.fayeClient);
};
},
fayeExtension: {
outgoing: function(message, callback) {
if (message.channel == "/meta/subscribe") {
// Attach the signature and timestamp to subscription messages
var subscription = self.subscriptions[message.subscription];
if (!message.ext) message.ext = {};
message.ext.private_pub_signature = subscription.signature;
message.ext.private_pub_timestamp = subscription.timestamp;
}
callback(message);
}
},
sign: function(options) {
if (!self.subscriptions.server) {
self.subscriptions.server = options.server;
}
if (!self.subscriptions[options.channel]) {
self.subscriptions[options.channel] = options;
self.faye(function(faye) {
faye.subscribe(options.channel, self.handleResponse);
});
}
},
handleResponse: function(message) {
if (message.eval) {
eval(message.eval);
}
if (callback = self.subscriptionCallbacks[message.channel]) {
callback(message.data, message.channel);
}
},
subscribe: function(channel, callback) {
self.subscriptionCallbacks[channel] = callback;
}
};
return self;
}(document));
try it.

Resources