Thursday, 31 August 2017

Introducing spfx-extensions-cli: A command line tool to manage SPFx extensions

I have just published a CLI tool to view and manage SharePoint Framework extensions:
https://www.npmjs.com/package/spfx-extensions-cli

More details in the package README.

Code is available on GitHub. Feel free to play around and submit any feedback:
https://github.com/vman/spfx-extensions-cli


Thursday, 27 July 2017

Simultaneously run multiple versions of the SPFx Yeoman generator with npx

This is a topic which has been discussed quite a lot since the launch of the SharePoint Framework. The SPFx Yeoman generator is recommended to be installed globally, but what if a new version is released and I want to try out the new version without uninstalling my globally installed generator? 

Waldek Mastykarz has a great post on the issue and suggests some solutions as well. Have a look at his post if you haven't already: Why you should consider installing the SharePoint Framework Yeoman generator locally

In this post, lets have a look at how we can use npx to provide a solution to this problem.

If you haven't heard about npx yet, it is the hot new member of the node ecosystem. Check out the introduction post by Kat March├ín:

In short, npx can be used to run npm packages directly from the command line without having to install them globally or locally.

npx comes bundled with npm@5.2.0 but unfortunately, the SharePoint Framework does not support npm@5.x.x yet. 

Lucky for us, npx comes as a standalone npm package as well: https://www.npmjs.com/package/npx

We are going to use the npx package with npm@4.6.1

From the intro post:

Calling npx <command> when <command> isn’t already in your $PATH will automatically install a package with that name from the npm registry for you, and invoke it. When it’s done, the installed package won’t be anywhere in your globals, so you won’t have to worry about pollution in the long-term.

This means that when we run the SharePoint Framework generator through npx, it will be as if it is running from a global install. After the SPFx solution is created, you will not find the generator installed either locally or globally. It has served it's purpose of generating us a solution and is no longer needed. 


Run different versions of the SPFx Yeoman generator in different folders: 


Now lets actually use npx to create two different SPFx solutions using two different versions of the SharePoint Framework Yeoman generator. We will use the latest version of the generator and the very first version of the generator which was part of SPFx Drop 1.

I am using the following command throughout the post to list the top level global packages:



I have done a global install for gulp already. This is to keep things simple as we only want to use npx for the SharePoint Framework generator. If we wanted to take things to the next level, we could use gulp through npx as well.

Now, let's go ahead and install npx globally:


After it's installed successfully, lets have a look at our global packages again:


As you can see, neither the SharePoint Framework generator, nor Yeoman itself is installed globally. This makes us free to use any version of the generator we want. Let's use the latest version, which at the time of this writing is 1.1.0

First, I am going to create a new folder named "latest" and navigate to it. Then run the following:


By specifying the -p (package) flag we run the yeoman (yo) and SPFx generator (@microsoft/generator-sharepoint) packages through npx. 

After that, we run the SharePoint Framework generator by running  -- yo @microsoft/sharepoint

 



Now let's run gulp serve to launch the workbench. As mentioned before, since we have already installed gulp globally, we don't have to install it again.




Now let's see the real power of npx. We will navigate to another folder and use Drop1 of the SharePoint Framework generator to create an SPFx solution.

I have created another folder called drop1. Lets navigate to it and run the following using npx:


As you have probably noticed already, the only difference in this and the previous npx command is that we are using the version numbered 0.0.65 of the generator and not the latest. This was the version of the generator when Drop 1 of the SharePoint Framework landed back in August 2016.


You will notice immediately that there are some differences in the wizard. It asks me whether to create a new folder for the solution or use the current folder. It also defaults to creating a web part and does not ask me whether I want to create an extension. This is obvious given that extensions were not part of the first drop. 

After running gulp serve, we can see the Drop 1 workbench running:



That's it! We have used two different versions of the generator to create two different solutions without having to install the generator on our machine!

Using a new version of the SPFx generator when an older version is already installed globally:


If you have been closely following the post, you know what's coming next. 

Let's say we already have a version of the generator installed globally. Now a newer version of the SPFx generator is released and we want to try it out immediately. All we have to do is use npx to run the latest version. We would be able to create a new SPFx solution with the latest generator and still keep our old generator installed globally!

The magic is described in the npx package description

If a full specifier is included, or if --package is used, npx will always use a freshly-installed, temporary version of the package. This can also be forced with the --ignore-existing flag.

This is good news because we want to have control over which generator version is used by npx to create our solution.

Here is how the process will look:


I already have the Drop 1 (0.0.65) version of the generator installed globally. Next, we are running npx and specifying it to use the latest version of the generator.

After the command is run, we are presented with the wizard which gives us the option of creation an SPFx extension. This option was not available with Drop 1 which means that the latest generator is being used to create our solution.

This is how we can use npx to explicitly specify the generator version and ignore the globally installed generator!

Where does npx store the packages?


If we navigate to our npm-cache folder, we will see that npx stores all the versions of the package in the cache. Here, we see that the @microsoft/sp-build-web package was used in both versions of the generator, hence both versions are being stored in the cache:


That's it! Hope you have enjoyed this post as much as I have enjoyed writing it :)

Wednesday, 26 July 2017

Working with the Page Comments REST API in SharePoint Communication sites

If you have been playing around with SharePoint Communication sites, you might have noticed there is commenting functionality available now on site pages. Digging deeper on how this functionality is implemented gives us some interesting findings!

There is a Comments REST API available which is used to get and post comments for a particular page. This endpoint is an addition to the SharePoint REST API, which means you will already be familiar with using it.

I checked with Vesa Juvonen from Microsoft and he has confirmed this is indeed a public API, which means it can be used in third party solutions and is not something internal used only by Microsoft.


There are a few interesting things about how the commenting solution is implemented:
  1. Comments are not stored in the page list item (which makes sense in terms of scalability). They appear to be stored in a separate data store.
  2. Comments are stored with references to list guids and item ids. This means that if you move or copy a page, comments for that page will be lost.
  3. Only a single level of replies is allowed. Which in my opinion is a good thing as this will prevent long winding conversations and force users to keep their comments brief.

Now lets have a look at the SharePoint Comments REST API:

1) Get comments for a page:

/_api/web/lists('1aaec881-7f5b-4f82-b1f7-9e02cc116098')/GetItemById(1)/Comments

This will bring back all the top level comments for a page which has the id 1 and lives in a site pages library with guid "1aaec881-7f5b-4f82-b1f7-9e02cc116098". 

2) You can also use the list title to get the list and the comments:

/_api/web/lists/GetByTitle('Site Pages')/GetItemById(1)/Comments

3) Get replies for each comment:

/_api/web/lists('1aaec881-7f5b-4f82-b1f7-9e02cc116098')/GetItemById(1)/Comments?$expand=replies

4) Get replies for a specific comment:

/_api/web/lists('1aaec881-7f5b-4f82-b1f7-9e02cc116098')/GetItemById(1)/Comments(2)/replies

Where 2 is the id of the comment. 

5) Post a new comment on a page by making a POST request to:

/_api/web/lists('1aaec881-7f5b-4f82-b1f7-9e02cc116098')/GetItemById(1)/Comments

6) To Delete a comment or a reply, Make a DELETE request to:

/_api/web/lists('1aaec881-7f5b-4f82-b1f7-9e02cc116098')/GetItemById(1)/Comments(2)

Since each comment or reply gets a unique id, the method is same for deleting both.

Here is some sample code I put together to use the Comments REST API in an SPFx webpart:


Get comments for a page:



Post a comment on a page:


Code for this web part available on GitHub: https://github.com/vman/spfx-sitepage-comments/

Quick note about running the webpart on the SharePoint Workbench: If the page on which you want to read or post comments lives in a communication site with url:

https://tenant.sharepoint.com/sites/comms/SitePages/ThisIsMyPage.aspx

Then make sure you are running the workbench from the same site:

https://tenant.sharepoint.com/sites/comms/_layouts/15/workbench.aspx

Hope you found this post interesting!

Friday, 21 July 2017

Using CSOM with an account configured with Multi-factor Authentication (MFA)

Here is some quick code I put together for using CSOM with an account which has MFA enabled. It uses the SharePoint PnP Core library which can be found here: https://www.nuget.org/packages/SharePointPnPCoreOnline

This will give you a prompt to enter your details:

Thursday, 13 July 2017

Using Redux Async Actions and ImmutableJS in SharePoint Framework

I was recently working on converting my hobby project Office 365 Public CDN manager from JS, Knockout and jQuery into TypeScript, React and general ES6 code. It was a really great learning experience! If you want to see the final(-ish) code, have a look here: https://github.com/vman/SPO-CDN-Manager

While working on it, I came across libraries like Redux and ImmutableJS and how they help solve particular problems in React and the modern JS world. This really peaked my interest, so naturally, like all new things I learn, I tried to see how they could be applied to SharePoint. So in this post, lets have a look at what problems do Redux and ImmutableJS solve and how we can use them in a SharePoint Framework web part:

Source of this web part is available as a part of Microsoft's SharePoint Framework client-side web part samples & tutorials on GitHub: https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-redux-async-immutablejs



Why Redux?


I am going to assume that you are familiar with React and understand the basic concepts. If not, have a look at the tutorials on the react website, they are really great to get you started.

So as you know, the way React components work is every component displays it's UI based on the component's state. When the state is updated, the UI of the component is updated as well.

Since I was working with multiple components, I quickly realised that some events in my application would mean updating the state of more than one component. How do we make this happen? The easy (but not so great) solution was to move the state in the parent component of the two child components and then pass the state as properties to the child components. If we wanted to update the state from a child component, we would update it using a function (which is also passed as a property to the child component). When the state in the parent component was updated, it would automatically update all the child components as well.

This would quickly become tedious as more components are added to the application. The state will have to be passed down deeper and deeper in the component tree which is not really ideal.

Luckily, there is a nice solution to this problem with the introduction of Redux. With Redux, what we do is maintain the entire state of our application in a single object. This state is connected to our components and is passed as properties to them.  Any change to the state is defined with an Action which is dispatched when an event occurs.The Reducer receives the Action and updates the necessary elements of the state. (Which in turn updates the UI of the relevant component)

This is the general idea of Redux. If you want to have a deeper look and also check out some advanced concepts, there are some excellent tutorials here: http://redux.js.org/

Working of the SharePoint Framework webpart:


When the page loads, a redux action is fired which makes a REST API call using SPHttpClient to the current site and gets all the lists. Once the lists are fetched, another redux action is fired to instruct that all lists were successfully fetched from the server. The reducer listens for these actions and updates the state (UI) accordingly.

We can also create a new list from the webpart. When the user enters a value in the text box, an action is dispatched which updates the element in the state which represents the new list title. When the user clicks on the "Add" button, an action is dispatched which again makes an async call using SPHttpClient to create the list. Once the call is successfully returned, the UI is updated with the name of the new list.

Redux Async Actions:


Each async operation ideally has 3 actions to go along. This is not a requirement but is helpful to nicely manage our UI when the operating in being performed. We will see why we need 3 actions for one operation in the Reducers sections below. For now, all we need is a "request" action which we will fire before making the async call, a "success" action which we will fire after the aync call returns successfully and then an "error" action which will be fired if the async call returns an error.  Here are the 3 actions we will use in our webpart, and then a parent action to wrap them all together:


Reducers:


A reducer determines how the state should change after an action occurs. For example, when a "request" async action is triggered the reducer changes the application state to show a loading icon. When a request is successfully completed and it returns data from the server, the "success" action is triggered and the reducer determines that the loading icon should disappear and the data should be shown instead. Similarly, if an error would be returned from the server, the "error" action would be triggered and the reducer should show an error message on the screen instead of the loading icon. Here is our reducer code which modifies the sate using ImmutableJS. In this code, to keep things simple, we are only updating the state when the success action is dispatched. We are not showing or hiding a loading icon here.


When a reducer updates the state, a core principle of react is that we should never mutate the state object. We should always make a copy of the state, update the necessary elements in the copy and then return the copy as the new state. More details on why immutability is important here: https://facebook.github.io/react/tutorial/tutorial.html#why-immutability-is-important

ImmutableJS:


Let me begin by saying that using Immutable JS with Redux is not mandatory. We can use native ES6 features like Object.assign or the spread operator to create a new copy of the state, update the necessary elements and return the new copy. (Just remember that for supporting IE, we will need polyfills for these) If we have small to medium sized application, this is perfectly fine.

But if we are maintaining lots of elements in our state, making a new copy of state for every action can be really performance intensive.  For changing only a single element, we have to copy the entire state tree in memory, and that too for every action. Fortunately, ImmutableJS comes to the rescue here.

Using ImmutableJS, we can create a new state object in memory without duplicating the elements which are unchanged. When we create a new state object using ImmutableJS, the new object still points to the previous memory locations of unchanged elements. Only the elements which are changed are allocated new memory locations. The new copy of the state points to the same memory locations as the old copy for unchanged elements and it points to the new memory locations for the changed elements.

Here is our application state which extends the Immutable.Record class:

We have used TypeScript readonly properties in the state to mandate that these properties should never be updated directly. Instead, the custom "setter" functions should be used. In the setter functions, we use ImmutableJS methods such as "set" and "update". These functions take care of returning a new copy of the state where the only the changed elements are stored in new memory locations.

Hope you have enjoyed reading this post.

Check out the full code of the web part here: https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-redux-async-immutablejs

Friday, 7 July 2017

Including only required Babel polyfills with Webpack

If you are using something like Object.assign or Promises in your ES6/TypeScript code, you will sooner or later come across the fact that IE11 does not support them natively. In such cases, the natural way forward is to include a polyfill to get them working.

Babel has a polyfill library based on core js which has polyfills for a lot of such ES6/ES2015 features.

But you don't want to include the entire polyfill library in your application if you are only using a couple of polyfills.

Here is a handy way to include just the polyfills you need using webpack:

1) Add babel-polyfill to your dev dependencies:



2) And then include the required polyfills in your webpack config:



This will make sure that only the polyfills you need are included in your webpack bundle.

More info here:
https://github.com/zloirock/core-js#commonjs
https://babeljs.io/docs/usage/polyfill/

Hope you find this useful!



Monday, 12 June 2017

Access Microsoft Graph from classic SharePoint pages (SPFx GraphHttpClient preview: Under the hood)

Recently, an update to the SharePoint Framework was released which introduced some cool new features including ApplicationCustomizers, FieldCustomizers and CommandSets. You can read more about the announcement here:  Announcing Availability of SharePoint Framework Extensions Developer Preview.

What was particularly interesting to me was the introduction of the GraphHttpClient class which makes it really easy to call the Microsoft Graph from within the SharePoint Framework. To make a call to the Graph, all you have to do is:


And all the plumbing and authentication required to successfully execute the call is handled by the GraphHttpClient class.

At the time of this writing (12th June 2017) the only permission scopes available to the GraphHttpClient are Group.ReadWrite.All and Reports.Read.All So if you call any Microsoft Graph endpoints which require permission scopes apart from these, you will get an "Insufficient privileges to complete the operation." error.

Also, the GraphHttpClient is in preview right now and not meant to be used in production.

So lets see what's going on behind the scenes here. How does the GraphHttpClient get the correct access token scoped to the current user?

Turns out it is really straightforward. If you observe the traffic sent/received, you will notice that to get the access token, the GraphHttpClient makes a request to a new endpoint: /_api/SP.OAuth.Token/Acquire

Update 10/07: According to the guidance released recently, Call Microsoft Graph using the SharePoint Framework GraphHttpClient this endpoint is subject to change and not meant for use in production. But the good news is that as mentioned in this twitter conversation https://twitter.com/simondizparc/status/879636058446680064, Microsoft is working on making the Graph accessible outside the SharePoint Framework. So we will just have to wait until then.

I will just keep my post here for informational purposes:

Since this endpoint is hosted in SPO itself, it knows who the current user is and returns the correct access token. Some additional details are required to call the endpoint such as the current request digest and the resource for which the access token is required i.e. http://graph.microsoft.com

So in theory, if we replicate the behaviour of the GraphHttpClient in a classic SharePoint page, we would be able to call the same endpoint and get the access token. And it works!

Here is my code which uses simple jQuery to get the access token for the Microsoft Graph and makes a call to a /v1.0/groups endpoint. Since it is just JavaScript code, it can be called from a Content Editor or a Script Editor webpart on a classic SharePoint page as well!

And here is the result:


This is very interesting and can open up new possibilities!