Akumina Framework Performance Considerations
Thought Process around Pre-Implementation and Post-Implementation modes
The Akumina framework ships and executes by default in 'Pre-Implementation' mode. This means all page lifecycle steps of the framework make queries against the Sharepoint list. This is done for easy configuration and quick setup. This does provide some overhead that can be eliminated. Most often times, when ready to go live, these lists are RARELY updated. So we typically like to offload this data to the JS code itself.. Rather than query the list on every uncached page load. For instance, one of the main lists for easy configuration which drives the entire framework is the 'DigispaceConfigurationIDS_AK' list. This list contains configuration data. This data should really NEVER change once launched... so there is no need to keep it in the list. It can be offloaded as configuration variables in code.
We have taken the time to outline every list that gets queried in the page life cycle of the Akumina Framework.
Performance concepts
There are 2 types of page loads:
- A cold load is when the page is loaded without any data or files being in cache, coming in cold with the browser and Akumina cache both cleared. This is the least performant load where all data calls are made and the times for file loads can be properly seen.
- A warm load is another load after the page and site have been accessed. The widget caches will have data in them, so limited data calls will be made. In addition, any CSS and JS files will have been cached in the browser, so file load times are limited.
Debugging the current performance of the framework
In order to determine which direction to go in terms of tweaking the page lifecycle, you first must determine which steps may be acting up, or not as performant as expected. These timings can vary based on tenant, site collection, time of day, o365 performance, internet connection, etc..
Perform the following tasks in the browser to get the following sample output.(We typically like to disable the Graph feature in the DigispaceConfigurationIDS_AK by setting EnableAzureAD to false, this will help with reading the console more clearly)
- Developer Tools
- Console Tab
- CTRL+UP arrow, Refresh All (localStorage.clear())
- Reload the page
- Filter your console for the keyword 'executing'
Akumina Loader Executing LOAD SP.ClientContext: 105.229248046875ms
Akumina Loader Executing on ExecuteOrDelayUntilBodyLoaded: 143.449951171875ms
Akumina Loader Executing Step Auto Clear Local Cache(id-49ztgw2i7jy): 0.875ms
Akumina Loader Executing Step Display Loader(id-49ztgw2i7jy): 1.14892578125ms
Akumina Loader Executing Step Fetching Digispace Configuration(id-49ztgw2i7jy): 472.97705078125ms
Akumina Loader Executing Step Get Extra LanguageNeutral Lists(id-49ztgw2i7jy): 0.0498046875ms
Akumina Loader Executing Step Fetching Async Lists(id-49ztgw2i7jy): 1067.14892578125ms
Akumina Loader Executing Step Detect Multiple SiteVisible Languages(id-49ztgw2i7jy): 0.06201171875ms
Akumina Loader Executing Step Load User Language Settings(id-49ztgw2i7jy): 248.154052734375ms
Akumina Loader Executing Step Getting Async HTML(id-49ztgw2i7jy): 196.277099609375ms
Akumina Loader Executing Step Event Subscription(id-49ztgw2i7jy): 0.072998046875ms
Akumina Loader Executing Step Set Site Theme(id-49ztgw2i7jy): 0.858154296875ms
Akumina Loader Executing Step Validating Interchange Query Key(id-49ztgw2i7jy): 110.068115234375ms
Akumina Loader Executing Step Index Page Data(id-49ztgw2i7jy): 0.0419921875ms
Akumina Loader Executing Step Fetching Page Permissions(id-49ztgw2i7jy): 0.423095703125ms
Akumina Loader Executing Step Getting Footer Markup template(id-49ztgw2i7jy): 238.807861328125ms
Akumina Loader Executing Step Display Site Logo(id-49ztgw2i7jy): 0.42529296875ms
Akumina Loader Executing Step Initialize Search Page(id-49ztgw2i7jy): 0.052734375ms
Akumina Loader Executing Step Initializing Rail(id-49ztgw2i7jy): 163.06494140625ms
Akumina Loader Executing Step Initialize Search Fields(id-49ztgw2i7jy): 2.178955078125ms
Akumina Loader Executing Step Set Department Site Color(id-49ztgw2i7jy): 0.090087890625ms
Akumina Loader Executing Step Prepare Widgets List(id-49ztgw2i7jy): 3.256103515625ms
Akumina Loader Executing Step Initialize Widgets(id-49ztgw2i7jy): 11.791015625ms
Akumina Loader Executing Step Initialize Generic Controls(id-49ztgw2i7jy): 2.423095703125ms
Akumina Loader Executing Step Load Dashboard Widgets(id-49ztgw2i7jy): 313.876953125ms
Akumina Loader Executing Step Display Sharepoint Bar(id-49ztgw2i7jy): 1.787109375ms
Akumina Loader Executing Step Debug Info(id-49ztgw2i7jy): 0.17919921875ms
Akumina Loader Executing Step Init Tray(id-49ztgw2i7jy): 1.3681640625ms
Akumina Loader Executing Step Resume Main Window Loader(id-49ztgw2i7jy): 0.118896484375ms
To get the overall Akumina Framework load time, perform the following steps
- Developer Tools
- Console Tab
- CTRL+UP arrow, Refresh All (localStorage.clear())
- Reload the page
- Filter your console for the keyword 'framework'
Akumina Framework: 2883.177978515625ms
The 'heaviest' calls of the framework are done in the step 'Fetching Async Lists'. This step performs the following queries (in parallel)
- Fetches UserProperties from SP or Graph
- Fetches Widget definitions from 'Widgets_AK'
- Fetches Widget instances from 'WidgetProperties_AK'
- Fetches available languages from 'Languages_AK' (if Multilingual is enabled)
In the below section we cover how to 'offline' these queries, or put them in a 'post-implementation' mode. For example, the 'Languages_AK' list and 'Widgets_AK' list rarely update after go live, as they normally take an implementation cycle when adding or modifying them. Either way, these changes can be done 'post-live', they are done by modifying a few lines of JS code.
Integration points
Page Life Cycle Steps Status
Out of the Box Page Life Cycle Steps are stored as CONSTANTS within the Configuration Context. As of 4.0.0.0, whether a step is active or not can be verified by checking the Page Life Cycle section of the Debug Panel
Additional Info on Page life cycle steps can be found here
Using LoaderConfiguration
The LoaderConfiguration class allows a developer to set the ConfigurationContext before the rest of the steps in the page lifecycle execute. The LoaderConfiguration is automatically detected by the framework. Within this class, steps can be turned on and off, and logging can be enabled. You can name the .Custom anything you wish. The framework will execute the Init() method on anything in the namespace 'LoaderConfiguration' ... ie LoaderConfiguration.ClientName would also be fine
var LoaderConfiguration = LoaderConfiguration || {}
if ((typeof LoaderConfiguration.Custom) === 'undefined') {
//Add shipped steps to loader
LoaderConfiguration.Custom = {
Init: function (config) {
Akumina.AddIn.Logger.WriteInfoLog('LoaderConfiguration.Custom.Init');
}
}
}
Using DigispaceConfigurationIDS_AK list
As of 4.0.0.0, Out of the Box Page Life Cycle Steps can also be controlled via entries in the DigispaceConfigurationIDS_AK list. In this example, we will deactivate the LOADER_STEPS_ENABLE_LOADUSERLANGSETTINGS step by adding an entry to the DigispaceConfigurationIDS_AK list as shown below:
This is convenient in the fact that performance modifications can be made without having to alter code.
Page lifecycle steps that can be switched to "Post Implementation" mode
Validate Interchange query key
This step is not needed once the query key is functioning. As of 4.0.0.0, this step is deprecated. The configuration is still there, set it to false to avoid confusion.
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_VALIDATEINTERCHANGEKEY = false;
Fetching the DigispaceConfiguration from the 'DigispaceConfigurationIDS_AK' list
(this step can be disabled, but you MUST supply a new step that sets the correct values or the framework will fail to load). IMPORTANT NOTE This step must be disabled from the LoaderConfiguration Class, and if the step is disabled you can no longer disable steps within the DigispaceConfigurationIDS_AK.
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_FETCHCONFIGCONTEXT = false;
Fetching the Enabled Languages from the 'Languages_AK' list
(this step can be disabled, but you MUST supply a new step that sets the correct values or the framework will fail to load)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_FETCHLANGUAGES = false;
Fetching the Enabled Widget Definitions from the 'Widgets_AK' list
(this step can be disabled, but you MUST supply a new step that sets the correct values or the framework will fail to load)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_LOADWIDGETSTYPES = false;
Fetching the InterchangeLoginURL - this queries the App Catalog and pulls back the App found in the site collection that contains the name 'Interchange'
(this step can be disabled, but you MUST supply the correct Variable in the Configuration Context so that widgets / features that use this will not break)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_GETINTERCHANGELOGINURL = false;
Load Widgets from Interchange (this step is great to do POST live, as it caches all of your widget properties)
Akumina.Digispace.ConfigurationContext.CONSTANTS.WIDGET_OPTIONS_LOADFROMAPPMANAGER = true;
Fetch dashboard widgets for use on the dashboard
(this step is not needed if the dashboard is not in use)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_LOADDASHBOARDWIDGETS = false;
Initialize the rail
(this step is not needed if the OOB foundation site RAIL is not used)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_INITRAIL = false;
For NON MULTI-LINGUAL sites - Fetching the en-us.js TOKEN file
(this step can be disabled if your site is only going be in English, the en-us.js contents can be brought into the custom.js file, or a file of your choice, instead of the framework dynamically loading this file, you MUST supply the contents of this file or the tokens in the OOB views will not be properly replaced)
- Replacement step code
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_LOADUSERLANGSETTINGS = false;
For MULTI-LINGUAL sites - Fetching the ll-cc.js TOKEN files
The contents of the ll-cc.js language files in the path /Style%20Library/DigitalWorkplace/Content/language/ must be brought into the digitalworkplace.custom.js file, or a file of your choice. This is in place of the framework dynamically loading this file. Since we have multiple languages, we will set different variables, then set a default on the lang object. In the step code, we will switch languages as needed.
This process is detailed in the following article:
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_LOADUSERLANGSETTINGS = false;
For MULTI-LINGUAL sites - Fetching the enabled languages from the 'Languages_AK' list
(this step can be disabled if you are done configuring the languages that will be used on the site, there is no need to query this list, you MUST supply a new step that sets the enabled languages or the framework will fail to function)
- Replacement step code
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_FETCHLANGUAGES = false;
Download the Core/Loading.html template step
(this dynamically downloads the template and sets the LoadingTemplateHtml propery of the ConfigurationContext, there is no need for this step if post launch, as it will be rarely changed)
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_GETLOADINGTEMPLATE = false;
Download the Core/AdditionalMasterMarkup.html template step
(this dynamically downloads the template and throws it and the end of the >body< tag, there is no need for this step if post launch, as it will be rarely changed)
- Take the contents of this file and put in the master page right before the end of the closing >body< tag
- Note - if you have language strings in the file, you will need to replace them, ie {{translate "common.save"}} becomes "Save"
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_GETADDITIONALMARKUP = false;
Download the FooterMarkup.html template step
(this dynamically downloads the template and throws it inbetween the >footer< tag, there is no need for this step if post launch, as it will be rarely changed)
- Take the contents of this file and put in the master page right before the end of the closing >body< tag
Akumina.Digispace.ConfigurationContext.CONSTANTS.LOADER_STEPS_ENABLE_GETFOOTERMARKUP = false;
Replacement Step Code
As always, if you are going to disable a step required by the framework, make sure that you are adding a replacement step using the following integration point - creating a custom step
//You can also create multiples, ie AdditionalSteps.MyAdvancedSteps, AdditionalSteps.SomethingElse, it will always run AdditionalSteps.XXYY.Init()
if ((typeof AdditionalSteps.MoreSteps) === 'undefined') {
AdditionalSteps.MoreSteps = {
Init: function () {
var steps = [];
//console.log('AdditionalSteps.MoreSteps.Init');
steps.push({ stepName: "Auto Clear Local Cache", additionalSteps: [{ name: "My Custom Step", callback: AdditionalSteps.MoreSteps.MyCustomStep }] });
return steps;
}
}
}
Replace the LOADER_STEPS_ENABLE_FETCHCONFIGCONTEXT step
You can get the values for the following keys directly from the 'DigispaceConfigurationIDS_AK' list
if ((typeof AdditionalSteps.MoreSteps) === 'undefined') {
AdditionalSteps.MoreSteps = {
Init: function () {
var steps = [];
steps.push({ stepName: "Auto Clear Local Cache", additionalSteps: [{ name: "Custom SetConfig", callback: AdditionalSteps.MoreSteps.SetConfig }] });
return steps;
},
SetConfig: function () {
Akumina.Digispace.ConfigurationContext.GraphSubscriptionId = "";
Akumina.Digispace.ConfigurationContext.GraphClientId = "";
Akumina.Digispace.ConfigurationContext.SkypeApiKey = "";
Akumina.Digispace.ConfigurationContext.SkypeApiKeyCC = "";
Akumina.Digispace.ConfigurationContext.AADClientSecret = "NOTNEEDEDONFRONTEND";
Akumina.Digispace.ConfigurationContext.AADTenantName = "NOTNEEDEDONFRONTEND";
Akumina.Digispace.ConfigurationContext.InterchangeURL = "";
Akumina.Digispace.ConfigurationContext.InterchangeQueryKey = "";
Akumina.Digispace.ConfigurationContext.SiteLogoObj = '{"default": "/Style%20Library/DigitalWorkPlace/img/site-logo.png","en-us": "/Style Library/DigitalWorkPlace/Images/Client.png"}';
Akumina.Digispace.ConfigurationContext.CachingStrategy = "medium";
Akumina.Digispace.ConfigurationContext.SiteDepartmentMap = '[{"SiteId":"","SiteName":"","Department":""}]';
Akumina.Digispace.ConfigurationContext.GoogleMapKey = "";
Akumina.Digispace.ConfigurationContext.EnableAzureAD = true;
Akumina.Digispace.ConfigurationContext.EnableDebugMode = true;
Akumina.Digispace.ConfigurationContext.Theme = "white";
Akumina.Digispace.ConfigurationContext.SearchPageExclusionList = "pages/search.aspx,pages/discussnew.aspx,pages/pagenotfoundError.aspx,pages/Logout.aspx".split(',');
Akumina.Digispace.ConfigurationContext.TemplateFolderName = "DigitalWorkPlace";
Akumina.Digispace.ConfigurationContext.IsMultiLingualEnabled = false;
// We use the value as an object;
Akumina.Digispace.ConfigurationContext.LanguageNeutralLists = {"siteneutral": ["VideoGallery_AK", "Favorites_AK", "IDS_AK", "AppDisplayOrder_AK", "Comments_AK", "WorkflowApproval_AK", "Forms_AK", "FormSubmissions_AK", "Apps_AK", "MyDashboard_AK", "Widgets_AK", "WidgetViews_AK", "DigispaceConfigurationIDS_AK", "DashboardWidgets_AK", "DashboardWidgetProperties_AK", "Languages_AK", "Banner_AK","DeptNews_AK"]};
Akumina.Digispace.ConfigurationContext.InterchangeLoginURL = __getTemplatePrefix() + "/_layouts/15/appredirect.aspx?instance_id=";
Akumina.Digispace.ConfigurationContext.LoadingTemplateHtml = "<div>Loading...</div>";
Akumina.Digispace.ConfigurationContext.GraphRedirectUrl = Akumina.Digispace.SiteContext.SiteAbsoluteUrl;
Akumina.Digispace.ConfigurationContext.TemplateURLPrefix = Akumina.Digispace.SiteContext.SiteAbsoluteUrl;
Akumina.Digispace.ConfigurationContext.WidgetInstanceSiteUrl = Akumina.Digispace.SiteContext.SiteAbsoluteUrl;
Akumina.Digispace.ConfigurationContext.RemoteListSiteUrl = Akumina.Digispace.SiteContext.SiteAbsoluteUrl;
Akumina.Digispace.ConfigurationContext.DashboardInstanceSiteUrl = Akumina.Digispace.SiteContext.SiteAbsoluteUrl;
var miniConfiguration = {};
miniConfiguration['clientid'] = Akumina.Digispace.ConfigurationContext.GraphClientId;
miniConfiguration['subscriptionid'] = Akumina.Digispace.ConfigurationContext.GraphSubscriptionId;
miniConfiguration['enableazuread'] = Akumina.Digispace.ConfigurationContext.EnableAzureAD.toString();
Akumina.AddIn.Cache.Set(Akumina.Digispace.ConfigurationContext.getCacheKeyLanguageNeutral('configurationcontext'), miniConfiguration, Akumina.AddIn.Constants.HOUR_CACHE_EXPIRATION);
Akumina.Digispace.AppPart.Eventing.Publish('/loader/onexecuted/');
}
}
}
Replace the LOADER_STEPS_ENABLE_LOADWIDGETSTYPES step
You can get the values for the following keys directly from the 'Widgets_AK' list
if ((typeof AdditionalSteps.MoreSteps) === 'undefined') {
AdditionalSteps.MoreSteps = {
Init: function () {
var steps = [];
steps.push({ stepName: "Auto Clear Local Cache", additionalSteps: [{ name: "Custom LoadWidgetTypes", callback: AdditionalSteps.MoreSteps.LoadWidgetTypes}] });
return steps;
},
LoadWidgetTypes: function () {
var widgets = [];
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "QuickLinks", "Akumina.AddIn.QuickLinksWidget", '[{"name":"querypart","friendlyname":"{quicklinks.friendlyname_querypart}","value":"MainMenu_AK","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"title","friendlyname":"{quicklinks.friendlyname_title}","value":"","type":"string"},{"name":"icon","friendlyname":"{quicklinks.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "GenericItem", "Akumina.AddIn.GenericItemWidget", '[{"name":"isroot","friendlyname":"{genericitem.friendlyname_isroot}","value":"true","type":"bool"},{"name":"selectfields","friendlyname":"selectfields","value":"","type":"string"},{"name":"listname","friendlyname":"{genericitem.friendlyname_listname}","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{genericitem.friendlyname_cacheinterval}","value":"-1","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "GenericList", "Akumina.AddIn.GenericListControlWidget", '[{"name":"isroot","friendlyname":"{genericlist.friendlyname_isroot}","value":"true","type":"bool"},{"name":"selectfields","friendlyname":"selectfields","value":"","type":"string"},{"name":"ispaging","friendlyname":"{genericlist.friendlyname_enablepaging}","value":"false","type":"bool"},{"name":"pagesize","friendlyname":"{genericlist.friendlyname_itemsperpage}","value":"10","type":"int"},{"name":"listname","friendlyname":"{genericlist.friendlyname_listname}","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"isasynccallback","friendlyname":"isasynccallback","value":"false","type":"bool"},{"name":"viewxml","friendlyname":"viewxml","value":"","type":"string"},{"name":"callbacktype","friendlyname":"callbacktype","value":"","type":"string"},{"name":"dataloadproperties","friendlyname":"dataloadproperties","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{genericlist.friendlyname_cacheinterval}","value":"-1","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "DashboardContainer", "Akumina.AddIn.DashboardContainerWidget", ' [{"name":"isroot","friendlyname":"{dashboard.friendlyname_isroot}","value":"true","type":"bool"},{"name":"selectfields","friendlyname":"selectfields","value":"ID,ItemList","type":"string"},{"name":"ispaging","friendlyname":"{dashboard.friendlyname_enablepaging}","value":"false","type":"bool"},{"name":"pagesize","friendlyname":"{dashboard.friendlyname_itemsperpage}","value":"10","type":"int"},{"name":"listname","friendlyname":"{dashboard.friendlyname_listname}","value":"MyDashboard_AK","type":"string"},{"name":"instuctionset","friendlyname":"instuctionset","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"ShowDashboardItems","type":"string"},{"name":"isasynccallback","friendlyname":"isasynccallback","value":"false","type":"bool"},{"name":"viewxml","friendlyname":"viewxml","value":"","type":"string"},{"name":"callbacktype","friendlyname":"callbacktype","value":"customdataload","type":"string"},{"name":"dataloadproperties","friendlyname":"dataloadproperties","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{dashboard.friendlyname_cacheinterval}","value":"0","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "MyTeam", "Akumina.AddIn.MyTeamWidget", '[{"name":"isroot","friendlyname":"{myteam.friendlyname_isroot}","value":"true","type":"bool"},{"name":"selectfields","friendlyname":"selectfields","value":"","type":"string"},{"name":"ispaging","friendlyname":"{myteam.friendlyname_enablepaging}","value":"false","type":"bool"},{"name":"pagesize","friendlyname":"{myteam.friendlyname_itemsperpage}","value":"10","type":"int"},{"name":"listname","friendlyname":"{myteam.friendlyname_listname}","value":"","type":"string"},{"name":"instructionset","friendlyname":"instructionset","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"isasynccallback","friendlyname":"isasynccallback","value":"false","type":"bool"},{"name":"viewxml","friendlyname":"viewxml","value":"","type":"string"},{"name":"callbacktype","friendlyname":"callbacktype","value":"","type":"string"},{"name":"dataloadproperties","friendlyname":"dataloadproperties","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{myteam.friendlyname_cacheinterval}","value":"-1","type":"int"},{"name":"fetchphotofromad","friendlyname":"{myteam.friendlyname_fetchphotofromad}","value":"","type":"string"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "RssNews", "Akumina.AddIn.RssNewsWidget", '[{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"rssurl","friendlyname":"{rssnews.friendlyname_rssfeedurl}","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{rssnews.friendlyname_cacheinterval}","value":"10","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "Weather", "Akumina.AddIn.WeatherWidget", '[{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"city","friendlyname":"{weather.friendlyname_city}","value":"","type":"string"},{"name":"state","friendlyname":"{weather.friendlyname_state}","value":"","type":"string"},{"name":"postalcode","friendlyname":"{weather.friendlyname_postalcode}","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{weather.friendlyname_cacheinterval}","value":"10","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "DocumentsSummaryList", "Akumina.AddIn.DocumentsSummaryListWidget", '[{"name":"title","friendlyname":"{dsl.friendlyname_title}","value":"Document Summary List","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"icon","friendlyname":"{dsl.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"targetdocumentlibrary","friendlyname":"{dsl.friendlyname_targetdocumentlibrary}","value":"Documents","type":"string"},{"name":"tablist","friendlyname":"{dsl.friendlyname_tablist}","value":"Newest,My Recent,Popular,Recommended","type":"string"},{"name":"newestnumberoffiles","friendlyname":"{dsl.friendlyname_newestnumberoffiles}","value":"20","type":"int"},{"name":"recentnumberoffiles","friendlyname":"{dsl.friendlyname_recentnumberoffiles}","value":"20","type":"int"},{"name":"popularnumberoffiles","friendlyname":"{dsl.friendlyname_popularnumberoffiles}","value":"20","type":"int"},{"name":"recommendednumberoffiles","friendlyname":"{dsl.friendlyname_recommendednumberoffiles}","value":"20","type":"int"},{"name":"newestinformationtext","friendlyname":"{dsl.friendlyname_newestinformationtext}","value":"","type":"string"},{"name":"recentinformationtext","friendlyname":"{dsl.friendlyname_recentinformationtext}","value":"","type":"string"},{"name":"popularinformationtext","friendlyname":"{dsl.friendlyname_popularinformationtext}","value":"","type":"string"},{"name":"recommendedinformationtext","friendlyname":"{dsl.friendlyname_recommendedinformationtext}","value":"","type":"string"},{"name":"popularnumberofdays","friendlyname":"{dsl.friendlyname_popularnumberofdays}","value":"30","type":"string"},{"name":"currentsite","friendlyname":"{dsl.friendlyname_currentsite}","value":"false","type":"bool"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "MyForms", "Akumina.AddIn.MyFormsWidget", '[{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"title","friendlyname":"{forms.friendlyname_title}","value":"","type":"string"},{"name":"listname","friendlyname":"{forms.friendlyname_listname}","value":"FormSubmissions_AK","type":"string"},{"name":"icon","friendlyname":"{forms.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"version","friendlyname":"version","value":"fullview","type":"string"},{"name":"pagesize","friendlyname":"{forms.friendlyname_itemsperpage}","value":"25","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "FormWidget", "Akumina.AddIn.FormWidget", '[{"name":"instructionset","friendlyname":"instructionset","value":"","type":"string"},{"name":"formtype","value":"","type":"string"},{"name":"chartfield","value":"","type":"string"},{"name":"displaynonmodal","value":"true","type":"bool"},{"name":"itemid","value":"","type":"string"},{"name":"title","friendlyname":"{forms.friendlyname_title}","value":"","type":"string"},{"name":"formdescription","value":"","type":"string"},{"name":"postback","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"referencelist","value":"","type":"string"},{"name":"columnorder","value":"","type":"string"},{"name":"siteid","value":"","type":"string"},{"name":"formdefinition","value":"","type":"string"},{"name":"actionbuttontext","value":"","type":"string"},{"name":"charttitle","value":"","type":"string"},{"name":"charttitlesize","value":"24","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "Traffic", "Akumina.AddIn.TrafficWidget", '[{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"city","friendlyname":"{traffic.friendlyname_city}","value":"","type":"string"},{"name":"state","friendlyname":"{traffic.friendlyname_state}","value":"","type":"string"},{"name":"postalcode","friendlyname":"{traffic.friendlyname_postalcode}","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "CompanyCalendar", "Akumina.AddIn.CompanyCalendarWidget", '[{"name":"groupname","friendlyname":"{calendar.friendlyname_groupname}","value":"CompanyCalendar","type":"string"},{"name":"color","friendlyname":"{calendar.friendlyname_color}","value":"{\\"Blue\\":\\"Blue\\",\\"Green\\":\\"Green\\"}","type":"choice"},{"name":"calendartitle","friendlyname":"Displayed Title","value":"Company Calendar","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"icon","friendlyname":"{calendar.friendlyname_icon}","value":"{\\"None\\":\\"None\\",\\"Bar\\":\\"Bar\\",\\"Calendar\\":\\"Calendar\\",\\"Camera\\":\\"Camera\\",\\"Car\\":\\"Car\\",\\"Cloud\\":\\"Cloud\\",\\"Comment\\":\\"Comment\\",\\"Comments\\":\\"Comments\\",\\"Envelope\\":\\"Envelope\\",\\"Exclamation\\":\\"Exclamation\\",\\"Feed\\":\\"Feed\\",\\"File\\":\\"File\\",\\"Files\\":\\"Files\\",\\"Filter\\":\\"Filter\\",\\"Folder\\":\\"Folder\\",\\"Gear\\":\\"Gear\\",\\"Image\\":\\"Image\\",\\"Info\\":\\"Info\\",\\"Link\\":\\"Link\\",\\"Newspaper\\":\\"Newspaper\\",\\"Pencil\\":\\"Pencil\\",\\"Phone\\":\\"Phone\\",\\"Pie\\":\\"Pie\\",\\"Question\\":\\"Question\\",\\"Search\\":\\"Search\\",\\"Shopping\\":\\"Shopping\\",\\"Sun\\":\\"Sun\\"}","type":"choice"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "PeopleDirectory", "Akumina.AddIn.PeopleDirectoryWidget", '[{"name":"title","friendlyname":"{peopledirectory.friendlyname_title}","value":"","type":"string"},{"name":"searchtype","friendlyname":"{peopledirectory.friendlyname_sortby}","value":"{\"First Name\":\"first\",\"Last Name\":\"last\"}","type":"choice"},{"name":"facets","friendlyname":"{peopledirectory.friendlyname_facets}","value":"[{ \"facetName\":\"department\",\"facetDisplayName\":\"Department\"},{ \"facetName\":\"officelocation\",\"facetDisplayName\":\"Office Location\"}]","type":"json"},{"name":"fetchphotofromad","friendlyname":"{peopledirectory.friendlyname_fetchphotofromad}","value":"true","type":"bool"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"searchlistingdisplay","friendlyname":"{peopledirectory.friendlyname_searchlistingdisplay}","value":"{\"First Last\":\"FL\",\"Last, First\":\"LF\"}","type":"choice"},{"name":"enableazselector","friendlyname":"{peopledirectory.friendlyname_enableazselector}","value":"True","type":"bool"},{"name":"displayview","friendlyname":"{peopledirectory.friendlyname_displayview}","value":"{\"Tile\":\"tile\",\"List\":\"list\"}","type":"choice"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "ImportantDates", "Akumina.AddIn.ImportantDatesWidget", '[{"name":"listname","friendlyname":"{importantdates.friendlyname_listname}","value":"ImportantDates_AK","type":"string"},{"name":"viewalllink","friendlyname":"{importantdates.friendlyname_viewalllink}","value":"Calendar.aspx","type":"string"},{"name":"title","friendlyname":"{importantdates.friendlyname_title}","value":"Important Dates","type":"string"},{"name":"icon","friendlyname":"{importantdates.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"calendar","friendlyname":"{importantdates.friendlyname_datesfromcalendar}","value":"","type":"bool"},{"name":"displaytemplateurl","value":"","type":"string"},{"name":"featuredfield","friendlyname":"{importantdates.friendlyname_featuredfield}","value":"Featured","type":"string"},{"name":"calendardisplay","friendlyname":"{importantdates.friendlyname_calendardisplay}","value":"today","type":"string"},{"name":"cacheinterval","friendlyname":"{importantdates.friendlyname_cacheinterval}","value":"0","type":"int"},{"name":"itemstodisplay","friendlyname":"{importantdates.friendlyname_itemstodisplay}","value":"0","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "ContentBlock", "Akumina.AddIn.ContentBlockWidget", '[{"name":"querypart","friendlyname":"{contentblock.friendlyname_listname}","value":"","type":"string"},{"name":"sitewidealertmessage","friendlyname":"Site Wide Alert Message","value":"","type":"string"},{"name":"disablealert","friendlyname":"{contentblock.friendlyname_disablealert}","value":"","type":"string"},{"name":"preview","friendlyname":"{contentblock.friendlyname_preview}","value":"false","type":"bool"},{"name":"dynamicpreview","value":"","type":"string"},{"name":"title","friendlyname":"{contentblock.friendlyname_title}","value":"","type":"string"},{"name":"icon","friendlyname":"{contentblock.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"instructionset","friendlyname":"instructionset","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{contentblock.friendlyname_cacheinterval}","value":"0","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "AnnouncementItems", "Akumina.AddIn.AnnouncementItemsWidget", '[{"name":"listname","friendlyname":"{announcementitems.friendlyname_listname}","value":"","type":"string"},{"name":"title","friendlyname":"{announcementitems.friendlyname_title}","value":"Announcement Items","type":"string"},{"name":"icon","friendlyname":"{announcementitems.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"displaytemplate","friendlyname":"displaytemplate","value":"PageTemplate","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"itemstodisplay","friendlyname":"{announcementitems.friendlyname_itemstodisplay}","value":"10","type":"int"},{"name":"viewalllink","friendlyname":"{announcementitems.friendlyname_viewalllink}","value":"NewsList.aspx","type":"string"},{"name":"ispaging","friendlyname":"{announcementitems.friendlyname_enablepaging}","value":"false","type":"bool"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "EventDetail", "Akumina.AddIn.EventDetailWidget", '[{"name":"listname","friendlyname":"{eventdetails.friendlyname_listname}","value":"Calendar_AK","type":"string"},{"name":"calendarlink","friendlyname":"{eventdetails.friendlyname_calendarlink}","value":"Calendar","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "Calendar", "Akumina.AddIn.CalendarWidget", '[{"name":"listname","friendlyname":"{calendar.friendlyname_listname}","value":"Calendar_AK","type":"string"},{"name":"title","friendlyname":"{calendar.friendlyname_title}","value":"Calendar","type":"string"},{"name":"preview","friendlyname":"{calendar.friendlyname_enablepreview}","value":"false","type":"bool"},{"name":"icon","friendlyname":"{calendar.friendlyname_icon}","value":"{\"None\":\"None\",\"Bar\":\"Bar\",\"Calendar\":\"Calendar\",\"Camera\":\"Camera\",\"Car\":\"Car\",\"Cloud\":\"Cloud\",\"Comment\":\"Comment\",\"Comments\":\"Comments\",\"Envelope\":\"Envelope\",\"Exclamation\":\"Exclamation\",\"Feed\":\"Feed\",\"File\":\"File\",\"Files\":\"Files\",\"Filter\":\"Filter\",\"Folder\":\"Folder\",\"Gear\":\"Gear\",\"Image\":\"Image\",\"Info\":\"Info\",\"Link\":\"Link\",\"Newspaper\":\"Newspaper\",\"Pencil\":\"Pencil\",\"Phone\":\"Phone\",\"Pie\":\"Pie\",\"Question\":\"Question\",\"Search\":\"Search\",\"Shopping\":\"Shopping\",\"Sun\":\"Sun\"}","type":"choice"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"category","friendlyname":"{calendar.friendlyname_category}","value":"","type":"string"},{"name":"isroot","friendlyname":"{calendar.friendlyname_isroot}","value":"false","type":"bool"},{"name":"showcategories","friendlyname":"{calendar.friendlyname_showcategories}","value":"true","type":"bool"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "PageLayoutWidget", "Akumina.AddIn.PageLayoutWidget", '[{"name":"container","value":".ak-footer .row","type":"string"},{"name":"instructionset","friendlyname":"instructionset","value":"","type":"string"},{"name":"containercontrols","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{pagelayout.friendlyname_cacheinterval}","value":"-1","type":"int"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "DocumentFilter", "Akumina.AddIn.DocumentFilterWidget", '[{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"listname","friendlyname":"{documentfilter.friendlyname_listname}","value":"","type":"string"},{"name":"taxonomycolumnname","friendlyname":"{documentfilter.friendlyname_taxonomycolumnname}","value":"","type":"string"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "DocumentList", "Akumina.AddIn.DocumentListWidget", '[{"name":"isroot","friendlyname":"{documentlist.friendlyname_isroot}","value":"true","type":"bool"},{"name":"selectfields","friendlyname":"selectfields","value":"","type":"string"},{"name":"ispaging","friendlyname":"{documentlist.friendlyname_enablepaging}","value":"false","type":"bool"},{"name":"pagesize","friendlyname":"{documentlist.friendlyname_itemsperpage}","value":"10","type":"string"},{"name":"listname","friendlyname":"{documentlist.friendlyname_listname}","value":"","type":"string"},{"name":"instructionset","friendlyname":"instructionset","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"isasynccallback","friendlyname":"isasynccallback","value":"false","type":"bool"},{"name":"viewxml","friendlyname":"viewxml","value":"","type":"string"},{"name":"callbacktype","friendlyname":"callbacktype","value":"","type":"string"},{"name":"dataloadproperties","friendlyname":"dataloadproperties","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{documentlist.friendlyname_cacheinterval}","value":"0","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "Banner", "Akumina.AddIn.BannerWidget", '[{"name":"resultsourceid","friendlyname":"{banner.friendlyname_listname}","value":"Banner_AK","type":"string"},{"name":"infiniteloop","friendlyname":"{banner.friendlyname_infiniteloop}","value":"true","type":"bool"},{"name":"autoplay","friendlyname":"{banner.friendlyname_autoplay}","value":"true","type":"bool"},{"name":"shownavigator","friendlyname":"{banner.friendlyname_shownavigator}","value":"true","type":"bool"},{"name":"transitioneffect","friendlyname":"{banner.friendlyname_transitioneffect}","value":"{\"Horizontal\":\"Horizontal\",\"Fade\":\"Fade\"}","type":"choice"},{"name":"slideduration","friendlyname":"{banner.friendlyname_slideduration}","value":"3000","type":"int"},{"name":"textcolor","friendlyname":"{banner.friendlyname_textcolor}","value":"{\"White\":\"white\",\"Black\":\"black\",\"Grey\":\"grey\"}","type":"choice"},{"name":"textlocation","friendlyname":"{banner.friendlyname_textlocation}","value":"{\"Top Left\":\"top_left\",\"Top Center\":\"top_center\",\"Top Right\":\"top_right\",\"Middle Left\":\"middle_left\",\"Middle Center\":\"middle_center\",\"Middle Right\":\"middle_right\",\"Bottom Left\":\"bottom_left\",\"Bottom Center\":\"bottom_center\",\"Bottom Right\":\"bottom_right\"}","type":"choice"},{"name":"textalignment","friendlyname":"{banner.friendlyname_textalignment}","value":"{\"Left\":\"left\",\"Center\":\"center\",\"Right\":\"right\"}","type":"choice"},{"name":"h1maxcharacters","friendlyname":"{banner.friendlyname_h1maxcharacters}","value":"80","type":"int"},{"name":"h2maxcharacters","friendlyname":"{banner.friendlyname_h2maxcharacters}","value":"80","type":"int"},{"name":"buttonmaxcharacters","friendlyname":"{banner.friendlyname_buttonmaxcharacters}","value":"80","type":"int"},{"name":"webparttheme","friendlyname":"webparttheme","value":"","type":"string"},{"name":"linkbuttontheme","friendlyname":"linkbuttontheme","value":"","type":"string"},{"name":"linkbuttontexttheme","friendlyname":"linkbuttontexttheme","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"preview","friendlyname":"{banner.friendlyname_enablepreview}","value":"false","type":"bool"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "LanguagePicker", "Akumina.AddIn.LanguagePickerWidget", '[{"name":"isroot","friendlyname":"{languagepicker.friendlyname_isroot}","value":"true","type":"bool"},{"name":"listname","friendlyname":"{languagepicker.friendlyname_listname}","value":"Languages_AK","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"{languagepicker.friendlyname_cacheinterval}","value":"0","type":"int"}]'));
widgets.push(AdditionalSteps.MoreSteps.GetWidgetType("", "GenericSearchList", "Akumina.AddIn.GenericSearchListWidget", '[{"name":"selectfields","friendlyname":"selectfields","value":"","type":"string"},{"name":"ispaging","friendlyname":"Enable Paging","value":"","type":"string"},{"name":"pagesize","friendlyname":"Items/Page","value":"10","type":"int"},{"name":"query","friendlyname":"Query","value":"","type":"string"},{"name":"displaytemplateurl","friendlyname":"displaytemplateurl","value":"","type":"string"},{"name":"callbackmethod","friendlyname":"callbackmethod","value":"","type":"string"},{"name":"cacheinterval","friendlyname":"Cache Interval","value":"","type":"string"}]'));
Akumina.AddIn.Cache.Set(AdditionalSteps.MoreSteps.GetWidgetTypesCacheKey(), widgets, AdditionalSteps.MoreSteps.GetCacheInterval());
Akumina.Digispace.AppPart.Eventing.Publish('/loader/onexecuted/');
},
GetWidgetType: function (title, widgetName, widgetClass, widgetProperties) {
var widgetType = {
title: title,
widgetName: widgetName,
widgetclass: widgetClass,
widgetProperties: widgetProperties
};
return widgetType;
},
GetCacheInterval: function () {
return Akumina.AddIn.Constants.HOUR_CACHE_EXPIRATION;
},
GetWidgetTypesCacheKey: function () {
return Akumina.Digispace.ConfigurationContext.getCacheKeyLanguageNeutral('widgets_ak');
},
}
}
Replace the LOADER_STEPS_ENABLE_FETCHLANGUAGES step
You can get the values for the following keys directly from the 'Languages_AK' list
if ((typeof AdditionalSteps.MoreSteps) === 'undefined') {
AdditionalSteps.MoreSteps = {
Init: function () {
var steps = [];
steps.push({ stepName: "Auto Clear Local Cache", additionalSteps: [{ name: "Custom LoadLanguages", callback: AdditionalSteps.MoreSteps.LoadWidgetTypes}] });
return steps;
},
LoadLanguages: function () {
var languages = [];
languages.push({ title: "English (U.S.)", languageId: 1033, languageCode: "en-US", direction: "ltr", isDefault: true, isActive: true, isSiteVisible: true, fallbackLanguageId: null });
Akumina.AddIn.Cache.Set(AdditionalSteps.MoreSteps.GetLanguagesCacheKey(), languages, AdditionalSteps.MoreSteps.GetCacheInterval());
var userlang = { languageCode: "en-US", languageId: 1033, fallbackLanguageId: 1033 };
Akumina.Digispace.UserContext.SetLanguage(userlang);
Akumina.Digispace.AppPart.Eventing.Publish('/loader/onexecuted/');
},
GetCacheInterval: function () {
return Akumina.AddIn.Constants.HOUR_CACHE_EXPIRATION;
},
GetLanguagesCacheKey: function () {
return Akumina.Digispace.ConfigurationContext.getCacheKeyLanguageNeutral('languages_ak');
}
}
}
Replace the LOADER_STEPS_ENABLE_GETINTERCHANGELOGINURL step
You can get the instanceid of your interchange app by clicking on the App in the site contents of the site collection, you can take the instanceid off of the querystring (it will always be a guid)
Akumina.Digispace.ConfigurationContext.InterchangeLoginURL = __getTemplatePrefix() + "/_layouts/15/appredirect.aspx?instance_id={}";
Script file ordering in the Master Page
We have found that moving the Akumina JS script references outside of the >head< tag and to the bottom of the >body< tag seem to help the "perceived" page load times. This is a common practice used on Public facing websites. The browser actually downloads browser resources sequentially, in order, so any SCRIPT tag needs to be executed (or downloaded) before completing the rest of the rendering process.
Open up the digitalworkspace.html file in the Master Page Gallery of sharepoint.
Remove the following lines:
<!-- DIGITALWORKPLACE JS FILES -->
<!--MS:<SharePoint:ScriptLink ID="ScriptLink1099" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.vendor.min.js" runat="server">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink ID="ScriptLink103" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.vendor-nomin.js" runat="server">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink ID="ScriptLink1098" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.min.js" runat="server">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink ID="ScriptLink10942" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.shippedsite.min.js" runat="server">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink ID="ScriptLink10943" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.custom.js" runat="server">-->
<!--ME:</SharePoint:ScriptLink>-->
Add the following lines just before the closing >body< tag:
<script src="https://TENANT.sharepoint.com/style%20library/digitalworkplace/js/digitalworkplace.vendor.min.js"></script>
<script src="https://TENANT.sharepoint.com/style%20library/digitalworkplace/js/digitalworkplace.vendor-nomin.js"></script>
<script src="https://TENANT.sharepoint.com/style%20library/digitalworkplace/js/digitalworkplace.min.js"></script>
<script src="https://TENANT.sharepoint.com/style%20library/digitalworkplace/js/digitalworkplace.shippedsite.min.js"></script>
<script src="https://TENANT.sharepoint.com/style%20library/digitalworkplace/js/digitalworkplace.custom.js"></script>
CDN
In Modern sites, we recommend enabling the CDN as this is where the client assets (js, css, etc) come from for the Single Page Application
The Akumina team has experienced various latency throughout the day trying to access resources coming out of the Style Library. This includes requests to images / javascript and css files. We have found that off loading these requests to a CDN has increased performance across the board. Not to mention, there is a browser restriction on how many requests can go out to the same TLD (Top Level Domain) at the same time. This restriction can range anywhere from 6-20 depending on the browser and can be attributed too "Stalled" requests. Making the requests come from a CDN URL allows this request limit to be avoided, ie, 10 requests go out to tenanturl.sharepoint.com and another 10 requests can go out to publiccdn.sharepointonline.com/tenanturl
**Lucky for us, Sharepoint provides us an OOB / Free of charge (as of 8/1/17) automatic syncing and routing to a public CDN. **
You can find all the information on public and private CDN's on the MS website
Enabling the Office 365 CDN
We have done this work often, so here is a quick step by step on how to enable the public CDN on your tenant
Note: This enable the CDN across all your site collections and apply the the "Style Library" and "MasterPages" library automatically
* Set-SPOTenantCdnEnabled -CdnType Public -Enable $true
* Get-SPOTenantCdnOrigins -CdnType Public
You should see the following:
Get-SPOTenantCdnOrigins -CdnType Public
*/MASTERPAGE
*/STYLE LIBRARY
If you have Akumina driven Modern sites, this should also be done for Akumina Library
. Execute the following command for those either central or standalone sites that have the Akumina Library
library in them:
Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl "sites/{SiteCollectionName}/Akumina Library"
If you have artifacts in other libraries, we would run the same command for any other library, example:
Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl "sites/{SiteCollectionName}/MyCustomLibrary"
Do this for any libraries in sites where you want the contents to be in the CDN.
Configuring file types for the Office 365 CDN
Note that in order to make use of the CDN for font or html files, additional configuration is needed for those extensions. We require the following extensions:
- CSS
- EOT
- GIF
- ICO
- JPEG
- JPG
- JS
- MAP
- PNG
- SVG
- TTF
- WOFF
- WOFF2
- HTML
- TXT
Note your CDN may be configured with existing file extensions; if so, then add our required extensions to the already existing list.
To enable the extensions, run the following:
Set-SPOTenantCdnPolicy -CdnType Public -PolicyType IncludeFileExtensions -PolicyValue "CSS,EOT,GIF,ICO,JPEG,JPG,JS,MAP,PNG,SVG,TTF,WOFF,WOFF2,HTML,TXT"
Classic sites - using the Office 365 CDN
A classic site master page will automatically use the CDN enabled files, if using the SharePoint syntax:
<!--MS:<SharePoint:ScriptLink ID="ScriptLink10942" Name="~sitecollection/Style Library/DigitalWorkPlace/js/digitalworkplace.min.js" runat="server">-->
However, if you are directly referencing files, then the file path must be prefixed with the CDN, example:
<link
ms-design-css-conversion="no"
rel="stylesheet"
href="https://publiccdn.sharepointonline.com/{tenant}.sharepoint.com/sites/{sitecollection}/Style%20Library/DigitalWorkPlace/CSS/digitalworkplace.css"
/>
This can be done via the site deployer, look for cdnprefix at https://akumina.github.io/docs/Site-Deployer-Version-5-0
Also, it is necessary to change the configuration to use the CDN as the location for template files. To do so,
Akumina.Digispace.ConfigurationContext.TemplateURLPrefix = _spPageContextInfo.siteAbsoluteUrl.replace("https://", "https://publiccdn.sharepointonline.com/");
This is placed in the digitalworkplace.env.js file, in the LoaderConfiguration.Custom.Init method, as shown below:
if ((typeof LoaderConfiguration.Custom) === 'undefined') {
//Add shipped steps to loader
LoaderConfiguration.Custom = {
Init: function (config) {
...
...
Akumina.Digispace.ConfigurationContext.TemplateURLPrefix = _spPageContextInfo.siteAbsoluteUrl.replace("https://", "https://publiccdn.sharepointonline.com/");
...
...
}
};
}
Modern sites - using the CDN
This needs to be done for each site where there is an SPA present.
Using the Modern SPA (see https://akumina.github.io/docs/Modern-SPA) then the configuration options must be changed:
- Enable Development Mode? (this will request your widget js directly rather than from bundle)
Set this value to checked (true)
- Path to prefix infront of the .html view requests for widgets. Set this when using a CDN (https://publiccdn.sharepointonline.com/{tenant}.sharepoint.com/sites/{sitecollection})
Set this value to https://publiccdn.sharepointonline.com/{tenant}.sharepoint.com/sites/{sitecollection} (with your values replaced) to enable CDN usage.
Troubleshooting SharePoint Page Performance
Most modern browsers have a form of developer tools where you can see the network calls that are made. Here we can see the performance of the SharePoint pages. Perform the following tasks in the browser to get the output:
- Developer Tools
- Network Tab
- CTRL+UP arrow, Refresh All (localStorage.clear())
- Reload the page
- Select the first aspx page (or the homepage if applicable)
- Look in the Headers tab, the Response headers group.
You will find the sprequestduration and other headers as shown:
The ones we are interested are defined below:
- sprequestduration – this is the time in milliseconds that SharePoint took to assemble the page. If this number is higher than that indicates a complex page - are there too many (non Akumina) web parts or other items on the page?
- x-sharepointhealthscore – This value is on a scale of 0 – 10 and indicates how much load the server where the response came from is experiencing.
SharePoint CSS theming
For CSS files, SharePoint will download the contents of the CSS file and append it as a style tag under the link tag. This has performance implications and can break styles if the CSS file is very large. For the CSS link, add this attribute to the link to prevent this:
ms-design-css-conversion="no"
For example, in a classic master page, the SharePoint:CssRegistration tag shown below:
<!--MS:<SharePoint:CssRegistration ID="CssRegistration1" Name="<% $SPUrl:{{SiteUrl}}/Style Library/DigitalWorkPlace/css/digitalworkplace.css %>" runat="server">-->
<!--ME:</SharePoint:CssRegistration>-->
Becomes a standard link tag:
<link ms-design-css-conversion="no" rel="stylesheet" type="text/css" href="{{SiteUrl}}/Style Library/DigitalWorkPlace/css/digitalworkplace.css"/>
Performance Data Template
The following represents a template for collecting information related to performance in your Akumina site. This will help identify areas of improvement.
Global Data template
Property | Value |
---|---|
SharePoint version: | Office365 / On Premise |
SharePoint experience: | Classic / Modern |
App Manager environment: | VM / App Service / Other |
Azure App/VM location: | Specify Region |
Tenant location: | Specify Region |
CDN: | Yes / No |
JS file location in master | Top / Bottom / NA |
Framework version: | |
App Manager Version: | |
SPA Version | |
Azure AD enabled? | Yes / No |
CSS references | SharePoint / link tag |
The following table lists common issues and corrective actions:
Item | Action |
---|---|
Azure App/VM location and tenant location different | Where possible, this should be the same to reduce latency |
No CDN usage | Recommend the use of a CDN - See "CDN" section in this article |
JS file location at top | Alter for optimal loading - See section "Script file ordering in the Master Page" section in this article |
CSS file contents loaded in style tags | Alter for optimal loading - See section "SharePoint CSS theming" section in this article |
Page Data template
Repeat this as needed
Property | Value | |
---|---|---|
Page URL: | ||
Date time accessed: | ||
Client location: | East US | |
Latency to Azure data center: | ||
Cold load | Warm load | |
Requests | ||
Resources transmitted | ||
Resources total | ||
Time in network panel | ||
SPRequestDuration (in network panel) | ||
X-SharePointHealthScore | ||
Process Query calls | ||
'Items' calls | ||
SP Call Count | ||
Connector Call Count | ||
Framework load time | ||
Framework file download time | ||
Time Spent Waiting on Dependecies | ||
Modern - headStart | ||
Modern - bodyEnd | ||
Modern - Total Time | ||
Total Browser | ||
Time spent connecting | ||
Total Render | ||
Yellow or red steps |
See the following sections for more information on common issues and corrective actions.
Measuring a baseline
When measuring the performance of a site, it is important to gather a baseline of the site. Using the above template, capture the page metrics using a blank Akumina page wihout and interior content (essentially, the header and footer only). Any changes or optimizations to the resources and widgets will impact all pages in the site.
The following table lists common issues and corrective actions:
Item | Action |
---|---|
Inefficient baseline | See "Measuring" sections - it is recommended to optimize the baseline as much as possible |
Measuring resources
The browser's Network panel in the developer tools is great resource for measuring performance. From here, we can see things such as:
- Items that are large in file size
- Items that are slow
- Total requests for the page
- Total size for the page
- API calls to SharePoint
Below is an example of the network panel with callouts for important values:
Footnote | Description |
---|---|
1 | The total number of requests made for the page |
2 | The size of resources transferred |
3 | The total size of resources on the page |
4 | The time to finish loading the page |
5 | Allows a filter of the items in the network panel grid |
In addition to recorrding the values for 1 - 4, we want to filter for ProcessQuery and Items and record the number for each. These represent API calls to SharePoint.
The following table lists common issues and corrective actions:
Item | Action |
---|---|
Large Resources transmitted / total | Reduce the overal page size by eliminating widgets. Also, you can reduce the amount loaded at one time by lazy loading widgets |
Large number of JS files | Consolidate by combining if possible, or can some be lazy loaded |
Large number of CSS files | Consolidate by combining if possible |
Large image sizes (> 250kb) | Optimize or otherwise reduce the size of the images |
301 or 302 status | Check the path to the resource and correct if possible. Is it the correct view URL for the item (it could be the internal SharePoint URL such as /:u:/r/sites/etc) |
401 status | No access to the item - Is the item checked in or published? |
404 status | Missing item - is the item present, and if so, is it published, as users with lower permissions may not be able to view it in an unpublished state |
High number of ProcessQuery calls | |
High number of Items calls |
Measuring API calls
In the Akumina Debugger panel, the number of times the Akumina API is called is recorded in the Cache tab. You can see two values SP Call Count and Connector Call Count. These are influenced by the number of widgets and other calls to SharePoint, and will change based on a warm or cold load. It is recommended to get these numbers as low as possible.
The following table lists common issues and corrective actions:
Item | Action |
---|---|
Large SP Call Count and Connector Call Count value | Remove some widgets, or make them lazy load as needed. Example - Load a typeahead search only when the user clicks into the search box |
No or small difference in SP Call Count and Connector Call Count values between cold and warm load | Check the widgets on the page have cache values |
Performance Tab
In the Akumina debugger panel, the performance tab can be used to evaluate different data points in regards to performance. The 'General' tab shows basic information around total Akumina framework load time (how long it takes to get through all the page lifecycle steps, they are executed asyncronsly but we track the completion time), when in Modern runtime, the Modern section indicates how long it took before Akumina code was able to execute as we have to wait for Modern to execute our 3rd party code. The 'Page lifecycle' tab indicates the total execution time for each step (core or CUSTOM) which can influence the load time. For instance Akumina allows you to inject your own step that can fetch data from a sharepoint list or some other API call that can HOLD up the page load time (sometimes by design). If you see any yellow or red numbers evaluate if its custom or core. 'Mark and Measure' - see more info here on its usage: https://akumina.github.io/docs/Measuring-Performance-With-Mark-and-Measure. Finally the 'Service Hub' tab will report on the Response Header coming from the App Service (x-akumina-elapsed-ms) - this tells you the SERVER execution time to help narrow down Edge Node problems with the App Manager servers.
Here is an emulated (by using Throttling in the network tab) POOR CLIENT collection example:
Measuring Azure App Service Latency
When looking at performance, it is important to measure the network latency from a given user location to where the Akumina App Manager is located. We can then correlate this value with what we see in the site. There are online services that can assist with this – a few are listed below.
Samples
A sample report from http://www.azurespeed.com/Azure/Latency, measuring the latency from the user location to the East US 2 data center:
A sample report from https://azurespeedtest.azurewebsites.net/
The following table lists common issues and corrective actions:
Item | Action |
---|---|
Slow latency | Check the speed of the internet connection the client is using. Also, is the physical distance between the client and the Azure region great, ie Accessing a site in Europe from North America. Depending on the site traffic, additional regions may be an option - see "Deployment using Multi Region" at https://community.akumina.com/knowledge-base/appmanager-deployment-options/ |