SharePoint + Flow (+ Azure Functions): Launching a Microsoft Flow from Client-Side Code

The requirement seemed deceptively simple… and it was, somewhat… simple. I’ll start with showing you how very simple it is to launch a Microsoft Flow (“flow”) from your client-side code hosted, well… wherever. I will give you this caveat, launching a flow this way requires no authentication. The URL is entirely obscure, but if you’re concerned that the flow you’re starting does something you only want to allow authenticated users in your organization to do then you may want to rethink this. As with all security issue you need to assess and balance security with risk. I suppose that’s true of life too.

Creating a Microsoft Flow that can be launched from the client

One of the most common uses of workflow, at least for me with my clients, is to send email notifications. Microsoft Flow is excellent at this, with the caveat that the email cannot be sent on behalf of the user running the workflow unless the user you use to create the send email step under in the flow can send email on behalf of the user running the workflow. That is to say, there isn’t a way to send email from the authenticated user with the Outlook connector without the appropriate permissions.

Ok, so let’s say you’d like to send an email notification from your client-side application running in SharePoint. The idea is that you would want to hand over to flow the information about how to compose the email and then it would do the rest. As my 5-year-old likes to say, easy peasy lemon squeezy. There’s even a walk-through of doing just this from Irina Gorbach on the Microsoft Flow Blog Calling Microsoft Flow from your application

To add to that post just a bit, the Request connector has a section for advanced parameters. The “Method” by default is a “POST”, you can certainly specify this strictly if you want. If you’re not passing parameters in your scenario and only want to use a GET, you’d have that option. Also, depending on your application there is a second parameter called “Relative path”. That’s used to specify your parameter on the path and use the “GET” method, this could be used for advanced routing in SPA applications. A more in-depth post in the Azure Logic Apps documentation can help you understand this scenario better Call, trigger, or nest workflows with HTTP endpoints in logic apps

Also, you may want to consider adding a “Response” action, also outlined in the afore mentioned Azure Logic Apps documentation, to your flow as the Azure post indicates to tell your client-side code what happened. If you don’t it will return a status 202 – Accepted by default.
Just to reiterate, once you have the flow done, you simply add an ajax/$http/<your favorite implementation of XMLHttpRequest> request to your client-side code, like you would to make any other REST call. Unlike with SharePoint calls though you will not need to add tokens to the header to make a POST call. Using AngularJS $http provider, the call would look like:

User Context for Microsoft Flow – The new elevated privileges

To keep with my lemon theme what might be considered lemons, in that you cannot execute actions as the user from a flow, we shall turn to lemonade, in that flow provides us developers with the perfect vehicle to execute work with elevated privileges. Given how much we can do through client-side code, all as the currently authenticated user, I’m personally quite happy with making this trade, especially with the addition of launching Azure functions as part of my flow. In my next scenario let’s discuss the idea of adding a Help Desk Request widget to the home page of every site collection in SharePoint. This reusable bit of code would be an excellent candidate for an SPFx web part but to keep the complexity level down I’m going to discuss it from the perspective of creating a basic client-side web part using the standard methods I often discuss which is to say using a SEWP/CEWP to put a bit of HTML/CSS/JavaScript on the page. The solution will basically be a form with a button that allows the user to enter the issue and submit it to a Help Desk list in another site collection that is secured to those that run the help desk.

When the user clicks submit what we’d like to do is launch a flow that will insert an item into the Help Desk Request list, where the user that is submitting the issue doesn’t even have read rights. To do this I’ve decided to create another O365 user called “Help Desk” that will act on the behalf of the help desk. That user has been given contribute rights to the Help Desk Request list. Yes, I’m absolutely aware that taking this action will require another monthly fee for that user, and I have to say I really wish there was a “service” account level user that we could add that could access an email box and get access to SharePoint, etc, etc, that would either be free or available at a significantly discounted monthly rate… sadly there is not.
Note: Although there is the concept of an unlicensed user that is a service account per say, the level of privileges that user would then have is way too high. Further, flow will not recognize it as a valid connection.
You could also do this with any other user that has access to the Help Desk Request list. However, please keep in mind that if that user ever leaves or their account is removed/deactivated for whatever reason your flow will stop working. At the very least you will want to make sure you share your flow with one or more other users so that if something happens there will be at least one other person with rights to the flow that can change the context of the actions.

First is the request trigger connection. I set this up with the following JSON payload where user is the user’s login name.

Next I added the SharePoint “Create item” action and set the values of the item with variables from my request trigger body. Note that I’ve made sure the action is running under the helpdesk@sympraxisconsulting.com user. This way the user will have permissions to add the item to the list.

If you’re looking at the above images and wondering wait, there are more fields in my form/JSON payload than in my flow “Create item” step… your eyes are not deceiving you. Read on…

Wait!? WHAT! Microsoft Flow can’t do that???? –Azure Functions to the rescue

This section is dedicated to my biggest pet peeve (at the moment) which is what I would consider basic missing features of Microsoft Flow SharePoint connectors. The fact that it lacks support for all basic list and library field types (i.e. Person, choice, manage metadata/taxonomy, etc), makes it somewhat less than a “mvp” (minimally viable product) but, well, who am I right. So, in lieu of a working product I’ll just share the work around. My griping aside, this section will hopefully become more and more obsolete with every passing month so I suppose that’s at least something.

My good friend Bob German (partially due to my relentless prodding) just posted an excellent series on creating Azure Functions that “talk” to SharePoint. You can read them here Calling SharePoint CSOM from Azure Functions. I used this method to write a customized Azure Function that would update my SharePoint list item created in the flow with the remaining information that could not be updated by the flow. I’m certainly not going to rehash what he expertly explained but I will share a tidbit that Bob also tracked down and why this post has been delayed a couple weeks and that is the API key for adding a custom connection to your Azure Function from flow.
To create the connection you need a swagger file/URL which you can get by going to your azure function and checking out the API Definition tab (in preview as of this post). I had tried to use the “Export to PowerApps and Flow” tool there but couldn’t get it to work, not that it won’t be working by the time you read this. Also, as of this post you’re going to need to do a little tweaking to the “Definition” section, for some reason it doesn’t really get what it needs from the swagger. Here’s what it looked like for me, your mileage may vary.

In all my efforts trying to get this to work properly at some point switched from pointing at the API Definition URL to trying to build my own swagger file, in hindsight I think the URL worked just fine.

More kudos to Bob on helping me through the security part. He figured out that the API key parameter label needs to be “code”.

And again, during Bob’s talk “Going with the Flow: Rationalizing the Workflow Options in SharePoint Online” he explained that to get the flow connector to understand my payload I needed to “Import from sample” which gives you a little flyout where you can specify how your REST call needs to look. Since I’m using the Body and not query string parameters my Request section is now all set for me.

Finally, my completed flow which I call exactly like the other simpler flow from the beginning of this post.

Hopefully a few of these scenarios will help you think through how you might make Microsoft Flow part of your SharePoint online solutions. Happy Coding!

Utilizing ngOfficeUIFabric People Picker in SharePoint

One of the great joys of developing custom forms in SharePoint is developing the controls for some of the more complicated field types, specifically the Taxonomy Picker and the People Picker. If you’re sensing sarcasm, you would be correct. There are brave souls out there who recreated these components for us that utilize no less than five (and sometimes more) Microsoft Javascript libraries. The reality is, for the People Picker, which is what I’m going to be discussing today, you’re really looking for a type ahead input field that filters a list of people that you can retrieve from SharePoint. Sounds easy right… *sigh* if only.

If you’ve started using the new SharePoint Framework (SPFx) there is a big push to use the OfficeUIFabric. This framework provides not only styling but components that mimic what we’re given out of the box. Unfortunately, if you’re not a React framework user it seems that the investment by Microsoft is significantly lacking. I suppose this makes sense. Regardless, a team of non-Microsoft people embarked on a community project to create an AngularJS version of this library, ngOfficeUIFabric. Although it has some issues, overall it seems to work pretty well, but given it took me a bit to figure out what does and doesn’t work and exactly the best way to wire it up I thought I’d share my findings. This is where you can find the online demo for the people picker.

The idea, is to provide a function that either returns a list of people that match the query string (or not, there really is no requirement) or a promise to return a list of people. It supports Angular’s ng-model directive as well as ng-disabled. Obvious missing components are the ability to specify whether the field should be multiselect or not (it’s always multiselect), and the ability to trigger any functions on selection or selection change, I believe this is potentially a bug. Never fear dear reader, we can get around these limitations for the most part and the ability to avoid seventeen million additional libraries is a huge plus. Further, the architecture will certainly work in modern… so for all you brave SPFx coders out there you can take the same principles and apply them to the React component or even this Angular component depending on which framework (you want to use).

Ok, let’s get down to brass tacks…

Data Source

The people picker component wants an array of objects with the following attributes. We’ll call that object “Person”

Attribute Description
initials Used in lieu of a users picture with a background color.
primaryText The primary display text identifier of the user/group.
secondaryText Some secondary information you want to highlight about the user/group.
presence Text value, available options are available, busy, away, blocked, dnd, offline
group The results group you want to display the person in when the results of the search are displayed. This takes the form of an object with the following properties { name: “Results”, order: 0 }
color If there is no image, this will be the background color for the users “Initials” block. Available options are lightBlue, blue, darkBlue, teal, lightGreen, green, darkGreen, lightPink, pink, magenta, purple, black, orange, red, darkRed
icon This is the URL to a thumbnail image of the user, if provided this will be used in lieu of the initials and color attribute.
id Ideally this would be the id for the user in your site collection, but in lieu of that it’s a good option to use the users account name, or fully qualified domain name.

Now that we understand what structure the data needs to take, we need to go get it. To my mind there are two ways to solve this problem, the first, and probably the easiest would be to use Search. By which I mean the Search REST endpoint in SharePoint. That will be the direction I’ll take for this post, that said, you could always leverage my previous posts on utilizing the Microsoft Graph API inside SharePoint and use that to get the results. That would have the distinct advantage of being able to provide significantly more interesting information about the user if you needed it.. like manager assuming your user data is complete and up to date <insert plug for Hyperfish here>.

Note: NGFPP.currentSite is the url for the current site collection

Now, as you can see from a Search query I’m not going to be able to get the user’s id which would be needed to set the value of a person field. In this scenario, I’m specifically attempting to get all the available users from our directory, not only the ones that have actually logged into our SharePoint site. So, before I’ll be able to create/update an item in a list I’ll need to convert that person’s id (account name) into an actual id from the hidden users list in the Site Collection. For that we can use the ensureuser REST endpoint which is analogous to its CSOM cousin.

UI

Now that we have all the back-end pieces put together we can get started with the user interface. The one bug that I still haven’t completely solved is that of a wrapping issue, you can see it in the screenshot below. I suspect that the issue is related to various SharePoint css attributes and I just haven’t found the right one to override. But it’s trivial so I’ve decided to move on without solving it for now. Eventually I’m going to get it!

Since I’m on the topic let’s start with a couple minor CSS overrides you’ll want to include within your form. I’d strongly suggest scoping them to your form as well as you wouldn’t want to upset SharePoint styling elsewhere.

Now onto the HTML, here’s a small snippet of a table that I created for the “form”. I’m only showing the row for the People Picker in it. Of note, uif-people is linked to a variable on my controller that is assigned the function and the ng-model is linked to an empty array that can receive the selected “Person” items from the source array. In my example, I’ve decided to use the compact type and include a search delay… these are options and I’d encourage you to look over the demo’s to decide what’s right for you.

Controller

Single User Hack

One of the missing components of the solution is the ability to limit the user to selecting only one value. The work around I came up with, which I completely admit is a hack, was to implement a $watchCollection. This way when I see the model change I can determine if more than one item is selected and if so replace the originally selected item with the newly selected item. I’ve found in implementation this looks very smooth to the user so I’m happy with it as a work around. To add this to the above controller you would do the following:

Summary

So even with its flaws I’m moving forward with the implementation simply because it feels like a significantly cleaner solution. If someone out there takes this on and solves the css issues before I do PLEASE let me know and I’ll update the post with your solution. Hopefully I’ll figure it out soon!

Resources

The complete code is available on my GitHub repo if you’re interested in looking at the complete solution.

Code Creep – SharePoint “CDN”

Centralizing your SharePoint client side code

“Code Creep”… no it’s not the latest thriller movie out of Hollywood, although it probably could be. I’m referring to the sprawl of client side code files that are stored when implementing client side web parts or “widgets” in SharePoint. A common solution for implementing “widgets” in SharePoint is to store the files in a document library, linking to them with a CEWP that will then run and render your “widget”. This is an effective way to implement customization when you don’t have administrator access, or you’re running in SharePoint online, or you just prefer the flexibility of a client side development paradigm; as some of my colleagues in the SharePoint community like to say, “It isn’t code, it’s content.” However, depending on the complexities of your environment and your development staff, this kind of end run can cause maintenance issues at best, horror stories at worst.

There are many ways to solve the code creep problem, from simple to incredibly complicated, and of course, as with everything there is no one-size-fits-all answer. Some guidance from my perspective centers on where your code will be implemented and how big your farm/tenant(s) are.

I’ve created a matrix below that outlines my thoughts on the subject.

solutionmatrix

 

The solution I’m going to focus on in this post is the “Store code in a site collection specifically for your client side code”, or basically creating a private CDN (Content Delivery Network) within your own tenant/farm.  In my opinion this is a fairly good solution to balance code maintenance/deployment without going all the way to the cost and complexities of implementing a full blown commercial style CDN.

The scenario is that you have developed or are developing client side “widgets” that you’re going to use in multiple site collections within a farm or tenant. My solution is to build a site collection specifically for storing the code needed to render those widgets.  And by code I mean all the html, js, and css files.  Any third party libraries that are already hosted on a CDN could be referenced separately and do not need to be added to your internal CDN, however, my rule of thumb is that if your SharePoint farm is behind a firewall and people access it from an internal network, you should consider downloading copies of the libraries you need and host them locally.  No reason why your solutions shouldn’t work if the internet goes down.

So let’s say I create a new site collection and I call it CDN so that my URL is http(s)://mysharepointurl/sites/CDN

I can disable most site collection and site features, leaving enabled at a minimum:

  • SharePoint Server Standard Site Collection features
  • SharePoint Server Standard Site features

Everything else is optional depending on what you want to do in your CDN, create approval workflows, etc…

The key to the solution is getting the permissions right. We want to make sure that everyone that needs access to code at any time now or in the future can get it, otherwise the “widgets” won’t work for them. But what we’d also like is the ability to version and “lightly” test that code without affecting them. So to that end we’re going to give “All authenticated users”/”Everyone” read permission to our CDN site by adding them to our CDN Visitors group. We can then add our developers to the CDN Members group, and we can add our CDN Managers or Administrators to the CDN Owners group. Now, by default, unless we break inheritance, all our code “libraries” will be able to be read by everyone and managed by our developers.

With permissions taken care of, we can create a library or libraries in the site to hold our code. There’s a lot of ways this could be organized and you should certainly take some time to think it through. Maybe you want to have different groups of developers have contribute rights to different code bases, etc… the key is to make sure you don’t remove visitors read rights from any of your code libraries and that you modify the versioning settings of your library as follows, the key being that we want Draft Item Security set to “Only users who can edit items”.

 

This allows you to “publish” major versions of the code files and until you do the user will continue to use the last published version.  Now you to do some “light” testing on the modifications to make sure everything is working before you “publish” it to the users.  I do not encourage you to use this method as a full out ALM solution but as a light weight one it can work well.  You could also in theory create approval workflows that would “publish” the content for you, but that’s a different post.

librarysettings

 

minorversion_libviewSo here’s an example of how you might use this.  I’ve uploaded some files into my “Code” library and note that they’re all minor versions of the file.  I’ve added myself as a CDN Member so I have the ability to “Contribute” to this library.

Now I need to insert the widget on the page and to do that I need to be a tad fancy.  This is because I cannot use a simple CEWP and point to the URL of an html file in my CDN Code library because CEWP cannot cross site collections.  To get around this you can either write your own binding function or utilize the Widget Wrangler to bootstrap your code simply into the page.  Below is an example of using a SEWP for that purpose with the Widget Wrangler to implement an AngularJS 1.x application:

puttingcodeonpageThe key here is that this code embedded onto the page is benign. Other than referencing the files that implement the solution it really doesn’t do anything and therefore it won’t need to be changed in order to modify the widget’s UX.

Now if we save the page and view it we’ll see our widget. Because our files have not been published my end users see nothing.

minorversion_julie

 

If I then publish all the files for this “widget” you can see that the end user now sees the same thing I do.

majorversion_user

 

So, as you can see there are real ways to help avoid the dreaded “code creep”.  From simply storing all your code in a library in the site collection to utilizing a commercial CDN.  The moral of the story is there is no one-size-fits-all answer, so you need to assess your needs and try and centralize your client side code in a way that makes the most sense for your environment allowing you to manage your solutions from one location.