January 2015 - Posts

The new functionality of Office Delve, Boards, just came out recently.  As a developer, you might be thinking how can I access this data in my own applications.  This post will help you get started.  These queries use the new Graph Query Language (GQL) syntax of Office Graph.  As the GQL reference link points out you should be warned that these APIs are highly subject to change and should not be used in production applications.  The queries we are using today were determined by examining the REST API calls from the pages inside Delve.  They may work now, but they may not work in the future.

Querying the boards a user is following

First, we want to determine which boards a user is following.  We want to return the same data that we see in the left navigation of Delve.

DelveBoardList

It appears Delve makes use of a new “protocol handler” like technology that has it’s own URL syntax.  These URLs look like TAG://PUBLIC.  To get the list of boards a user is following, we issue the following query:

TAG://PUBLIC/?NAME=*

However, we also have to include some Properties in our REST query to get the data we need.  In particular interest is the new GQL action number 1050 that you use on the me actor.  Here is what the entire REST query looks like.   I recommend limiting the SelectProperties that you returnThe important ones are Title, Path, and DocId.

https://<tenant>.sharepoint.com/_api/search/query?QueryText='Path:"TAG://PUBLIC/?NAME=*"'&Properties='IncludeExternalContent:true,GraphQuery:actor(me\,action\:1050),GraphRankingModel:action\:1050\,weight\:1\,edgeFunc\:time\,mergeFunc\:max'&SelectProperties='Title,Path,DocId'

Try typing it in the browser of your tenant. 

DelveBoardFollowedXml

Looking at the individual results, you’ll see the name of the board, it’s path and the DocId.   The Title contains the name of the board in all caps.  The Path we can use to query items that have been tagged. The DocId actually refers to an ActorId that we’ll use later.

Querying the items tagged to a board

When you visit a board’s page in Delve, it actually issues two queries to get the items that have been tagged to the board.  First, it issues a query using the path we saw above.  It does this to get the ActorId which is stored in the DocId property.  It then uses that ActorId in a second query to get the actual items that have been tagged to the board.  If you already know the ActorId, you can obviously skip the first step to retrieve it.

To get the ActorId, we issue a query using the path on the TAG URL with the name in all caps following the NAME parameter.  This is just like what we saw in the results above.  Here is what the REST query looks like.  We are only interested in the DocId property so we specify that in the SelectProperties.

https://<tenant>.sharepoint.com/_api/search/query?QueryText='Path="TAG://PUBLIC/?NAME=<board name>"'&Properties='IncludeExternalContent:true'&SelectProperties='DocId'

Now let’s write some JavaScript code to retrieve this value.  In my example, we’re going to retrieve the ActorId for the Marketing board in a SharePoint-hosted app.  Make sure you request the Search permission in your AppManifest.xml.  I have URL encoded the URL.  This just uses a simple call with $.ajax.  I’ve left out the use of deferreds to keep it simple. 

$(document).ready(function () {

    var queryUrl = _spPageContextInfo.webAbsoluteUrl + '/_api/search/query?' +

        'QueryText=%27Path%3D"TAG%3A%2F%2FPUBLIC%2F%3FNAME%3DMARKETING"%27&Properties=%27IncludeExternalContent:true%27&SelectProperties=%27DocId%27';

 

 

    $.ajax({ url: queryUrl, method: "GET", headers: { "Accept": "application/json; odata=verbose" }, success: onQuerySuccess, error: onQueryError });

 

});

In our onQuerySuccess function, we will retrieve the value of the ActorId.  Remember it is stored in the DocId managed property.  The data of search results is buried in multiple objects, so you have to go through quite a bit to get to it.  For more information on querying search with JavaScript and REST, see this code sample on MSDN Code.

function onQuerySuccess(data) {

    var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;

 

    var actorId;

    $.each(results[0].Cells.results, function () {

        if (this.Key == 'DocId')

            actorId = this.Value;

    });

 

    $("#actorId").html(actorId);

}

Now, that we have the ActorId, we can issue the query to get the item associated with the board.  In the simplest form, you issue a query with QueryText of * (everything).  You then issue a GraphQuery using the ActorId and the undocumented ActionId of 1045.  However, if you want the query to match exactly what is on the Board page, you need a few additional exclusions.  These exclusions specifically remove content hidden from Delve as well as only show specific file extensions.  Here is what the REST URL looks like.

https://<tenant>.sharepoint.com/_api/search/query?QueryText='* AND ((NOT HideFromDelve:True) AND (FileExtension:doc OR FileExtension:docx OR FileExtension:ppt OR FileExtension:pptx OR FileExtension:xls OR FileExtension:xlsx OR FileExtension:pdf OR ContentTypeId:0x010100F3754F12A9B6490D9622A01FE9D8F012*))'&Properties='GraphQuery:actor(<actorId>\,action\:1045),GraphRankingModel:action\:1045\,weight\:1\,edgeFunc\:time\,mergeFunc\:max,IncludeExternalContent:true'

When it comes to the JavaScript, we simply replace out the ActorId  Again we encode the URL.

var boardQueryUrl = _spPageContextInfo.webAbsoluteUrl + '/_api/search/query?' +

    "QueryText='* AND ((NOT HideFromDelve:True) AND " +

    "(FileExtension:doc OR FileExtension:docx OR FileExtension:ppt OR FileExtension:pptx OR FileExtension:xls OR FileExtension:xlsx OR FileExtension:pdf OR ContentTypeId:0x010100F3754F12A9B6490D9622A01FE9D8F012*))'" +

    "&Properties='GraphQuery:actor(" + actorId + "%5C%2Caction%5C%3A1045),GraphRankingModel%3Aaction%5C%3A1045%5C%2Cweight%5C%3A1%5C%2CedgeFunc%5C%3Atime%5C%2CmergeFunc%5C%3Amax,IncludeExternalContent:true'";

 

$.ajax({ url: boardQueryUrl, method: "GET", headers: { "Accept": "application/json; odata=verbose" }, success: onQuerySuccess2, error: onQueryError });

Now, in our success function, I simply return the results as a table by iterating through all of the rows and cells of the results.  The first loop prints out the column names and the second one writes out each row.

function onQuerySuccess2(data) {

    var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;

 

    $("#results").append('<table>');

 

    $("#results").append('<tr>');

    $.each(results[0].Cells.results, function () {

        $("#results").append('<th>' + this.Key + '</th>');

    });

    $("#results").append('</tr>');

 

    $.each(results, function () {

        $("#results").append('<tr>');

        $.each(this.Cells.results, function () {

            $("#results").append('<td>' + this.Value + '</td>');

        });

        $("#results").append('</tr>');

    });

 

    $("#results").append('</table>');

}

Here’s what my results look like in my SharePoint-hosted app.

DelveBoardResults

Comparing it to the original page in Delve for the boards, you will notice the results are the same.

DelveBoardMarketing

If you are interested in developing with Boards in Office Delve, I hope you have found this post helpful.  This information hasn’t really been documented so it’s highly subject to change.  Try it out and let me know what you come up with.

Follow me on twitter: @coreyroth

Updated: January 9th, 2015

You might have heard today that the new Boards (aka Pinterest) feature for Office Delve was released to First Release customers of Office 365.  I was lucky enough to have it show up already in a few of my tenants, so I thought I would share my initial experience. 

When you open Delve now, you’ll notice a new icon that says Add to board

DelvreBoardNoTag

Clicking on the icon will allow you to type the name of a new board or select an existing one. 

DelveBoardNewBoardName

Once you have tagged your document, it will show underneath the document for all users.  Items tagged to boards are visible to all users.  However, the results are still security trimmed like everything else.  That means if Sara pins something to Acquisitions, but Alex doesn’t have permission to it, Alex won’t see it.

DelveBoardItemTagged

Clicking on the tag will take you a page with other items tagged.  When you first visit any board’s page, you will automatically be “following” it.  I suspect this makes the board show up in your list of boards in the navigation of Office Delve. 

DelveBoardPage1

When you click the Send a link button, it will open your mail client with a link to the board’s page in Delve.

 DelveBoardSendEmail

If you look at the URL, you will notice a new query string parameter, b, with the board’s name.

DelveBoardUrl

Items can also belong to multiple boards.

DelveBoardMultipleTags

After we have added some items to boards, here is what a typical page might look like.

DelveBoardHome

You can remove an item from a board by right-clicking on the tag and choosing Remove from boards.

DelveBoardRemoveTag

New features tend to roll out over time in First Release, so one feature that is notably missing is the list of boards I am following.  It should be above the People list.  I suspect this will show up soon, and I’ll update my post with details when it arrives.

DelveBoardNoList

My understanding is that your list of boards updates every two hours or so.  After checking Delve later, the list of boards I am following now shows up.  If you unfollow a board, it will still show in this list until the cache clears.  If you create a new board, it won’t show up in this list until then either.

DelveBoardList

The concept of removing and managing boards has been a hot topic on Yammer this week.  If you are interested in the topic be sure and follow this thread.

Delve Boards are an interesting new way of tagging documents.  It lets users organize things in logical buckets that make sense to them.  Now you might be wondering if this ties into anything like Managed Metadata Enterprise Keywords and unfortunately the answer is no.  The new system is disconnected from that.  I think users will like it though.  As an administrator though, it might be a while before you can do any maintenance of the boards.  I don’t think you need to worry about that too much though yet.  The whole purpose of this is that the tagging is end user driven and easy for the users.

Updated 2/4/2015: Read my full Sling TV product review on IT Unity.

Dish Network announced at CES this week a new Internet-based TV service called Sling TV for $20 / month.  This new service, scheduled to launch in the first quarter of 2015, will allow those without a traditional cable / satellite TV package to get the following 12 cable TV channels:

  • ESPN
  • ESPN2
  • TNT
  • TBS
  • Food Network
  • HGTV
  • Travel Channel
  • Adult Swim
  • Cartoon Network
  • Disney Channel
  • ABC Family
  • CNN

Most specifically in this list are ESPN and TNT.  As an avid NBA fan, watching primetime games can’t be done without a traditional cable package.  With NBA League Pass these games are blacked out during primetime.  This is a great option for college sports as well.  I’ll be curious to see if your Sling TV subscription includes rights with WatchESPN.com.  As someone who watches sports, this offering looks appealing.

Sling TV will be available on most of the popular streaming devices such as Amazon Fire TV, Google, Roku, and the Xbox One.  Most notably missing from this list if the Apple TV.

Is this a step in the right direction though?

Absolutely not.  This is more of the same from TV providers just a new medium.  It still doesn’t give us the a la carte pricing that we want.  It just gives us smaller and more manageable packages (not a bad thing for sure).  I’m still happy to see more options out there for those who don’t want a traditional TV package. 

I also think the pricing is a little high for what a cord-cutter is willing to spend.  Part of what is driving that cost up is the including of ESPN which costs a provider more than $6 a user in fees.  Keep in mind, our bill is already starting to add back up with our multitude of services we have such as Netflix, Hulu Plus and CBS All Access.

Even though it’s a small bundle, it still suffers from the same problem as the larger bundles.  I personally only need sports programming.  While some other people may only need kids programming.  Don’t make me get both.

If you don’t watch sports, I would say there is no reason to ever pick this package up as a cord-cutter unless you just want programming from the Food Network or the Disney Channel.  Those with younger kids, I could certainly see the appeal though.  Until the content offering for sports improves online, I could see myself subscribing to this for a few months during the year.  The nice thing is there isn’t a contract to lock you in.

The TV industry is having to shift this year thanks to the large number of streaming services coming to market.  Already we have seen CBS and HBO offering an online-only offering and I suspect a few more networks will have offering by the end of the year.  I think 2015 will be a good year for cord-cutters.

Read more about Sling TV on their site.

Follow me on twitter: @coreyroth

with no comments
Filed under: ,