Hello Community, 

 

Is it possible to bind the title of the form page from "New Record"  to a field value on load of a page in freedom UI.

 

Thanks

Gargeyi.G

Like 0

Like

1 comments

Hello,

You can change that by adding a handler like this - note this will change the value from "New record" when adding a new record for the page:

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.HandleViewModelInitRequest",
		handler: async (request, next) => {
			const result = await next?.handle(request);
 
			const cardState = await request.$context.CardState;
			if (cardState == "add" || cardState == "copy") {
				request.$context.HeaderCaption = "Add a new something";
			}
 
			return result;
		}
	}
]/**SCHEMA_HANDLERS*/,

As far as binding it to some page value, you could use the same but first get a value from the page. Something like this:

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.HandleViewModelInitRequest",
		handler: async (request, next) => {
			const result = await next?.handle(request);
 
			const cardState = await request.$context.CardState;
			if (cardState == "add" || cardState == "copy") {
				request.$context.HeaderCaption = "Add a new something";
			}
			else {
				// get a value from the page
				const someValue = request.$context.someAttributeOnThePage;
				request.$context.HeaderCaption = someValue;
			}
 
			return result;
		}
	}
]/**SCHEMA_HANDLERS*/,

Ryan

Show all comments

Perform verification whenever a user adds or modifies a daily tour offer as follows: if the total number of active daily tours exceeds the system setting value , saving a record should not be permitted. Instead, a user should receive a message informing that no more than “N” daily tours can be active at a time. “N” is the system setting value.

 

Here is my code : 

asyncValidate: function(callback, scope) {
    this.callParent([
        function(response) {
            if (!this.validateResponse(response)) {
                return;
            }
            this.validateTravelOfferTour(function(response) {
                if (!this.validateResponse(response)) {
                    return;
                }
                callback.call(scope, response);
            }, this);
        }, this
    ]);
},
 
validateTravelOfferTour: function(callback, scope) {
    // Fetch the Maximum Number Of Daily Periodical Editions System Setting
    var mySetting = Terrasoft.SysSettings.cachedSettings.Usr_Max_Number_Activity_Tours;
    var FrequencyObject=this.get("UsrTravelOfferFrequency");
    if(!FrequencyObject){
        if(callback){
            callback.call(scope,{
                success:true
            });
        }
        return;
    }
    var FrequencyId=FrequencyObject.value;
    //create query
    var esq=this.Ext.create("Terrasoft.EntitySchemaQuery",{
        rootSchemaName:"UsrTravelOffers"
    });
    //esq.addAggregationSchemaColumn("UsrActive",Terrasoft.AggregationType.)
    var ActivityFilter = esq.createColumnFilterWithParameter(0, "UsrActive", "1");
    var frequencyFilter=esq.createColumnFilterWithParameter(0,"UsrTravelOfferFrequency",FrequencyId);
    esq.filters.addItem(frequencyFilter);
    esq.filters.addItem(ActivityFilter);
 
    // Aggregation to get the Count of resulting Query
    esq.addAggregationSchemaColumn("UsrActive", Terrasoft.AggregationType.COUNT, "ActiveOffers");
    //run query
    // Get the entire esq result colelction
    esq.getEntityCollection(function(result) {
        if (result.success && result.collection) {
            // Store the Count of Filtered Records to a variabble
            var items = result.collection.getItems();
            if(items.length>0){
                esqresult=items[0].get("ActiveOffers");
            }
            if(esqresult==mySetting){
                if(callback){
                    callback.call(this,{
                        success:false,
                        message:"no more than 3 daily tours can be active at a time."
                    });
                }
            }else
                if(callback){
                    callback.call(scope,{
                        success:true
                    });
                }
        }
    },this);
},

and this is the error :

{"responseStatus":{"ErrorCode":"InvalidObjectStateException","Message":"Condition with type \"Between\" must contain two expressions in the left part.","Errors":[]},"rowsAffected":-1,"nextPrcElReady":false,"success":false}

 

Like 0

Like

3 comments
Best reply

Since it's more of a question about the ESQ, the first parameter for createColumnFilterWithParameter is a value from Terrasoft.ComparisonType. You have a 0 (zero) there, which means a BETWEEN. Instead it should be 3, which is EQUAL. It's better to use the value Terrasoft.ComparisonType.EQUAL so the code is easier to read.

var ActivityFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrActive", "1");
var frequencyFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,"UsrTravelOfferFrequency", FrequencyId);

Ryan

Hello,

 

Thanks for your question. Please note that posting certification questions is not encouraged on our platform.

 

Thank you for understanding!

 

Best regards,

Anastasiia

Since it's more of a question about the ESQ, the first parameter for createColumnFilterWithParameter is a value from Terrasoft.ComparisonType. You have a 0 (zero) there, which means a BETWEEN. Instead it should be 3, which is EQUAL. It's better to use the value Terrasoft.ComparisonType.EQUAL so the code is easier to read.

var ActivityFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "UsrActive", "1");
var frequencyFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,"UsrTravelOfferFrequency", FrequencyId);

Ryan

Ryan Farley,Thank you that was it.

Show all comments

Hi Community, 



Is there anyone who might be able to help me with the code below? I am trying to filter a lookup column, by the value of another lookup column on the same page.

Specifically, my column "PrimaryContact" should be filter Contacts where the "Account" is equal to the "UsrCompanyName" of the same page. 



I've tried many things in the "Value" for rightExpression, but can't seem to get it to work. The rest of the code seems okay because if I add a Guid of an Account to the value, it filters fine. 



Thanks!



 

"LookupAttribute_j53fgnq_List_BusinessRule_Filter": {
					"value": {
						"filterType": 6,
						"isEnabled": true,
						"items": {
							"CustomFilters": {
								"filterType": 6,
								"isEnabled": true,
								"items": {
									"cb855fc4-4526-475a-beea-8e41a7f5a439": {
										"comparisonType": 11,
										"filterType": 1,
										"isEnabled": true,
										"leftExpression": {
											"expressionType": 0,
											"columnPath": "Account"
										},
										"rightExpression": {
											"expressionType": 2,
											"parameter": {
												"dataValueType": 1,
												"value": "$PDS.UsrCompanyName.Id"
											}
										},
										"trimDateTimeParameterToDate": false
									}
								}
							}
						}
					}
				}, 
 

 

Like 2

Like

4 comments
Best reply

Hi Harry,

It would be easier to handle the request for when the lookup requests its data source and then add the filters to that request since you'd have access to page data.

When the lookup is activated (user clicks the dropdown) it sends a crt.LoadDataRequest. You can listen for that and then add the filters there. The request would look something like this: 

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.LoadDataRequest",
		handler: async (request, next) => {
		    // the data soruce name will be the lookup attribute name + "_List_DS"
			if (request.dataSourceName !== "LookupAttribute_46uzwvy_List_DS") {
				return await next?.handle(request);
			}
 
			// get other page values
			const compId = request.$context.UsrCompanyName.value;
 
			// add filter
			request.parameters.push({
				type: "filter",
				value: {
						"filterType": 6,
						"isEnabled": true,
						"items": {
							"CustomFilters": {
								"filterType": 6,
								"isEnabled": true,
								"items": {
									"cb855fc4-4526-475a-beea-8e41a7f5a439": {
										"comparisonType": 11,
										"filterType": 1,
										"isEnabled": true,
										"leftExpression": {
											"expressionType": 0,
											"columnPath": "Account"
										},
										"rightExpression": {
											"expressionType": 2,
											"parameter": {
												"dataValueType": 1,
												"value": compId
											}
										},
										"trimDateTimeParameterToDate": false
									}
								}
							}
						}
			});
 
			return await next?.handle(request);
		}
	}
]/**SCHEMA_HANDLERS*/,

As a side note, for the filter, I believe something along these lines should work. It's close the working, but the end result request shows in the network tab that the filter key and filter values get added separately to the filters array causing a server error. Hopefully we'll get more details on this sort of thing soon:

(Note, the below doesn't work yet, but sharing it in case someone else gets it to work)

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.LoadDataRequest",
		handler: async (request, next) => {
		    // data soruce name is lookup attribute + "_List_DS"
			if (request.dataSourceName !== "LookupAttribute_46uzwvy_List_DS") {
				return await next?.handle(request);
			}
 
			let filters = new sdk.FilterGroup();
			filters.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "Type.Name", "Partner");
 
			// add filter
			request.parameters.push({
				type: sdk.ModelParameterType.Filter,
				value: filters
			});
 
			return await next?.handle(request);
		}
	}
]/**SCHEMA_HANDLERS*/,

Ryan

Hi Harry,

 

In case you doubt about the filtration on the column you can create a test list based on the object of your lookup column and specify the needed filtration there:

and

save the page and open the code. As a result you will see an autogenerated code of the working filtration that then can be applied to the column:

HI Oleg, 



Thank you. This example works well when applying a static filter. However, it seems not to work the same when trying to apply filter by page data. 



Do you have any example how to translate this same method so that I can filter a lookup column by page data? 



Thank you 

Hi Harry,

It would be easier to handle the request for when the lookup requests its data source and then add the filters to that request since you'd have access to page data.

When the lookup is activated (user clicks the dropdown) it sends a crt.LoadDataRequest. You can listen for that and then add the filters there. The request would look something like this: 

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.LoadDataRequest",
		handler: async (request, next) => {
		    // the data soruce name will be the lookup attribute name + "_List_DS"
			if (request.dataSourceName !== "LookupAttribute_46uzwvy_List_DS") {
				return await next?.handle(request);
			}
 
			// get other page values
			const compId = request.$context.UsrCompanyName.value;
 
			// add filter
			request.parameters.push({
				type: "filter",
				value: {
						"filterType": 6,
						"isEnabled": true,
						"items": {
							"CustomFilters": {
								"filterType": 6,
								"isEnabled": true,
								"items": {
									"cb855fc4-4526-475a-beea-8e41a7f5a439": {
										"comparisonType": 11,
										"filterType": 1,
										"isEnabled": true,
										"leftExpression": {
											"expressionType": 0,
											"columnPath": "Account"
										},
										"rightExpression": {
											"expressionType": 2,
											"parameter": {
												"dataValueType": 1,
												"value": compId
											}
										},
										"trimDateTimeParameterToDate": false
									}
								}
							}
						}
			});
 
			return await next?.handle(request);
		}
	}
]/**SCHEMA_HANDLERS*/,

As a side note, for the filter, I believe something along these lines should work. It's close the working, but the end result request shows in the network tab that the filter key and filter values get added separately to the filters array causing a server error. Hopefully we'll get more details on this sort of thing soon:

(Note, the below doesn't work yet, but sharing it in case someone else gets it to work)

handlers: /**SCHEMA_HANDLERS*/[
	{
		request: "crt.LoadDataRequest",
		handler: async (request, next) => {
		    // data soruce name is lookup attribute + "_List_DS"
			if (request.dataSourceName !== "LookupAttribute_46uzwvy_List_DS") {
				return await next?.handle(request);
			}
 
			let filters = new sdk.FilterGroup();
			filters.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "Type.Name", "Partner");
 
			// add filter
			request.parameters.push({
				type: sdk.ModelParameterType.Filter,
				value: filters
			});
 
			return await next?.handle(request);
		}
	}
]/**SCHEMA_HANDLERS*/,

Ryan

Thank you, Ryan. That worked perfectly. 

Show all comments

Good day!

Tried to set up your application on our system. But unfortunately, there were errors. Nothing happens when you save the settings for a recurring activity. Activities are not duplicated (although there is no error).

Maybe not all categories can use them?

please contact me and help)

Thank you)

Like 0

Like

7 comments

This package in the marketplace is for MSSQL systems only. If this is a could system it's most likely a Postgresql system, not MSSQL. The package will install on a Postgresql system, but won't work (and I believe doesn't show any errors). Do you know if the system it's installed on is MSSQL database or not? 

Ryan

Seems bizarre there is no Postgres support given most Creatio cloud environments run on this.

Lewis Pull,

I agree. This would be a very useful add-on. I would love to see this work with new systems (actually should be added as a base part of Creatio)

Ryan

Hi Yana, Ryan and Lewis,

The developer does not have plans to add PostgreSQL compatibility. Therefore, we decided to remove this add-on from the Marketplace.

Also, we have sent feedback to our R&D team about including such functionality in Creatio out of the box.

Irina Lazorenko,

Hi Irina, do you know if there are any plans for this agreed? This is a feature we would really benefit from.

Very bizarre that this is not a standard feature within any CRM to be honest.

@Irina Lazorenko, any plans to implement this?

Show all comments

Hi guys,

I am working on a custom "ContactFieldConverter" [the thing that splits the Contact's FullName imported by excel/ webserveces etc] in order to split new contact's names into "GivenName" and "Surname", and preventing the OOTB function from filling in the "MiddleName" column.

In order to do so, I created a custom ContactGsFieldConverter in my package and inserted the value of the Separator and Converter in the Lookup "ShowNamesBy" and sysSetting "ContactFieldConverter".

[myContactGsFieldConverter code:]

 

 namespace Terrasoft.Configuration {
	using System;
	using System.Linq;
	using System.Text;
	using Terrasoft.Common;
	using Terrasoft.Configuration;
 
	#region Class: myContactGsFieldConverter
 
	/// <summary>
	/// Contact "Full name" field converter class.
	/// Separates "Full name" string using "Given name Surname" rule.
	/// </summary>
	public class myContactGsFieldConverter : IContactFieldConverter
	{
 
		#region Properties: Public
 
		/// <summary>
		/// Contact "Full name" separator characters array.
		/// </summary>
		private char[] _separator = { ' ' };
		public char[] Separator {
			get {
				return _separator;
			}
			set {
				_separator = value;
			}
		}
 
		#endregion
 
		#region Methdos: Public
 
		/// <summary>
		/// <see cref="IContactFieldConverter.GetContactSgm"/>
		/// </summary>
		/// <remarks>
		/// After splitting <paramref name="name"/> first element will be used as <see cref="ContactSgm.GivenName"/>,
		/// Everything else as <see cref="ContactSgm.Surname"/>.
		/// </remarks>
		ContactSgm IContactFieldConverter.GetContactSgm(string name) {
			var sgm = new ContactSgm();
			if (string.IsNullOrEmpty(name)) {
				return sgm;
			}
 
			var array = name.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
			switch (array.Length) {
				case 0:
					return sgm;
				case 1:
					sgm.GivenName = array[0];
					break;
				case 2:
					sgm.GivenName = array[0];
					sgm.Surname = array[1];
					break;
				default:
					sgm.GivenName = array[0];
					StringBuilder sb = new StringBuilder();
					for (var i = 1; i <= array.Length - 1; i++) {
						sb.AppendFormat("{0} ", array[i]);
					}
					sgm.Surname = sb.ToString().Trim();
					break;
			}
			return sgm;
		}
 
		/// <summary>
		/// <see cref="IContactFieldConverter.GetContactName"/>
		/// </summary>
		/// <remarks>
		/// "Full name" string will be created using "Given name [Middle name] Surname" rule.
		/// </remarks>
		public string GetContactName(ContactSgm sgm) {
			var concatChar = Separator.FirstOrDefault();
			return new[] { sgm.GivenName, sgm.MiddleName, sgm.Surname }.ConcatIfNotEmpty(concatChar.ToString());
		}
		#endregion
	}
	#endregion	
}

The converter is not working. I tried to debug and noticed that my contact converter is returned as null to [this is a method in the Contact c# object]: 

public virtual void SetSgm(Contact contact) {
			if (contact == null) {
				return;
			}
			contact.FillSgmFields(GetContactConverter());
		}

Do you know if I need to do something specific in case of separate-assembly package?

ie: Using a different namespace for the converter/ setting the converter path in a different way within the system setting/ recreate the method on the Contact Object in my custom package.





Thank you in advance!

Like 0

Like

4 comments

Hello Federica,

 

I just completed the test - convertor works in the assembly package as well. The code (since we don't need middle name) was:

namespace Terrasoft.Configuration {
    using System;
    using System.Linq;
    using System.Text;
    using Terrasoft.Common;
    #region Class: UsrCustomContactFieldConverter
    /// &lt;summary&gt;
    /// Contact "Full name" field converter class.
    /// Separates "Full name" string using "Surname Given name" rule.
    /// &lt;/summary&gt;
    public class UsrCustomContactFieldConverter : IContactFieldConverter
    {
        #region Properties: Public
        /// &lt;summary&gt;
        /// Contact "Full name" separator characters array.
        /// &lt;/summary&gt;
        private char[] _separator = { ' ' };
        public char[] Separator {
            get {
                return _separator;
            }
            set {
                _separator = value;
            }
        }
        #endregion
        #region Methdos: Public
        /// &lt;summary&gt;
        /// &lt;see cref="IContactFieldConverter.GetContactSgm"/&gt;
        /// &lt;/summary&gt;
        /// &lt;remarks&gt;
        /// After splitting &lt;paramref name="name"/&gt; first element will be used as &lt;see cref="ContactSgm.Surname"/&gt;,
        /// second element as &lt;see cref="ContactSgm.GivenName"/&gt;
        /// &lt;/remarks&gt;
        ContactSgm IContactFieldConverter.GetContactSgm(string name) {
			var sgm = new ContactSgm();
			if (string.IsNullOrEmpty(name)) {
				return sgm;
			}
			var array = name.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
			switch (array.Length) {
				case 0:
					return sgm;
				case 1:
					sgm.GivenName = array[0];
					break;
				default:
					sgm.GivenName = array[0];
					sgm.Surname = array[1];
					break;
			}
			return sgm;
		}
        /// &lt;summary&gt;
        /// &lt;see cref="IContactFieldConverter.GetContactName"/&gt;
        /// &lt;/summary&gt;
        /// &lt;remarks&gt;
        /// "Full name" string will be created using "Surname Given name" rule.
        /// &lt;/remarks&gt;
        public string GetContactName(ContactSgm sgm) {
            var concatChar = Separator.FirstOrDefault();
            return new[] { sgm.Surname, sgm.GivenName }.ConcatIfNotEmpty(concatChar.ToString());
        }
        #endregion
    }
    #endregion
 
}

and then this convertor was registered in the database (ShowNamesBy table). As a result newly created contacts where full name is Test 1 2 had the first (Test) and last (1) name only while middle name was skipped.

Hi Oleg Drobina,

Could you share with me the record registered in the database table ShowNamesBy for a separate assembly pkg?

Hence, in case the site receives a Contact "Name": "Federica Rose Cattani" I don't want to "lose" the "MiddleName" but I want it to be concat to the "Surname". That's what I did in the converter shared. 

Federica,

 

Hi,

 

Sorry, I guess I was wrong with the package. Tested the same approach today and it didn't work until I unchecked the "Compile into separate assembly" checkbox in the package settings. So in your case you need to also do the same to make the converter work.

 

The insert was:

INSERT INTO ShowNamesBy (Name, Separator, Converter) VALUES (N'UsrCustomContactFieldConverter', N' .,;', N'Terrasoft.Configuration.UsrCustomContactFieldConverter');

 

Oleg Drobina,

Ok! In my case I can't "undo" the separate assembly since it contains customer's implementation and separate assembly it's way faster to compile.

The actual possible workaround would be to implement a second package without separate assembly containing only the custom ContactGsFieldConverter, am I correct?

Show all comments

Hello I'm getting this issue after install the package from the marketplace https://marketplace.creatio.com/app/access-rights-setup-wizard-creatio

 

Like 0

Like

3 comments

Hi Federico!

I have installed this app and compiled the configuration successfully. Please send us more information to help us reproduce this issue:

1. What is your Creatio product and version?

2. When did you install the app? Was it the first installation or an update?

3. Have you modified the app package?

Hi Irina Lazorenko,

 

I update the version from the marketplace, I tried to delete the previous app and reinstalled and same issues shows up. Version is Sales Enterprise 8.0.4.1870.

There is a case open in support with the access to the site if you want to check.

Hi Federico!

To resolve this issue, take the following steps:

  1. Delete the Access rights setup wizard for Creatio app.
  2. Compile the configuration.
  3. Install the app from Creatio Marketplace.
Show all comments

Hi Community,

 

Do you have any example how to use asyncValidate during save and EntitySchemaQuery in freedom UI form page. I couldn't find more topics when it comes to client side coding in freedom UI.

 

 

Like 1

Like

6 comments

Hello Fulgen,

 

For creating the field validator - you need to use validators as described in the Academy article here. As for the ESQ in the Freedom UI page - unfrotunately we currently don't have any documentation on it, but we've created a task for our core R&D team to write the specification for ESQ usage in the Freedom UI page.

Hello Oleg,



Whether the document for the specification for ESQ usage in the Freedom UI page is prepared or when we can expect the documentation on the same.

Sivaranjani,

 

After verifying all the necessary information regarding specification for ESQ usage, I want to inform you that this task has been created and accepted. The process of writing such documentation may take some time, so for the moment you need to wait a while.



Thank you for your patience and understanding in this matter.

 

Sorry to jump in. Any update on the documentation?

Jahnavi,

Unfortunately the documentation is not ready yet. However, I have added your inquiry to the registered idea as to increase its priority and speed up the process.

Mira Dmitruk,

 

Any update on doing async validation in Freedom UI using validators? We need to use them, but don't have any examples in the academy as far as I can tell.

Show all comments

Can we hide a section from a workplace for a certain time frame?

 

Regards

Sivanesan

Like 0

Like

1 comments

Hello,

 

If you need to hide the section for some time for a specific user or group of users/role, you can simply remove the section for the needed time from a Workplace in which the user/group of users or specific user role is working and once needed add it to the Workplace again. 

You may also consider creating a separate Workplace for this user/users so it will be easier to manage. 

However, the user will still be able to access records or a section by a direct link for example, if you need to prevent it, we'd suggest considering changing access rights for the object for the user/user role. 



If we are talking about hiding a section for a specific timeframe, for example from 4 to 5 pm each day, such implementation can be done only by means of additional development. 

 

Best regards,

Yuliya Gritsenko

Show all comments

Hi Community,

 

Currently we are using Studio Enterprise, we've added new section from existing "Activity" object. Activity section is created having List and Dashboard view by default. How we can add the Calendar view here?

 

 

Like 0

Like

1 comments

Hello,

 

You can find the example oh how to add a Calendar view to a section in this Community post.

Show all comments

We are trying to set a dashboard to find out the user logged in to the system. We have set the below filter :

 

 

Question : When we try to login as a user then we need to see only that user usage and not the other user’s data also when the user manager logs in, then the manager needs to see his usage as well as the users associated to him in the org structure. How do we achieve this scenario?

 

Regards,

Mayan

Like 0

Like

1 comments

Hi,

 

Unfortunately, this task can not be achieved from the user's perspective 

You can create a custom widget, which allows you to upload data from the module which you customize yourself.



However, we will create a case for our R&D team on this matter so it may be implemented in the next releases.

Show all comments