How to create a “special” custom Home Page for SharePoint Online in Microsoft Office 365

Introduction

In this post, I would like to illustrate a real scenario that I think is really interesting and useful. During the last months we had to satisfy a customer’s requirement about designing the home page of a corporate Intranet network based on Microsoft Office 365 and SharePoint Online, together with the deployment of an hybrid scenario that leverages a bunch of VMs (about 25) in Windows Azure IaaS for hosting an “on-premises” (even if on Microsoft Azure) SharePoint 2013 farm and an ADFS environment, as well. Thus, the customer has some workloads on-premises, based on the VMs in Microsoft Azure, and some other workloads in Office 365. All the users are managed through Federated Identities, using ADFS 3.0 and Windows Server 2012 R2.

We decided to provision the SharePoint 2013 farm on Windows Azure IaaS because we needed to provide some services that aren’t available (yet) in Office 365. They were mainly Business Intelligence services and workloads, as well as some kind of direct integrations with a completely on-premises deployment of Microsoft Dynamics Ax, which is installed in the headquarters of the customer. Thus, we also have a site-to-site VPN between the headquarters and Microsoft Azure.

The customer is quite big – at least from my country perspective – because there are about 1.000 people all over the country. We provisioned multiple site collections to hold contents for the various departments and units. For instance we have a site collection for the Insurance unit, another for the IT department, another for the Accounting unit, and so on. Moreover, there are some other cross-company contents that we placed in the root site collection.

The customer’s requirement was to have a unique home page (with responsive design) for the corporate Intranet, through which accessing and sharing all the latest information and documents available all over the distributed network (remember: something is completely on-premises in the headquarters, something is in IaaS on Azure, and something else is in Microsoft Office 365). Lastly, there a bunch of SharePoint Apps (provider hosted apps on Azure PaaS) to enrich the Intranet network.

Overview of the Solution

We defined a solution that I think is really interesting:

  • We designed a “nice” (or supposed to be 🙂 …) and user friendly graphical solutions based on HTML5/CSS3/jQuery
  • We placed the page in SharePoint Online, as the default home page of the root site collection
  • We used the Enterprise Search Engine of SharePoint to index all the contents, leveraging an hybrid topology
  • We provided a unique and aggregated view of new items, documents, and tasks of every department/unit to which the current user has access to
  • Thanks to the security trimming features of the Enterprise Search Engine of SharePoint, every single user has a “personal” view of the contents (i.e. everyone sees only what is in target for him, of course!)
  • We provided an easy to use and fast to access entry point for any other search
  • We allowed the company to provide quick and fast company news in the home page

Here, in the following figure, you can see a sample of the final result (the contents are in Italian language and obfuscated, for privacy reasons):
Intranet-FFF-Home-Obfuscated_thumb_1EE4DD4D
As you can see, the home page takes inspiration from the well-known tiles of Windows 8, and provides animated contents to provide dynamic contents and live feedbacks to the end users, leveraging the metaphor of the live tiles.

You can find further “non-technical” details about the solution in the case study published by Microsoft Italy.

The Solution from a Technical Perspective

I know, I know 🙂 … you’re used to read technical contents on this blog … and here we are. Thus, how we made it, from a technical perspective?

We simply made an HTML5/CSS3/jQuery page that leverages the powerful REST API of SharePoint 2013/Online and we used some AJAX requests to query the Search Engine.

First of all, we provisioned a support list (custom list with a custom content type) to hold the list of all the available contents (site collections, SharePoint apps, search targets, etc.), which can be part of the home page. Then we used that list to feed a custom JavaScript/jQuery function that queries the sites for new contents (documents or tasks).

Here you can see a sample of the code we used to search for all the documents changed within the last 3 days (which is a suitable timeframe to consider a content “new” or “refreshed”):

$.ajax({
url: searchDocumentsUrl,
type: “GET”,
headers: {“accept”: “application/json;odata=verbose”},
success: function (data) {
var c = data[“d”][“query”]
[“PrimaryQueryResult”][“RelevantResults”][“RowCount”];
$(“#” + targetItem.attr(“data-area”) + “-docs-count”)
.text(c.toString());

totalItemsCount += c;
$(“#” + targetItem.attr(“data-area”) + “-total-count”)
.text(totalItemsCount.toString());

targetItem.show();
},
error: function (err) {
console.log(“Error query search for: ” + targetUrl);
}
});

The key part of the AJAX request is the URL (the variable highlighted in red color) that we used to query the search engine. Here you can see a sample URL (simplified to make it more readable):

https://{tenant}.sharepoint.com/sites/{sitecollection}/_api/search/query?
querytext=’IsDocument:true Path:https://{tenant}.sharepoint.com/sites/{sitecollection}/’&
sortlist=’LastModifiedTime:descending’
&selectproperties=’Title,Url,ContentTypeId,IsDocument’
&refinementfilters=’write:range(2014-08-13T15:07:48.0000000Z,max,from=”gt”,to=”le”)’

The base URL is the one of the search namespace provided by the REST API (the one highlighted in red color), followed by the invocation of the query method. The querystring parameters make the real work. Thus, here is a in depth explanation of the querystring parameters:

  • querytext: defines that we are looking for documents (IsDocument:true) and that we are targeting a specific site collection (via the Path constraint)
  • sortlist: it is just for the sake of completeness, it simply orders the results by modified date time descending
  • selectproperties: declares to retrieve a “brief” list of items, including only Title, Url, ContentTypeId and the IsDocument properties/fields
  • refinementfilters: this is the most interesting part of the query. Here we define to retrieve all those items that have a modified datetime (write) greater than (gt) the point in time in which we are executing the query, and lower or equal to (le) max (i.e. infinite) – credits to my friend Mikael Svenson for explaining that on his blog.

And the result will be something like this (in JSON format):
image_thumb_1_3EE28930
Where the “d/query/PrimaryQueryResults/RelevantResults/RowCount” path will contain the number of items found.

And now you can also use the JSON light format, announced and released a few days ago, getting the following result (using “odata=nometadata”):
image_thumb_2_3EE28930
In case you want to search for new or updated tasks, the query will be almost the same as before, but we will use a slightly different query rule in the querytext parameter. Here is an example:

https://{tenant}.sharepoint.com/sites/{sitecollection}/_api/search/query?
querytext=’ContentTypeId:0x0108* Path:https://{tenant}.sharepoint.com/sites/{sitecollection}/’&
sortlist=’LastModifiedTime:descending’
&selectproperties=’Title,Url,ContentTypeId’
&refinementfilters=’write:range(2014-08-13T15:07:48.0000000Z,max,from=”gt”,to=”le”)’

The search filter will be based on the content-type ID (see the syntax highlighted in red color). We query for every item with a content-type ID inherited from 0x0108, which means every kind of SharePoint task (including workflow tasks).

And the game is done! Feel free to reuse any part of these ideas, queries, and code. And feel free to give any feedback through email (paolo at pialorsi.com), twitter, or whatever else.

Now I’ll go back to my summer vacation … see you in September.