From ffdaeca298107cab16aacbf64545c6d812e1f86e Mon Sep 17 00:00:00 2001 From: scottdurow Date: Tue, 18 Aug 2015 15:03:00 +0100 Subject: [PATCH] Resolves #65 #64 --- .../ClientUI/View/ConnectionsView.cs | 9 ++- .../ViewModel/ConnectionsViewModel.cs | 28 ++++++-- .../ViewModel/ObservableConnection.cs | 67 ++++++++++++++++-- .../ClientUI/ViewModel/QueryParser.cs | 9 ++- .../CrmPackage/WebResources/js/ClientUI.js | 17 +++-- .../RefreshedConnectionsUI_1_1_managed.zip | Bin 0 -> 15741 bytes 6 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 SparkleXrmSamples/RefreshedConnectionsUI_1_1_managed.zip diff --git a/SparkleXrmSamples/ConnectionsUI/ClientUI/View/ConnectionsView.cs b/SparkleXrmSamples/ConnectionsUI/ClientUI/View/ConnectionsView.cs index f7cf7ed6..ca018eb0 100644 --- a/SparkleXrmSamples/ConnectionsUI/ClientUI/View/ConnectionsView.cs +++ b/SparkleXrmSamples/ConnectionsUI/ClientUI/View/ConnectionsView.cs @@ -90,12 +90,11 @@ private static void InitLocalisedContent() QueryParser queryParser = new QueryParser(new string[] {"connection"}); queryParser.GetView("connection", defaultView); queryParser.QueryMetadata(); + EntityQuery connectionViews = queryParser.EntityLookup["connection"]; + string viewName = connectionViews.Views.Keys[0]; + FetchQuerySettings view = connectionViews.Views[viewName]; - // Get the columsn for the view - EntityQuery connectionViews = queryParser.EntityLookup["connection"]; - FetchQuerySettings view = connectionViews.Views[connectionViews.Views.Keys[0]]; - string fetchXml = queryParser.GetFetchXmlParentFilter(view, "record1id"); - vm = new ConnectionsViewModel(parent, entities.Split(","), pageSize, fetchXml); + vm = new ConnectionsViewModel(parent, entities.Split(","), pageSize, view); // Bind Connections grid GridDataViewBinder connectionsGridDataBinder = new GridDataViewBinder(); diff --git a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ConnectionsViewModel.cs b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ConnectionsViewModel.cs index 444e9b3b..10923e13 100644 --- a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ConnectionsViewModel.cs +++ b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ConnectionsViewModel.cs @@ -32,23 +32,32 @@ public class ConnectionsViewModel : ViewModelBase public DependentObservable AllowAddNew; public Observable ParentRecordId = Knockout.Observable(); private string _viewFetchXml; + private SortCol _defaultSortCol; #endregion #region Constructors - public ConnectionsViewModel(EntityReference parentRecordId, string[] connectToTypes, int pageSize, string viewFetchXml) + public ConnectionsViewModel(EntityReference parentRecordId, string[] connectToTypes, int pageSize, FetchQuerySettings view) { Connections = new EntityDataViewModel(pageSize, typeof(Connection), true); + if (view != null) + { + _viewFetchXml = QueryParser.GetFetchXmlParentFilter(view, "record1id"); + // Set initial sort + _defaultSortCol=new SortCol(view.OrderByAttribute, !view.OrderByDesending); + } + ParentRecordId.SetValue(parentRecordId); - _viewFetchXml = viewFetchXml; + ObservableConnection connection = new ObservableConnection(connectToTypes); connection.Record2Id.SetValue(parentRecordId); ConnectionEdit = (Observable)ValidatedObservableFactory.ValidatedObservable(connection); - + Connections.OnDataLoaded.Subscribe(Connections_OnDataLoaded); ConnectionEdit.GetValue().OnSaveComplete += ConnectionsViewModel_OnSaveComplete; ObservableConnection.RegisterValidation(Connections.ValidationBinder); AllowAddNew = Knockout.DependentObservable(AllowAddNewComputed); } + #endregion #region Event Handlers @@ -76,7 +85,15 @@ private void connection_PropertyChanged(object sender, Xrm.ComponentModel.Proper switch (e.PropertyName) { case "record2roleid": + // Check if the record1id is loaded - if not load it now so we can work out the opposite role + if (updated.Record1Id == null) + { + Connection connection = (Connection) OrganizationServiceProxy.Retrieve(Connection.LogicalName,updated.ConnectionID.Value,new string[] {"record1id"}); + updated.Record1Id = connection.Record1Id; + } connectionToUpdate.Record2RoleId = updated.Record2RoleId; + connectionToUpdate.Record1RoleId = ObservableConnection.GetOppositeRole(updated.Record2RoleId, updated.Record1Id); + updateRequired = true; break; case "description": @@ -145,13 +162,14 @@ public void Search() {3} "; + Connections.Refresh(); } else { Connections.FetchXml = _viewFetchXml.Replace(QueryParser.ParentRecordPlaceholder, parentRecordId); - + Connections.SortBy(_defaultSortCol); } - Connections.Refresh(); + } [PreserveCase] diff --git a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ObservableConnection.cs b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ObservableConnection.cs index 5886e795..2ae0a4ae 100644 --- a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ObservableConnection.cs +++ b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/ObservableConnection.cs @@ -133,11 +133,12 @@ public static void RoleSearch(string term, Action callback,str if (typeName != null) { // find the entity type code from the type name - int? etc = (int?)Script.Literal("Mscrm.EntityPropUtil.EntityTypeName2CodeMap[{0}]", typeName); + int? etc = GetEntityTypeCodeFromName(typeName); // Filter by the currently select role recordTypeFilter = String.Format(@" - + + ", etc); } string fetchXml = @" @@ -151,7 +152,7 @@ public static void RoleSearch(string term, Action callback,str {1} - + @@ -184,7 +185,10 @@ public void SaveCommand() connection.Record1RoleId = Record1RoleId.GetValue(); connection.Record2RoleId = Record2RoleId.GetValue(); - OrganizationServiceProxy.BeginCreate(connection,delegate(object state) + EntityReference oppositeRole = GetOppositeRole(connection.Record1RoleId, connection.Record2Id); + connection.Record2RoleId = oppositeRole; + + OrganizationServiceProxy.BeginCreate(connection, delegate(object state) { try { @@ -193,8 +197,8 @@ public void SaveCommand() Record1Id.SetValue(null); Record1RoleId.SetValue(null); ((IValidatedObservable)(object)this).Errors.ShowAllMessages(false); - - + + } catch (Exception ex) { @@ -205,8 +209,57 @@ public void SaveCommand() { this.IsBusy.SetValue(false); } - + }); + + } + + private static int? GetEntityTypeCodeFromName(string typeName) + { + int? etc = (int?)Script.Literal("Mscrm.EntityPropUtil.EntityTypeName2CodeMap[{0}]", typeName); + return etc; + } + + public static EntityReference GetOppositeRole(EntityReference role, EntityReference record) + { + EntityReference oppositeRole = null; + int? etc = GetEntityTypeCodeFromName(record.LogicalName); + + // Add the opposite connection role + string getOppositeRole = String.Format(@" + + + + + + + + + + + + + + + + + + + + + + + ", role.Id.ToString(), etc); + + + + EntityCollection results = (EntityCollection)OrganizationServiceProxy.RetrieveMultiple(getOppositeRole); + + if (results.Entities.Count > 0) + { + oppositeRole = results.Entities[0].ToEntityReference(); + } + return oppositeRole; } [PreserveCase] diff --git a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/QueryParser.cs b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/QueryParser.cs index 4246b95e..04c7e5ca 100644 --- a/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/QueryParser.cs +++ b/SparkleXrmSamples/ConnectionsUI/ClientUI/ViewModel/QueryParser.cs @@ -376,7 +376,7 @@ public string GetFetchXmlForQuery(string entityLogicalName, string queryName, st fetchXml = fetchXml.Replace("#Query#", XmlHelper.Encode(searchTerm)); return fetchXml; } - public string GetFetchXmlParentFilter(FetchQuerySettings query, string parentAttribute) + public static string GetFetchXmlParentFilter(FetchQuerySettings query, string parentAttribute) { jQueryObject fetchElement = query.FetchXml.Find("fetch"); @@ -387,6 +387,10 @@ public string GetFetchXmlParentFilter(FetchQuerySettings query, string parentAtt fetchElement.Attribute("distinct", "true"); fetchElement.Attribute("no-lock", "true"); jQueryObject orderByElement = fetchElement.Find("order"); + // Get the default order by field - currently only supports a single sort by column + query.OrderByAttribute = orderByElement.GetAttribute("attribute"); + query.OrderByDesending = orderByElement.GetAttribute("descending") == "true"; + orderByElement.Remove(); // Get the root filter (if there is one) @@ -431,7 +435,8 @@ public class FetchQuerySettings public jQueryObject FetchXml; public EntityQuery RootEntity; public Observable RecordCount; - + public string OrderByAttribute; + public bool OrderByDesending; } diff --git a/SparkleXrmSamples/ConnectionsUI/SparkleXrmCrmPackage/CrmPackage/WebResources/js/ClientUI.js b/SparkleXrmSamples/ConnectionsUI/SparkleXrmCrmPackage/CrmPackage/WebResources/js/ClientUI.js index ba8eefda..5b5c4353 100644 --- a/SparkleXrmSamples/ConnectionsUI/SparkleXrmCrmPackage/CrmPackage/WebResources/js/ClientUI.js +++ b/SparkleXrmSamples/ConnectionsUI/SparkleXrmCrmPackage/CrmPackage/WebResources/js/ClientUI.js @@ -2,26 +2,29 @@ (function($){ Type.registerNamespace('ClientUI');ResourceStrings=function(){} Type.registerNamespace('ClientUI.ViewModels');ClientUI.ViewModels.QueryParser=function(entities){this.entityLookup={};this.$0={};this.$1={};this.entities=entities;} +ClientUI.ViewModels.QueryParser.getFetchXmlParentFilter=function(query,parentAttribute){var $0=query.fetchXml.find('fetch');$0.attr('count','{0}');$0.attr('paging-cookie','{1}');$0.attr('page','{2}');$0.attr('returntotalrecordcount','true');$0.attr('distinct','true');$0.attr('no-lock','true');var $1=$0.find('order');query.orderByAttribute=$1.attr('attribute');query.orderByDesending=$1.attr('descending')==='true';$1.remove();var $2=$0.find('entity>filter');if($2!=null){var $4=$2.attr('type');if($4==='or'){var $5=$(""+$2.html()+'');$2.remove();$2=$5;$0.find('entity').append($5);}}var $3=$("");$2.append($3);return query.fetchXml.html().replaceAll('','{3}');} ClientUI.ViewModels.QueryParser.prototype={entities:null,getQuickFinds:function(){this.$2(true,null);},getView:function(entityLogicalName,viewName){this.$2(false,viewName);},$2:function($p0,$p1){var $0="\r\n \r\n \r\n \r\n \r\n \r\n \r\n ";var $enum1=ss.IEnumerator.getEnumerator(this.entities);while($enum1.moveNext()){var $3=$enum1.current;var $4=Mscrm.EntityPropUtil.EntityTypeName2CodeMap[$3];$0+="";}$0+='';if($p0){$0+="\r\n ";}else if($p1!=null&&$p1.length>0){$0+="";}else{$0+="\r\n ";}$0+='\r\n \r\n ';var $1=Xrm.Sdk.OrganizationServiceProxy.retrieveMultiple($0);var $2={};var $enum2=ss.IEnumerator.getEnumerator($1.get_entities());while($enum2.moveNext()){var $5=$enum2.current;$2[$5.getAttributeValueString('returnedtypecode')]=$5;}var $enum3=ss.IEnumerator.getEnumerator(this.entities);while($enum3.moveNext()){var $6=$enum3.current;var $7=$2[$6];var $8=$7.getAttributeValueString('fetchxml');var $9=$7.getAttributeValueString('layoutxml');var $A;if(Object.keyExists(this.entityLookup,$6)){$A=this.entityLookup[$6];}else{$A={};$A.logicalName=$6;$A.views={};$A.attributes={};this.entityLookup[$6]=$A;}var $B=this.$3($8,$9);$A.views[$7.getAttributeValueString('name')]=$B;if($p0){$A.quickFindQuery=$B;}}},$3:function($p0,$p1){var $0={};var $1=$(''+$p0.replaceAll('{0}','#Query#')+'');var $2=$1.find('fetch');$0.fetchXml=$1;this.$5($0);$0.columns=this.$4($0.rootEntity,$p1);return $0;},$4:function($p0,$p1){var $0=$($p1);var $1=$0.find('cell');var $2=[];$1.each(ss.Delegate.create(this,function($p1_0,$p1_1){ var $1_0=$p1_1.getAttribute('name').toString();var $1_1=$1_0;var $1_2;var $1_3;var $1_4=$1_0.indexOf('.');if($1_4>-1){var $1_8=$1_0.substr(0,$1_4);$1_1=$1_0.substr($1_4+1);$1_2=this.$0[$1_8];}else{$1_2=$p0;}if(Object.keyExists($1_2.attributes,$1_1)){$1_3=$1_2.attributes[$1_1];}else{$1_3={};$1_3.columns=[];$1_3.logicalName=$1_1;$1_2.attributes[$1_3.logicalName]=$1_3;}var $1_5=parseInt($p1_1.getAttribute('width').toString());var $1_6=$p1_1.getAttribute('disableSorting');var $1_7=SparkleXrm.GridEditor.GridDataViewBinder.newColumn($1_3.logicalName,$1_3.logicalName,$1_5);$1_7.sortable=!($1_6!=null&&$1_6.toString()==='1');$1_3.columns.add($1_7);$2.add($1_7);}));return $2;},queryMetadata:function(){var $0=new Xrm.Sdk.Metadata.Query.MetadataQueryBuilder();var $1=[];var $2=[];var $enum1=ss.IEnumerator.getEnumerator(Object.keys(this.entityLookup));while($enum1.moveNext()){var $4=$enum1.current;$1.add($4);var $5=this.entityLookup[$4];var $enum2=ss.IEnumerator.getEnumerator(Object.keys($5.attributes));while($enum2.moveNext()){var $6=$enum2.current;var $7=$5.attributes[$6];var $8=$7.logicalName;var $9=$8.indexOf('.');if($5.aliasName!=null&&$9>-1){$8=$8.substr($9);}$2.add($8);}}$0.addEntities($1,['Attributes','DisplayName','DisplayCollectionName','PrimaryImageAttribute']);$0.addAttributes($2,['DisplayName','AttributeType','IsPrimaryName']);$0.setLanguage(USER_LANGUAGE_CODE);var $3=Xrm.Sdk.OrganizationServiceProxy.execute($0.request);var $enum3=ss.IEnumerator.getEnumerator($3.entityMetadata);while($enum3.moveNext()){var $A=$enum3.current;var $B=this.entityLookup[$A.logicalName];$B.displayName=$A.displayName.userLocalizedLabel.label;$B.displayCollectionName=$A.displayCollectionName.userLocalizedLabel.label;$B.primaryImageAttribute=$A.primaryImageAttribute;$B.entityTypeCode=$A.objectTypeCode;var $enum4=ss.IEnumerator.getEnumerator($A.attributes);while($enum4.moveNext()){var $C=$enum4.current;if(Object.keyExists($B.attributes,$C.logicalName)){var $D=$B.attributes[$C.logicalName];$D.attributeType=$C.attributeType;switch($C.attributeType){case 'Lookup':case 'Picklist':case 'Customer':case 'Owner':case 'Status':case 'State':case 'Boolean':this.$1[$C.logicalName]=$D;break;}$D.isPrimaryName=$C.isPrimaryName;var $enum5=ss.IEnumerator.getEnumerator($D.columns);while($enum5.moveNext()){var $E=$enum5.current;$E.name=$C.displayName.userLocalizedLabel.label;$E.dataType=($C.isPrimaryName)?'PrimaryNameLookup':$C.attributeType;}}}}},$5:function($p0){var $0=$p0.fetchXml;var $1=$0.find('entity');var $2=$1.attr('name');var $3;if(!Object.keyExists(this.entityLookup,$2)){$3={};$3.logicalName=$2;$3.attributes={};this.entityLookup[$3.logicalName]=$3;}else{$3=this.entityLookup[$2];}var $4=$1.find('link-entity');$4.each(ss.Delegate.create(this,function($p1_0,$p1_1){ var $1_0={};$1_0.attributes={};$1_0.aliasName=$p1_1.getAttribute('alias').toString();$1_0.logicalName=$p1_1.getAttribute('name').toString();if(!Object.keyExists(this.entityLookup,$1_0.logicalName)){this.entityLookup[$1_0.logicalName]=$1_0;}else{var $1_1=$1_0.aliasName;$1_0=this.entityLookup[$1_0.logicalName];$1_0.aliasName=$1_1;}if(!Object.keyExists(this.$0,$1_0.aliasName)){this.$0[$1_0.aliasName]=$1_0;}}));$p0.rootEntity=$3;var $5=$0.find("filter[isquickfindfields='1']");$5.first().children().each(function($p1_0,$p1_1){ $2=$p1_1.getAttribute('attribute').toString();var $1_0=$($p1_1);var $1_1=$1_0.parents('link-entity');if(!Object.keyExists($p0.rootEntity.attributes,$2)){var $1_2={};$1_2.logicalName=$2;$1_2.columns=[];$p0.rootEntity.attributes[$2]=$1_2;}});},getFetchXmlForQuery:function(entityLogicalName,queryName,searchTerm){var $0;if(queryName==='QuickFind'){$0=this.entityLookup[entityLogicalName].quickFindQuery;}else{$0=this.entityLookup[entityLogicalName].views[queryName];}var $1=$0.fetchXml.find('fetch');$1.attr('distinct','true');$1.attr('no-lock','true');var $2=$1.find('order');$2.remove();var $3=$1.find("filter[isquickfindfields='1']");$3.first().children().each(ss.Delegate.create(this,function($p1_0,$p1_1){ -var $1_0=$p1_1.getAttribute('attribute').toString();if(Object.keyExists(this.$1,$1_0)){$p1_1.setAttribute('attribute',$1_0+'name');}}));var $4=$0.fetchXml.html();$4=$4.replaceAll('#Query#',Xrm.Sdk.XmlHelper.encode(searchTerm));return $4;},getFetchXmlParentFilter:function(query,parentAttribute){var $0=query.fetchXml.find('fetch');$0.attr('count','{0}');$0.attr('paging-cookie','{1}');$0.attr('page','{2}');$0.attr('returntotalrecordcount','true');$0.attr('distinct','true');$0.attr('no-lock','true');var $1=$0.find('order');$1.remove();var $2=$0.find('entity>filter');if($2!=null){var $4=$2.attr('type');if($4==='or'){var $5=$(""+$2.html()+'');$2.remove();$2=$5;$0.find('entity').append($5);}}var $3=$("");$2.append($3);return query.fetchXml.html().replaceAll('','{3}');}} +var $1_0=$p1_1.getAttribute('attribute').toString();if(Object.keyExists(this.$1,$1_0)){$p1_1.setAttribute('attribute',$1_0+'name');}}));var $4=$0.fetchXml.html();$4=$4.replaceAll('#Query#',Xrm.Sdk.XmlHelper.encode(searchTerm));return $4;}} Type.registerNamespace('ClientUI.View.GridPlugins');ClientUI.View.GridPlugins.RowHoverPlugin=function(containerDivId){this.$2=containerDivId;} ClientUI.View.GridPlugins.RowHoverPlugin.prototype={$0:null,$1:null,$2:null,$3:false,destroy:function(){this.$1.remove();},init:function(grid){this.$0=grid;this.$1=$('#'+this.$2);this.$1.mouseenter(ss.Delegate.create(this,function($p1_0){ this.$3=false;}));$('#grid').find('.slick-viewport').append(this.$1);(this.$0.onMouseEnter).subscribe(ss.Delegate.create(this,this.handleMouseEnter));(this.$0.onMouseLeave).subscribe(ss.Delegate.create(this,this.handleMouseLeave));},handleMouseLeave:function(e,item){this.$3=true;window.setTimeout(ss.Delegate.create(this,function(){ if(this.$3){this.$1.fadeOut();}}),500);},handleMouseEnter:function(e,item){var $0=this.$0.getCellFromEvent(e);if($0!=null){this.$3=false;var $1=this.$0.getDataItem($0.row);if($1!=null){this.$0.getGridPosition();var $2=this.$0.getViewport().rightPx;var $3=this.$0.getViewport().leftPx;var $4=$(this.$0.getCellNode($0.row,$0.cell));var $5=this.$1.width();var $6=$4.parent().width();if($2<$6+$5){$6=$2-$5;}var $7=0;$4.parent().append(this.$1);this.$1.css('left',$6.toString()+'px');this.$1.css('top',$7.toString()+'px');this.$1.css('display','block');this.$1.attr('rowId',$1.id);}}}} Type.registerNamespace('ClientUI.Model');ClientUI.Model.Connection=function(){ClientUI.Model.Connection.initializeBase(this,['connection']);} ClientUI.Model.Connection.prototype={connectionid:null,record1id:null,record2id:null,record1roleid:null,record2roleid:null,description:null,effectivestart:null,effectiveend:null} -Type.registerNamespace('ClientUI.ViewModel');ClientUI.ViewModel.ConnectionsViewModel=function(parentRecordId,connectToTypes,pageSize,viewFetchXml){this.SelectedConnection=ko.observable();this.ErrorMessage=ko.observable();this.parentRecordId=ko.observable();ClientUI.ViewModel.ConnectionsViewModel.initializeBase(this);this.Connections=new SparkleXrm.GridEditor.EntityDataViewModel(pageSize,ClientUI.Model.Connection,true);this.parentRecordId(parentRecordId);this.$1_0=viewFetchXml;var $0=new ClientUI.ViewModel.ObservableConnection(connectToTypes);$0.record2id(parentRecordId);this.ConnectionEdit=ko.validatedObservable($0);this.Connections.onDataLoaded.subscribe(ss.Delegate.create(this,this.$1_1));this.ConnectionEdit().add_onSaveComplete(ss.Delegate.create(this,this.$1_3));ClientUI.ViewModel.ObservableConnection.registerValidation(this.Connections.validationBinder);this.AllowAddNew=ko.dependentObservable(ss.Delegate.create(this,this.allowAddNewComputed));} -ClientUI.ViewModel.ConnectionsViewModel.prototype={Connections:null,ConnectionEdit:null,AllowAddNew:null,$1_0:null,$1_1:function($p0,$p1){var $0=$p1;for(var $1=0;$1<$0.to;$1++){var $2=this.Connections.getItem($1);if($2==null){return;}$2.add_propertyChanged(ss.Delegate.create(this,this.$1_2));}},$1_2:function($p0,$p1){var $0=new ClientUI.Model.Connection();var $1=$p0;$0.connectionid=new Xrm.Sdk.Guid($1.id);var $2=false;switch($p1.propertyName){case 'record2roleid':$0.record2roleid=$1.record2roleid;$2=true;break;case 'description':$0.description=$1.description;$2=true;break;case 'effectivestart':$0.effectivestart=$1.effectivestart;$2=true;break;case 'effectiveend':$0.effectiveend=$1.effectiveend;$2=true;break;}if($2){Xrm.Sdk.OrganizationServiceProxy.beginUpdate($0,ss.Delegate.create(this,function($p1_0){ -try{Xrm.Sdk.OrganizationServiceProxy.endUpdate($p1_0);this.ErrorMessage(null);}catch($1_0){this.ErrorMessage($1_0.message);}}));}},$1_3:function($p0){if($p0==null){this.Connections.reset();this.Connections.refresh();}this.ErrorMessage($p0);},search:function(){var $0=this.parentRecordId().id.toString().replaceAll('{','').replaceAll('}','');if(this.$1_0==null){this.Connections.set_fetchXml("\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {3}\r\n \r\n ");}else{this.Connections.set_fetchXml(this.$1_0.replaceAll('#ParentRecordPlaceholder#',$0));}this.Connections.refresh();},RoleSearchCommand:function(term,callback){ClientUI.ViewModel.ObservableConnection.RoleSearch(term,callback,this.SelectedConnection().record2id.logicalName);},AddNewCommand:function(){this.ConnectionEdit().record2id(this.parentRecordId());this.ErrorMessage(null);this.ConnectionEdit().AddNewVisible(true);},OpenAssociatedSubGridCommand:function(){var $0=window.parent.Xrm.Page.ui.navigation.items.get('navConnections');$0.setFocus();},DeleteSelectedCommand:function(){var $0=SparkleXrm.GridEditor.DataViewBase.rangesToRows(this.Connections.getSelectedRows());if(!$0.length){return;}Xrm.Utility.confirmDialog(String.format(ResourceStrings.ConfirmDeleteSelectedConnection,$0.length),ss.Delegate.create(this,function(){ +Type.registerNamespace('ClientUI.ViewModel');ClientUI.ViewModel.ConnectionsViewModel=function(parentRecordId,connectToTypes,pageSize,view){this.SelectedConnection=ko.observable();this.ErrorMessage=ko.observable();this.parentRecordId=ko.observable();ClientUI.ViewModel.ConnectionsViewModel.initializeBase(this);this.Connections=new SparkleXrm.GridEditor.EntityDataViewModel(pageSize,ClientUI.Model.Connection,true);if(view!=null){this.$1_0=ClientUI.ViewModels.QueryParser.getFetchXmlParentFilter(view,'record1id');this.$1_1=new SparkleXrm.GridEditor.SortCol(view.orderByAttribute,!view.orderByDesending);}this.parentRecordId(parentRecordId);var $0=new ClientUI.ViewModel.ObservableConnection(connectToTypes);$0.record2id(parentRecordId);this.ConnectionEdit=ko.validatedObservable($0);this.Connections.onDataLoaded.subscribe(ss.Delegate.create(this,this.$1_2));this.ConnectionEdit().add_onSaveComplete(ss.Delegate.create(this,this.$1_4));ClientUI.ViewModel.ObservableConnection.registerValidation(this.Connections.validationBinder);this.AllowAddNew=ko.dependentObservable(ss.Delegate.create(this,this.allowAddNewComputed));} +ClientUI.ViewModel.ConnectionsViewModel.prototype={Connections:null,ConnectionEdit:null,AllowAddNew:null,$1_0:null,$1_1:null,$1_2:function($p0,$p1){var $0=$p1;for(var $1=0;$1<$0.to;$1++){var $2=this.Connections.getItem($1);if($2==null){return;}$2.add_propertyChanged(ss.Delegate.create(this,this.$1_3));}},$1_3:function($p0,$p1){var $0=new ClientUI.Model.Connection();var $1=$p0;$0.connectionid=new Xrm.Sdk.Guid($1.id);var $2=false;switch($p1.propertyName){case 'record2roleid':if($1.record1id==null){var $3=Xrm.Sdk.OrganizationServiceProxy.retrieve(ClientUI.Model.Connection.logicalName,$1.connectionid.value,['record1id']);$1.record1id=$3.record1id;}$0.record2roleid=$1.record2roleid;$0.record1roleid=ClientUI.ViewModel.ObservableConnection.getOppositeRole($1.record2roleid,$1.record1id);$2=true;break;case 'description':$0.description=$1.description;$2=true;break;case 'effectivestart':$0.effectivestart=$1.effectivestart;$2=true;break;case 'effectiveend':$0.effectiveend=$1.effectiveend;$2=true;break;}if($2){Xrm.Sdk.OrganizationServiceProxy.beginUpdate($0,ss.Delegate.create(this,function($p1_0){ +try{Xrm.Sdk.OrganizationServiceProxy.endUpdate($p1_0);this.ErrorMessage(null);}catch($1_0){this.ErrorMessage($1_0.message);}}));}},$1_4:function($p0){if($p0==null){this.Connections.reset();this.Connections.refresh();}this.ErrorMessage($p0);},search:function(){var $0=this.parentRecordId().id.toString().replaceAll('{','').replaceAll('}','');if(this.$1_0==null){this.Connections.set_fetchXml("\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {3}\r\n \r\n ");this.Connections.refresh();}else{this.Connections.set_fetchXml(this.$1_0.replaceAll('#ParentRecordPlaceholder#',$0));this.Connections.sortBy(this.$1_1);}},RoleSearchCommand:function(term,callback){ClientUI.ViewModel.ObservableConnection.RoleSearch(term,callback,this.SelectedConnection().record2id.logicalName);},AddNewCommand:function(){this.ConnectionEdit().record2id(this.parentRecordId());this.ErrorMessage(null);this.ConnectionEdit().AddNewVisible(true);},OpenAssociatedSubGridCommand:function(){var $0=window.parent.Xrm.Page.ui.navigation.items.get('navConnections');$0.setFocus();},DeleteSelectedCommand:function(){var $0=SparkleXrm.GridEditor.DataViewBase.rangesToRows(this.Connections.getSelectedRows());if(!$0.length){return;}Xrm.Utility.confirmDialog(String.format(ResourceStrings.ConfirmDeleteSelectedConnection,$0.length),ss.Delegate.create(this,function(){ var $1_0=[];var $enum1=ss.IEnumerator.getEnumerator($0);while($enum1.moveNext()){var $1_1=$enum1.current;$1_0.add(this.Connections.getItem($1_1));}try{var $enum2=ss.IEnumerator.getEnumerator($1_0);while($enum2.moveNext()){var $1_2=$enum2.current;Xrm.Sdk.OrganizationServiceProxy.delete_($1_2.logicalName,new Xrm.Sdk.Guid($1_2.id));}}catch($1_3){this.ErrorMessage($1_3.toString());}this.Connections.raiseOnSelectedRowsChanged(null);this.Connections.reset();this.Connections.refresh();}),null);},DeleteCommand:function(data,e){Xrm.Utility.confirmDialog(ResourceStrings.ConfirmDeleteConnection,ss.Delegate.create(this,function(){ var $1_0=e.target.parentNode.getAttribute('rowId').toString();Xrm.Sdk.OrganizationServiceProxy.beginDelete(ClientUI.Model.Connection.logicalName,new Xrm.Sdk.Guid($1_0),ss.Delegate.create(this,function($p2_0){ try{Xrm.Sdk.OrganizationServiceProxy.endDelete($p2_0);var $enum1=ss.IEnumerator.getEnumerator(this.Connections.get_data());while($enum1.moveNext()){var $2_0=$enum1.current;if($2_0.id===$1_0){this.Connections.removeItem($2_0);break;}}this.Connections.refresh();}catch($2_1){this.ErrorMessage($2_1.message);}}));}),null);},allowAddNewComputed:function(){var $0=this.parentRecordId();return $0!=null&&$0.id!=null&&$0.id.value!=null&&$0.id.value.length>0;}} ClientUI.ViewModel.ObservableConnection=function(types){this.AddNewVisible=ko.observable(false);this.connectiondid=ko.observable();this.record1id=ko.observable();this.record2id=ko.observable();this.record1roleid=ko.observable();this.record2roleid=ko.observable();this.description=ko.observable();ClientUI.ViewModel.ObservableConnection.initializeBase(this);this.$1_2=types;ClientUI.ViewModel.ObservableConnection.registerValidation(new SparkleXrm.ObservableValidationBinder(this));} -ClientUI.ViewModel.ObservableConnection.RoleSearch=function(term,callback,typeName){var $0='';if(typeName!=null){var $2=Mscrm.EntityPropUtil.EntityTypeName2CodeMap[typeName];$0=String.format("\r\n \r\n \r\n ",$2);}var $1="\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {1}\r\n \r\n \r\n \r\n \r\n \r\n ";$1=String.format($1,Xrm.Sdk.XmlHelper.encode(term),$0);Xrm.Sdk.OrganizationServiceProxy.beginRetrieveMultiple($1,function($p1_0){ +ClientUI.ViewModel.ObservableConnection.RoleSearch=function(term,callback,typeName){var $0='';if(typeName!=null){var $2=ClientUI.ViewModel.ObservableConnection.$1_4(typeName);$0=String.format("\r\n \r\n \r\n \r\n ",$2);}var $1="\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {1}\r\n \r\n \r\n \r\n \r\n \r\n ";$1=String.format($1,Xrm.Sdk.XmlHelper.encode(term),$0);Xrm.Sdk.OrganizationServiceProxy.beginRetrieveMultiple($1,function($p1_0){ var $1_0=Xrm.Sdk.OrganizationServiceProxy.endRetrieveMultiple($p1_0,Xrm.Sdk.Entity);callback($1_0);});} +ClientUI.ViewModel.ObservableConnection.$1_4=function($p0){var $0=Mscrm.EntityPropUtil.EntityTypeName2CodeMap[$p0];return $0;} +ClientUI.ViewModel.ObservableConnection.getOppositeRole=function(role,record){var $0=null;var $1=ClientUI.ViewModel.ObservableConnection.$1_4(record.logicalName);var $2=String.format("\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ",role.id.toString(),$1);var $3=Xrm.Sdk.OrganizationServiceProxy.retrieveMultiple($2);if($3.get_entities().get_count()>0){$0=$3.get_entities().get_item(0).toEntityReference();}return $0;} ClientUI.ViewModel.ObservableConnection.validateRecord1Id=function(rules,viewModel,dataContext){return rules.addRule(ResourceStrings.RequiredMessage,function($p1_0){ return ($p1_0!=null)&&($p1_0).id!=null;});} ClientUI.ViewModel.ObservableConnection.validateRecord1RoleId=function(rules,viewModel,dataContext){return rules.addRule(ResourceStrings.RequiredMessage,function($p1_0){ @@ -30,12 +33,12 @@ ClientUI.ViewModel.ObservableConnection.registerValidation=function(binder){bind ClientUI.ViewModel.ObservableConnection.prototype={add_onSaveComplete:function(value){this.$1_0=ss.Delegate.combine(this.$1_0,value);},remove_onSaveComplete:function(value){this.$1_0=ss.Delegate.remove(this.$1_0,value);},$1_0:null,$1_1:null,$1_2:null,RecordSearchCommand:function(term,callback){if(this.$1_1==null){this.$1_1=new ClientUI.ViewModels.QueryParser(this.$1_2);this.$1_1.getQuickFinds();this.$1_1.queryMetadata();}var $0=0;var $1=[];var $2=ss.Delegate.create(this,function($p1_0){ $0++;var $1_0=this.$1_1.entityLookup[$p1_0.get_entityName()].quickFindQuery;var $enum1=ss.IEnumerator.getEnumerator($p1_0.get_entities());while($enum1.moveNext()){var $1_1=$enum1.current;var $1_2=$1_1;var $1_3=($1_0.columns.length<3)?$1_0.columns.length:3;for(var $1_4=0;$1_4<$1_3;$1_4++){var $1_5='col'+$1_4.toString();$1_1[$1_5]=$1_1[$1_0.columns[$1_4].field];$1_2.formattedValues[$1_5+'name']=$1_2.formattedValues[$1_0.columns[$1_4].field+'name'];}}$1.addRange($p1_0.get_entities().items());$1.sort(function($p2_0,$p2_1){ return String.compare($p2_0.getAttributeValueString('name'),$p2_1.getAttributeValueString('name'));});if($0===this.$1_2.length){var $1_6=new Xrm.Sdk.EntityCollection($1);callback($1_6);}});var $enum1=ss.IEnumerator.getEnumerator(this.$1_2);while($enum1.moveNext()){var $3=$enum1.current;this.$1_3(term,$2,$3);}},$1_3:function($p0,$p1,$p2){var $0=this.$1_1.getFetchXmlForQuery($p2,'QuickFind','%'+$p0+'%');Xrm.Sdk.OrganizationServiceProxy.beginRetrieveMultiple($0,function($p1_0){ -var $1_0=Xrm.Sdk.OrganizationServiceProxy.endRetrieveMultiple($p1_0,Xrm.Sdk.Entity);$1_0.set_entityName($p2);$p1($1_0);});},RoleSearchCommand:function(term,callback){var $0=this.record1id();ClientUI.ViewModel.ObservableConnection.RoleSearch(term,callback,($0!=null)?$0.logicalName:null);},SaveCommand:function(){if(!(this).isValid()){(this).errors.showAllMessages(true);return;}this.isBusy(true);this.AddNewVisible(false);var $0=new ClientUI.Model.Connection();$0.record1id=this.record1id();$0.record2id=this.record2id();$0.record1roleid=this.record1roleid();$0.record2roleid=this.record2roleid();Xrm.Sdk.OrganizationServiceProxy.beginCreate($0,ss.Delegate.create(this,function($p1_0){ +var $1_0=Xrm.Sdk.OrganizationServiceProxy.endRetrieveMultiple($p1_0,Xrm.Sdk.Entity);$1_0.set_entityName($p2);$p1($1_0);});},RoleSearchCommand:function(term,callback){var $0=this.record1id();ClientUI.ViewModel.ObservableConnection.RoleSearch(term,callback,($0!=null)?$0.logicalName:null);},SaveCommand:function(){if(!(this).isValid()){(this).errors.showAllMessages(true);return;}this.isBusy(true);this.AddNewVisible(false);var $0=new ClientUI.Model.Connection();$0.record1id=this.record1id();$0.record2id=this.record2id();$0.record1roleid=this.record1roleid();$0.record2roleid=this.record2roleid();var $1=ClientUI.ViewModel.ObservableConnection.getOppositeRole($0.record1roleid,$0.record2id);$0.record2roleid=$1;Xrm.Sdk.OrganizationServiceProxy.beginCreate($0,ss.Delegate.create(this,function($p1_0){ try{this.connectiondid(Xrm.Sdk.OrganizationServiceProxy.endCreate($p1_0));this.$1_0(null);this.record1id(null);this.record1roleid(null);(this).errors.showAllMessages(false);}catch($1_0){this.$1_0($1_0.message);}finally{this.isBusy(false);}}));},CancelCommand:function(){this.AddNewVisible(false);}} Type.registerNamespace('ClientUI.View');ClientUI.View.ConnectionsView=function(){} ClientUI.View.ConnectionsView.Init=function(){Xrm.PageEx.majorVersion=2013;var $0=Xrm.Sdk.OrganizationServiceProxy.getUserSettings().uilanguageid;SparkleXrm.LocalisedContentLoader.fallBackLCID=0;SparkleXrm.LocalisedContentLoader.supportedLCIDs.add(0);SparkleXrm.LocalisedContentLoader.loadContent('con_/js/Res.metadata.js',$0,function(){ ClientUI.View.ConnectionsView.$1();});} -ClientUI.View.ConnectionsView.$1=function(){var $0;var $1;var $2;var $3=10;var $4=null;$0=Xrm.PageEx.getWebResourceData();$1=window.parent.Xrm.Page.data.entity.getId();$2=window.parent.Xrm.Page.data.entity.getEntityName();window.parent.Xrm.Page.data.entity.addOnSave(ClientUI.View.ConnectionsView.$2);var $5=new Xrm.Sdk.EntityReference(new Xrm.Sdk.Guid($1),$2,null);var $6='account,contact,opportunity,systemuser';var $enum1=ss.IEnumerator.getEnumerator(Object.keys($0));while($enum1.moveNext()){var $D=$enum1.current;switch($D.toLowerCase()){case 'entities':$6=$0[$D];break;case 'pageSize':$3=parseInt($0[$D]);break;case 'view':$4=$0[$D];break;}}var $7=new ClientUI.ViewModels.QueryParser(['connection']);$7.getView('connection',$4);$7.queryMetadata();var $8=$7.entityLookup['connection'];var $9=$8.views[Object.keys($8.views)[0]];var $A=$7.getFetchXmlParentFilter($9,'record1id');ClientUI.View.ConnectionsView.vm=new ClientUI.ViewModel.ConnectionsViewModel($5,$6.split(','),$3,$A);var $B=new SparkleXrm.GridEditor.GridDataViewBinder();var $C=$9.columns;var $enum2=ss.IEnumerator.getEnumerator($C);while($enum2.moveNext()){var $E=$enum2.current;switch($E.field){case 'record2roleid':SparkleXrm.GridEditor.XrmLookupEditor.bindColumn($E,ss.Delegate.create(ClientUI.View.ConnectionsView.vm,ClientUI.View.ConnectionsView.vm.RoleSearchCommand),'connectionroleid','name,category','');break;case 'description':SparkleXrm.GridEditor.XrmTextEditor.bindColumn($E);break;case 'effectivestart':case 'effectiveend':SparkleXrm.GridEditor.XrmDateEditor.bindColumn($E,true);break;}}ClientUI.View.ConnectionsView.$0=$B.dataBindXrmGrid(ClientUI.View.ConnectionsView.vm.Connections,$C,'container','pager',true,false);ClientUI.View.ConnectionsView.$0.onActiveCellChanged.subscribe(function($p1_0,$p1_1){ +ClientUI.View.ConnectionsView.$1=function(){var $0;var $1;var $2;var $3=10;var $4=null;$0=Xrm.PageEx.getWebResourceData();$1=window.parent.Xrm.Page.data.entity.getId();$2=window.parent.Xrm.Page.data.entity.getEntityName();window.parent.Xrm.Page.data.entity.addOnSave(ClientUI.View.ConnectionsView.$2);var $5=new Xrm.Sdk.EntityReference(new Xrm.Sdk.Guid($1),$2,null);var $6='account,contact,opportunity,systemuser';var $enum1=ss.IEnumerator.getEnumerator(Object.keys($0));while($enum1.moveNext()){var $D=$enum1.current;switch($D.toLowerCase()){case 'entities':$6=$0[$D];break;case 'pageSize':$3=parseInt($0[$D]);break;case 'view':$4=$0[$D];break;}}var $7=new ClientUI.ViewModels.QueryParser(['connection']);$7.getView('connection',$4);$7.queryMetadata();var $8=$7.entityLookup['connection'];var $9=Object.keys($8.views)[0];var $A=$8.views[$9];ClientUI.View.ConnectionsView.vm=new ClientUI.ViewModel.ConnectionsViewModel($5,$6.split(','),$3,$A);var $B=new SparkleXrm.GridEditor.GridDataViewBinder();var $C=$A.columns;var $enum2=ss.IEnumerator.getEnumerator($C);while($enum2.moveNext()){var $E=$enum2.current;switch($E.field){case 'record2roleid':SparkleXrm.GridEditor.XrmLookupEditor.bindColumn($E,ss.Delegate.create(ClientUI.View.ConnectionsView.vm,ClientUI.View.ConnectionsView.vm.RoleSearchCommand),'connectionroleid','name,category','');break;case 'description':SparkleXrm.GridEditor.XrmTextEditor.bindColumn($E);break;case 'effectivestart':case 'effectiveend':SparkleXrm.GridEditor.XrmDateEditor.bindColumn($E,true);break;}}ClientUI.View.ConnectionsView.$0=$B.dataBindXrmGrid(ClientUI.View.ConnectionsView.vm.Connections,$C,'container','pager',true,false);ClientUI.View.ConnectionsView.$0.onActiveCellChanged.subscribe(function($p1_0,$p1_1){ var $1_0=$p1_1;ClientUI.View.ConnectionsView.vm.SelectedConnection(ClientUI.View.ConnectionsView.$0.getDataItem($1_0.row));});$B.bindClickHandler(ClientUI.View.ConnectionsView.$0);SparkleXrm.ViewBase.registerViewModel(ClientUI.View.ConnectionsView.vm);ClientUI.View.ConnectionsView.$3();$(window).resize(ClientUI.View.ConnectionsView.$4);$(function(){ ClientUI.View.ConnectionsView.$4(null);ClientUI.View.ConnectionsView.vm.search();});} ClientUI.View.ConnectionsView.$2=function(){var $0=new Xrm.Sdk.EntityReference(new Xrm.Sdk.Guid(window.parent.Xrm.Page.data.entity.getId()),window.parent.Xrm.Page.data.entity.getEntityName(),null);if(window.parent.Xrm.Page.ui.getFormType()!==10*.1&&$0.id!=null){ClientUI.View.ConnectionsView.vm.parentRecordId($0);ClientUI.View.ConnectionsView.vm.search();}else{window.setTimeout(ClientUI.View.ConnectionsView.$2,1000);}} diff --git a/SparkleXrmSamples/RefreshedConnectionsUI_1_1_managed.zip b/SparkleXrmSamples/RefreshedConnectionsUI_1_1_managed.zip new file mode 100644 index 0000000000000000000000000000000000000000..8c501a36e3161f56a427feca72714457835bc357 GIT binary patch literal 15741 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 P|NdcrD`lJWzgGVbs6H@` literal 0 HcmV?d00001