How to add dynamic values to field injections list with custom trigger to camunda properties panel? - camunda

I have two questions here
Is it possible to add dynamic lists values to field injection list input ?
Can I create a trigger for this so this can be initiated from any other input selection say a class selection will populate all fields
I was just looking into FieldInjection.js whether that can be extented for the same
Can someone please provide a hint or direction for this ?
Thanks.

For anyone interested in the answer, I was able to achieve the above goal by changing the set function of the Java Class select input as folllowing
few imports
var extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'),
elementHelper = require('../../../../helper/ElementHelper')
var CAMUNDA_FIELD_EXTENSION_ELEMENT = 'camunda:Field';
function getExtensionFields(bo) {
return bo && extensionElementsHelper.getExtensionElements(bo, CAMUNDA_FIELD_EXTENSION_ELEMENT) || [];
}
then changing the set function to create extension element and push the field values as :
set: function(element, values, node) {
var bo = getBusinessObject(element);
var type = getImplementationType(element);
var attr = getAttribute(type);
var prop = {}
var commands = [];
prop[attr] = values.delegate || '';
var extensionElements = getExtensionFields(bo);
//remove any extension elements existing before
extensionElements.forEach(function(ele){
commands.push(extensionElementsHelper.removeEntry(getBusinessObject(element), element, ele));
});
if(prop[attr] !== ""){
var extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory);
commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements }));
var arrProperties = ["private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varOne","private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varTwo"]
var newFieldElem = "";
arrProperties.forEach(function(prop){
var eachProp = {
name:"",
string:"",
expression:""
}
var type = prop.split(" ")[1].split(".").reverse()[0];
var val = prop.split(" ")[2].split(".").reverse()[0];
eachProp.name = val;
if( type == "String"){
eachProp.string = "${" + val +" }"
}else if( type == "Expression"){
eachProp.expression = "${" + val +" }"
}
newFieldElem = elementHelper.createElement(CAMUNDA_FIELD_EXTENSION_ELEMENT, eachProp, extensionElements, bpmnFactory);
commands.push(cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newFieldElem ]));
});
}
commands.push(cmdHelper.updateBusinessObject(element, bo, prop));
return commands;
}
Cheers !.

Related

Google Sheet Script - if else, checking if cells match

looking for some help with the function below. I'm trying to have it check if a file has been updated in Google Drive before running a import script. I have it down to checking if two dates/times match in a sheet, but I can't seem to get it to correctly register whether they match. It should either be when S3 <> T3 or when U3 = FALSE. Any help would be greatly appreciated!!
function syncCSVtransactions() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getSheetByName("LOOKUP")
var cell_trnsnew = sh.getRange("S3");
var cell_trnsold = sh.getRange("T3");
var cell_trnscheck = sh.getRange("U3");
if( cell_trnsnew != cell_trnsold ){ //this is the line giving trouble
var source_file = DriveApp.getFilesByName("data_export.csv").next();
var csvData = Utilities.parseCsv(source_file.getBlob().getDataAsString());
var sheet2 = ss.getSheetByName('trs');
sheet2.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
cell_trnsnew.copyTo(cell_trnsold, {contentsOnly:true});
chartupdate();
} else {
}
}
I think that in your script, var cell_trnsnew = sh.getRange("S3");, var cell_trnsold = sh.getRange("T3"); and var cell_trnscheck = sh.getRange("U3"); can be written by one call. And, although I'm not sure about the values of your "LOOKUP" sheet, how about the following 2 patterns?
Pattern 1:
In this pattern, it supposes that the values of "S3", "T3" and "U3" are the date object, the date object and boolean, respectively.
From:
var cell_trnsnew = sh.getRange("S3");
var cell_trnsold = sh.getRange("T3");
var cell_trnscheck = sh.getRange("U3");
if( cell_trnsnew != cell_trnsold ){
To:
var [cell_trnsnew, cell_trnsold, cell_trnscheck] = sh.getRange("S3:U3").getValues()[0];
if (cell_trnsnew.getTime() != cell_trnsold.getTime() || cell_trnscheck === false) {
Pattern 2:
In this pattern, the values of "S3", "T3" and "U3" are used as the string values.
From:
var cell_trnsnew = sh.getRange("S3");
var cell_trnsold = sh.getRange("T3");
var cell_trnscheck = sh.getRange("U3");
if( cell_trnsnew != cell_trnsold ){
To:
var [cell_trnsnew, cell_trnsold, cell_trnscheck] = sh.getRange("S3:U3").getDisplayValues()[0];
if (cell_trnsnew != cell_trnsold || cell_trnscheck == "FALSE") {
References:
getValues()
getDisplayValues()

How do I get an alert prompt when an "if" statement returns no 'finds' in Google Apps Script?

//Invoice find and transfer to Warehouse Sheet
function searchInvoiceWhSh() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var shUserForm = ss.getSheetByName("Warehouse Form")
var shSalesSheet = ss.getSheetByName("Sales")
var sValue = shUserForm.getRange("G5").getValue();
var sData = shSalesSheet.getDataRange().getValues();
var currentRow = 9
for (var i=0; i<sData.length; i++) {
var row = sData[i];
if (row[0] == sValue) { //do something}
currentRow += 2
}}
I've used this to search for an "Invoice number" from the "Sales" worksheet and when found to transfer the data back to the user form.
If, for example, the invoice number is typed incorrectly into the "sValue" cell, then no data will be transferred.
How do I code a prompt message to ask the user to check the invoice number as no records were found?
Try:
function searchInvoiceWhSh() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const shUserForm = ss.getSheetByName("Warehouse Form")
const shSalesSheet = ss.getSheetByName("Sales")
const sValue = shUserForm.getRange("G5").getValue()
const sData = shSalesSheet.getDataRange().getValues()
const targetData = sData.filter(row => row[0] === sValue)
if (targetData.length) {
// Value(s) found
targetData.forEach(row => {
Logger.log(row)
})
} else {
SpreadsheetApp.getUi().alert(`No match found.`)
}
}
This will search for the sValue provided as in your code, but will store the row in a variable once found. If it's not found, it will create an alert pop-up with your specified message.
Alternatively, you can check out UI Class for other pop-up options.
Try it like this:
function myfunk() {
var ss = SpreadsheetApp.getActive()
var fsh = ss.getSheetByName("Warehouse Form")
var ssh = ss.getSheetByName("Sales")
var fv = fsh.getRange("G5").getValue();
var svs = ssh.getDataRange().getValues();
let m = 0;
svs.forEach((r, i) => {
if (r[0] == fv) {
m++;
}
SpreadsheetApp.getUi().alert(`${m} matches found`)
});
}
Always provides a result

Sharepoint 2013 JSOM : How to iterate through each item of list (get column values) and get information of its parent lookup list columns as well.

List1 have a lookup column to List2. I need column values for both lists using JSOM.
Currently i am getting Column values from List1 for each item within executeAsync call...
var List1 = context.get_web().get_lists().getByTitle('List1');
var List2 = context.get_web().get_lists().getByTitle('List2');
var collListItem = List1.getItems(camlQuery);
context.load(collListItem);
context.executeQueryAsync(onQuerySucceeded, onQueryFailed);
function onQuerySucceeded(sender, args) {
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
var listItemProject = oListItem.get_item('ProjectID'); // my lookup column
var listProjectLookupId = listItemProject.get_lookupId();
var itemProject = List2.getItemById(listProjectLookupId);
var country= null;
context.load(itemProject);
context.executeQueryAsync(function () {
country = itemProject.get_item('Country'); // columns from List2
});
// using column values from both lists
}
enter code here
But in second Async call i'm getting null values.. may be they are not happening one after another..
I would suggest you to utilize List Joins and Projections to retrieve data from parent/child lists.
Assume the following lists:
Contacts - contains Country lookup field (target list: Countries)
Countries
Then the following example demonstrates how to retrieve list items from both lists.
Example
function createJoinQuery(joinListTitle,joinFieldName,projectedFields)
{
var queryText =
"<View>" +
"<Query/>" +
"<ProjectedFields>";
for(var idx in projectedFields) {
queryText += String.format("<Field Name='{0}_{1}' Type='Lookup' List='{0}' ShowField='{1}' />",joinListTitle,projectedFields[idx]);
}
queryText +=
"</ProjectedFields>" +
"<Joins>" +
"<Join Type='INNER' ListAlias='{0}'>" +
"<Eq>" +
"<FieldRef Name='{1}' RefType='Id'/>" +
"<FieldRef List='{0}' Name='ID'/>" +
"</Eq>" +
"</Join>" +
"</Joins>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,joinListTitle,joinFieldName));
return qry;
}
function getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createJoinQuery(joinListTitle,joinFieldName,projectedFields));
ctx.load(items);
ctx.executeQueryAsync(
function() {
success(items);
},
error
);
}
Usage
var listTitle = 'Contacts';
var joinListTitle = 'Countries'
var joinFieldName = 'Country';
var projectedFields = ['ID','Title'];
getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,
function(items){
//print items
for(var i = 0; i < items.get_count(); i++){
var item = items.getItemAtIndex(i);
var contactName = item.get_item('Title');
var countryName = item.get_item('Countries_Title').get_lookupValue();
}
},
function(sender,args){
console.log(args.get_message());
});

CRM Late Bound - Cleaner Approach

I have the following code and I'm trying to find a more elegant approach to this. activityParty is a DataCollection. I am basically trying to get a list of recipients for an email, which can be of type users or contacts.
I am familiar with early bound but in this scenario must use late bound.
Is there a better approach to this?
var recipientParty = activityParty.Where(x => x.GetAliasedValueOrDefault<OptionSetValue>("ap.participationtypemask").Value == 2).ToList();
var recipientList = new List<string>();
foreach (var to in recipientParty)
{
if (to.Attributes.Contains("u.internalemailaddress"))
{
recipientList.Add(to.GetAliasedValueOrDefault<string>("u.internalemailaddress"));
}
if (to.Attributes.Contains("c.emailaddress1"))
{
recipientList.Add(to.GetAliasedValueOrDefault<string>("c.emailaddress1"));
}
}
Have a look at AddressUsed property of ActivityParty entity. It should contain email address, regardless which entity is source of party involved.
So, in your code you can use to.AddressUsed instead whole if {...} statement.
Try this:
using (var serviceContext = new OrganizationServiceContext(this.OrganizationService)) // if you are writing custom code activity
//using (var serviceContext = new OrganizationServiceContext(localContext.OrganizationService)) // if you are writing plugin
{
var activityPartySet = serviceContext.CreateQuery<ActivityParty>();
var activityParties = activityPartySet.Where(
ap => ap.PartyId != null &&
ap.ParticipationTypeMask != null &&
ap.ParticipationTypeMask.Value == 2).ToList();
var userSet = serviceContext.CreateQuery<SystemUser>();
var contactSet = serviceContext.CreateQuery<Contact>();
var recipientList = new List<string>();
foreach (var ap in activityParties)
{
var partyRef = ap.PartyId;
if (partyRef.LogicalName == SystemUser.EntityLogicalName)
{
var user = (from u in userSet
where u.Id == partyRef.Id
select new SystemUser
{
InternalEMailAddress = u.InternalEMailAddress
}).FirstOrDefault();
if (user != null)
recipientList.Add(user.InternalEMailAddress);
}
else if (partyRef.LogicalName == Contact.EntityLogicalName)
{
var contact = (from c in contactSet
where c.Id == partyRef.Id
select new Contact
{
EMailAddress1 = c.EMailAddress1
}).FirstOrDefault();
if (contact != null)
recipientList.Add(contact.EMailAddress1);
}
}
}
Hope it helps!

How to pass 2 lists to 1 view

I want to show recent and incoming appointments in my view(one page).Here is my controller where can i add the second list and how can i pass it to same view?I know I cant return two list but there must be way for it?
public ActionResult Index()
{
if (Session["UserEmail"] != null)
{
string Email = (string)Session["UserEmail"];
using (var db = new MaindbModelDataContext())
{
var patient = db.Patients.FirstOrDefault(u => u.Email == (String)Session["UserEmail"]);
ViewBag.FirstName = patient.Name;
ViewBag.LastName = patient.Surname;
ViewBag.BirthDate = patient.Birthday;
ViewBag.Email = patient.Email;
}
using (var db = new MaindbModelDataContext())
{
var patient = db.Patients.FirstOrDefault(u => u.Email == (String)Session["UserEmail"]);
var listrecent = (from y in db.Appointments
where y.PatientNo == patient.PatientNo
where y.Date < DateTime.Today
orderby y.Date descending
select y).Take(5);
var TempRecent = new List<Models.AppModel>();
foreach (var item in listrecent)
{
var Temp = new Models.AppModel();
Temp.AppNo = item.AppNo;
Temp.PatientNo = (Int32)item.PatientNo;
Temp.Date = (DateTime)item.Date;
Temp.Status = item.Status;
Temp.Description = item.Description;
TempRecent.Add(Temp);
}
return View(TempRecent);
}
}
else
{
return RedirectToAction("RegAndLogin", "User");
}
}
}
}
and here is my view part
#model IEnumerable<DentAppSys.Models.AppModel>
#using System.Web.Helpers
#{
ViewBag.Title = "Index";
}
<section class="Patient-Dashboard">
<div id="dashboard_left">
<h1> Recent Appointments</h1>
#{
var Mygrid = new WebGrid(Model, selectionFieldName: "SelectedRow");
}
#Mygrid.GetHtml(
displayHeader: true,
mode: WebGridPagerModes.FirstLast,
columns: Mygrid.Columns
(
Mygrid.Column("Appointment No", "Appointment No",format: #<text>#item.AppNo</text>),
Mygrid.Column("Patient No", "Patient No", format: #<text>#item.PatientNo</text>) ,
Mygrid.Column("Description", "Description", format: #<text>#item.Description</text>),
Mygrid.Column("Date", "Date", format: #<text>#item.Date.ToString("yyyy/MM/dd")</text>),
Mygrid.Column("Status", "Status", format: #<text>#item.Status</text>)
))
</div>
<div id="dashboard_right">
<br/>
<h1>Incoming Appointments</h1>
/* HERE I WANT TO ADD MY SECOND LIST*/
</div>
</section>
Edit:
and after using two instances of the AppModel I get error when I try to equal Temp.RecentIncoming.AppNo=item.AppNo.
using (var db = new MaindbModelDataContext())
{
var patient = db.Patients.FirstOrDefault(u => u.Email == (String)Session["UserEmail"]);
var listincoming = (from y in db.Appointments
where y.PatientNo == patient.PatientNo
where y.Date > DateTime.Today
orderby y.Date descending
select y).Take(5);
var TempIncoming = new List<Models.RecentIncoming>();
foreach (var item in listincoming)
{
var Temp = new Models.RecentIncoming.;
Temp.RecentIncoming.AppNo?????= item.AppNo;
Temp.PatientNo = (Int32)item.PatientNo;
Temp.Date = (DateTime)item.Date;
Temp.Status = item.Status;
Temp.Description = item.Description;
TempIncoming.Add(Temp);
}
return View(TempIncoming);
}
Instead of having IEnumerable as your model, create a new model class that has two instances of the AppModel as well as any other additional data you need to pass to the view...
public class MyAppointments
{
public IEnumerable<DentAppSys.Models.AppModel> RecentAppts;
public IEnumerable<DentAppSys.Models.AppModel> IncomingAppts;
public MyAppointments() { }
}
...
return View( new MyAppointments() { RecentAppts=TempRecent, IncomingAppts=TempIncoming } );
Change the view to...
#model MyAppointments
...
#{
var MyRecentgrid = new WebGrid(Model.RecentAppts, selectionFieldName: "SelectedRow");
var MyIncomingGrid = new WebGrid(Model.IncomingAppts, selectionFieldName: "SelectedRow");
}