web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Dynamics 365 Community / Blogs / CRM Fields / Dynamics crm apps: Enforce ...

Dynamics crm apps: Enforce right app on login

Micchael Profile Picture Micchael 390

     The new dynamics crm apps (Dynamics 365) is a great feature. Once it show up, I promised to my customer to create a few “masks” for crm to wear based on login user roles. So I did.
      All looks good but one unpleasant surprise. After login, the Default app is always loaded. Users then have to find desired app in the list and load it. Few additional clicks, time – not a good user experience.
      I have disable Default App from all users in settings but issue persisted.

Well, coding.

    1. Create an Enable Rule for some of home page ribbons.
I added it to “Refresh All” button. Thanks to Scott Durow’s Workbench.

    2. Code flow:

- Create a JSON object to map apps to roles. I named Apps after roles and now it makes the mapping very convenient.
* This hard code mapping works for me but there definitely a lot of option to generalize the selection *
- Get logged in user roles names and use JSON mapping to get a right app name.
- Validate current app name vs one we found to prevent overlapping.
- Get app id by name and create url with.
- Reload home page

I use OOB Progress Indicator just in case of delays. Not necessary.


Used articles:
Create and manage custom business apps in Customer Engagement using code

Code:

 /* Register as Enable Rule of "Refresh All" command in application ribbon  
************************************************************************/
var EnforceAppsScript = (function (window, document)
{
/*Privet properties and methods
*******************************/
var appPerRole = {
"Name of Role One": "Name of App One",
"Name of Role Two": "Name of App Two",
"Name of Role Three": "Name of App Three"
};
var appName = window.top.requiredAppName;
/*****************************************************************************************
Helper methods
*****************************************************************************************/
function webApiOutputParse(collection, propertiesArray)
{
var prop = [];
collection.forEach(function (row, i)
{
propertiesArray.forEach(function (p)
{
var f = p + "@OData.Community.Display.V1.FormattedValue";
prop.push((row[f] ? row[f] : row[p])); // Get formatted value if one exists for this property.
})
});
return prop;
}
function SdkRequest(action, clientUrl, uri, data, formattedValue, maxPageSize)
{
if (!RegExp(action, "g").test("POST PATCH PUT GET DELETE"))
{ // Expected action verbs.
throw new Error("Sdk.request: action parameter must be one of the following: " +
"POST, PATCH, PUT, GET, or DELETE.");
}
if (!typeof uri === "string")
{
throw new Error("Sdk.request: uri parameter must be a string.");
}
if ((RegExp(action, "g").test("POST PATCH PUT")) && (data === null || data === undefined))
{
throw new Error("Sdk.request: data parameter must not be null for operations that create or modify data.");
}
if (maxPageSize === null || maxPageSize === undefined)
{
maxPageSize = 10; // Default limit is 10 entities per page.
}
// Construct a fully qualified URI if a relative URI is passed in.
if (uri.charAt(0) === "/")
{
uri = clientUrl + "/api/data/v9.0" + uri;
}
return new Promise(function (resolve, reject)
{
var request = new XMLHttpRequest();
request.open(action, encodeURI(uri), true);
request.setRequestHeader("OData-MaxVersion", "4.0");
request.setRequestHeader("OData-Version", "4.0");
request.setRequestHeader("Accept", "application/json");
request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
request.setRequestHeader("Prefer", "odata.maxpagesize=" + maxPageSize);
if (formattedValue)
{
request.setRequestHeader("Prefer",
"odata.include-annotations=OData.Community.Display.V1.FormattedValue");
}
request.onreadystatechange = function ()
{
if (this.readyState === 4)
{
request.onreadystatechange = null;
switch (this.status)
{
case 200: // Success with content returned in response body.
case 204: // Success with no content returned in response body.
resolve(this);
break;
default: // All other statuses are unexpected so are treated like errors.
var error;
try
{
error = JSON.parse(request.response).error;
} catch (e)
{
error = new Error("Unexpected Error");
}
reject(error);
break;
}
}
};
request.send(JSON.stringify(data));
});
};
/*****************************************************************************************
Enforce Apps
*****************************************************************************************/
function enforceApps(globalContext)
{
//check flag to verified if the load already happened
if (window.top.isAppLoaded && window.top.isAppLoaded == '1') return;
var clientUrl = globalContext.getClientUrl();
//get roles names
var userRolesIds = globalContext.userSettings.securityRoles;
var filterTemplate = "roleid eq ";
var filter = "";
for (var i = 0; i < userRolesIds.length; i++)
filter = filter + ((userRolesIds.length > 1 && i < (userRolesIds.length - 1))
? (filterTemplate + userRolesIds[i] + " or ") : (filterTemplate + userRolesIds[i]));
var url = "$select=name";
if (filter != null)
{
url += "&$filter=" + filter;
}
url += "&$orderby=name";
//overlay with spinner 1
Xrm.Utility.showProgressIndicator("Loading app ...");
EnforceAppsScript.SdkRequest("GET", clientUrl, "/roles?" + url)
.then(function (request)
{
console.log("roles done");
var collection = JSON.parse(request.response).value;
console.log("response value " + collection);
var rolesNames = EnforceAppsScript.webApiOutputParse(collection, ["name"]);
console.log("roles Names done");
//find app by name
for (var i = 0; i < rolesNames.length; i++)
{
appName = appPerRole[rolesNames[i]];
if (appName && appName != undefined) break;
}
console.log("app Name: " + appName);
//find app by name
if (appName && appName != undefined && appName != '')
return EnforceAppsScript.SdkRequest("GET", clientUrl, "/appmodules?$select=name,clienttype,appmoduleid&$filter=name eq '" + appName + "'");
//default app persists
else throw new Error('No app found by current user roles');
}).then(function (request)
{
console.log("checking current app");
//appmoduleid
globalContext.getCurrentAppName()
.then(function (currentAppName)
{
//check if app already opened
//no => get id and load it
if (currentAppName != appName)
{
var app = JSON.parse(request.response).value;
//close progress spinner
Xrm.Utility.closeProgressIndicator();
//update flag:
window.top.isAppLoaded = "1";
window.top.requiredAppName = appName;
window.top.location.href = clientUrl + "/main.aspx?appid=" + app[0].appmoduleid;
}
//app is already loaded => nothing else we need
//close progress spinner
Xrm.Utility.closeProgressIndicator();
},
function (error)
{
//close progress spinner
Xrm.Utility.closeProgressIndicator();
console.log(error.message);
});
})
.catch(function (error)
{
//close progress spinner
Xrm.Utility.closeProgressIndicator();
console.log(error.message);
});
}
/*Public properties and methods
********************************/
return {
//loads on Home (main) page
OnLoad: function ()
{
console.log("begin apps");
var globalContext = Xrm.Utility.getGlobalContext();
//manage apps and reload
enforceApps(globalContext);
},
SdkRequest: SdkRequest,
webApiOutputParse: webApiOutputParse,
};
})(window, document);



This was originally posted here.

Comments

*This post is locked for comments