Thursday, 29 June 2017

Office 365 developer wish list (SPFx and modern sites), summer 2017

Clearly we’re in a transitional period in Office 365 at the time of writing (June 2017), where modern SharePoint experiences are available - modern sites and pages for example - but not everything is fully joined-up yet. That said, it’s a fast-moving landscape and part of the consultant’s role is to keep up with the best way to deliver solutions. For once, I hope this is a blog post which dates very quickly – certainly I have had to add bits of info as I’ve been writing it, and I’ll come back again and update the table below as things get announced/released.

Going back to that ‘transitional period’ - this is especially the case for organizations with collaboration workloads, where there’s a need to create some kind of site template for team sites. This is still very common for our clients, even if it’s just a need to provide a different home page experience or add some lists/libraries/content types/global admins to the site. After all, I think that *whatever* Microsoft provide as the default experience, many orgs benefit from some lightweight changes to this – and so site templating continues to be important in SharePoint. I hope Microsoft don’t lose sight of this. Certainly when I consider my wish list, many items relate to “doing team sites at scale” in SharePoint – so perhaps let’s think about that first.

Current site templating challenges

Currently site templating is challenging because:

  • Want to use Group sites? Well, it’s challenging to template these currently, because:
    • Can’t currently specify a custom template
    • Can’t currently be notified that a new site has been created, because there are no web hooks
      • [By the way, I agree there are  ways around this (e.g. web job/function which polls for new sites), but none are pretty because users may start using the site in one state, only for it to change as they are working in it..]
  • Want to use non-Group SharePoint sites? Currently challenging to template these *and get modern experiences*, because:
    • Even the Patterns and Practices (PnP) site templating doesn’t currently allow provisioning of modern pages – at least, not without some dev effort to extend it

For our clients who don’t want to use Groups, that 2nd approach is becoming common for us. But it would be nice if it was more baked-in/required less work. It’s coming I know (see info in my table below), but there’s no harm in nudging people along the way ;)

My current wish list

Here’s an extract from a PowerPoint slide I recently to discuss my current list of “asks” to Microsoft:

SPFx and modern pages wishlist - June 2017

Let me expand on those in a bit more detail:

Thing

Status (June 2017)

Notes

Global deployment of SPFx web parts

  • Needed so that SPFx app does not need to be installed to each site
  • Ideally at different scopes e.g:
    • All sites of a certain type e.g. all group sites, all regular team sites etc.
    • Sites with X in property bag
    • All site collections except [list]
    • etc.

Partial solution “imminent” (weeks not months)

See slide at the end of this article. Initial solution will allow web parts to be available across sites, but without much control (e.g. my “scopes” examples).

Expand PnP schema to include provisioning modern pages and web parts

  • Needed to allow provisioning of team sites *with modern page as home page* – without code/PnP extensibility provider)

Expected in next release of PnP Core (August 2017 release). It’s in the XML schema already...

More web hooks

No news

I’d like to see web hooks for:

  • Site creation e.g. group sites
  • Subsite creation
  • List creation
  • Permission changes
  • Other changes

Remove restrictions on “no script” sites (esp. property bag)

  • Needed to bring more extensibility to Group sites (or other sites with “no script” enabled
  • Writing to property bag is common in many customization scenarios

Done!

It’s now possible to disable “no script” on modern team sites, including Group sites. The Customizing modern team sites page has been updated to reflect this (June 26 2017)

Missing controls and tagging support

  • Taxonomy control
  • Person/Group control
  • Calendar control (for non-Group sites)
  • Full Content Search web part (or similar)

No specific news

Modern pages in team sites are great for editing and display, but currently not so good when it comes to some types of content and tagging. Missing controls include the ones I’ve listed (difficult to have a “Page contact” or “Site owner” for example), but the tagging/metadata support is lacking too due to the (lack of) fields on the Site Page content type. Rolling up these pages with a filter is tricky in the current arrangement.

Pages

  • Multi-column support
  • Fix banner/header height

Coming “soon”

More known issues with flexibility of these pages – the single column aspect in particular. But, this is relatively low-hanging fruit for Microsoft and we can expect these resolved soon I think.

Expand SPFx extensions model (bonus item)

No specific news

Additional areas to target, not just “PageHeader” and “PageFooter”. The product group have said more areas are coming for modern pages in team sites (and presumably communication sites too).

    In terms of the first item, global deployment of SPFx web parts, Vesa recently used this slide to discuss what’s coming:

      SNAGHTML46ce695

      That sounds like a reasonable plan, since at least the long-term solution would give us full control. The short-term solution would clearly mean that all SPFx web parts are available everywhere (e.g. in my team sites, my intranet and my communication sites) which might not make sense, so hopefully the long-term arrangement isn’t too far away.

      Communication sites

      Communication sites are starting to launch and Microsoft’s “Ask Me Anything” session was yesterday (28 June 2017). I was disappointed not to hear any detail about templating of communication sites, so that would certainly be another wish list item. I know there are “new” templating options for those coming, but I still want the ability to use PnP site provisioning and XML too – after all, we still need the control and ability to specify all the aspects of a site template that PnP provides, so why use another approach? Also, having a mismatch between what I’m doing everywhere else and for comms sites would be sub-optimal too. Hopefully PnP provisioning will be possible there too – I really hope so!

      What else?

      I could certainly think of a few more items. But what did I miss that’s on your list at the moment?

      UPDATE 26 JULY 2017 – Wait, how did I miss the lack of API for Microsoft Teams? Again, I know it’s coming, but I’m really looking forward to the ability to create a template for a team with appropriate tabs and connectors, and the ability to create Teams programmatically (perhaps alongside an Office 365 Group/SharePoint site). Hopefully not too long to wait!

        Sunday, 11 June 2017

        Use an SPFx Application Customizer to add JavaScript (e.g. header) to every page in a site

        New tools for customizing modern SharePoint sites and pages in Office 365 have arrived (in preview at the time of writing, June 2017).  These are known as “SharePoint Framework (SPFx) extensions”, and replace some tools that SharePoint developers have long used to deliver key scenarios such as:

        • Adding JavaScript to every page in a site/web
        • Injecting some content (e.g. a mega-menu/global navigation or message bar) into every page
        • Popping up dialog boxes in an integrated way
        • Adding items into certain toolbars/menus in SharePoint
        • Changing the rendering/behavior of a specific field in a list

        In other words, SPFx extensions provide the equivalent of CustomActions and JSLink – previous dev approaches which didn’t necessarily translate to modern pages.

        In this article I want to focus on the first two scenarios listed above (in bold) – referencing some JS on every page, and also running some code to put something in the header area of the page. The documentation provided by Microsoft does a good job on the 2nd scenario, but sometimes it’s good to have something a bit more visual so I’ll provide more screenshots. I’ll also talk about the scenario where you don’t necessarily want to add some *content* to the page, but you do want to add *some other form of script* to run on every page (e.g. analytics/whatever).

        In terms of injecting content into the page, we now have the following zones in modern pages:

        • PageHeader
        • PageFooter
        • DialogContainer

        N.B. We can expect more zones in the future! Here’s what the header and footer look like:

        SNAGHTML4eec1a

        Key information

        Microsoft are currently saying that SPFx extensions will hit General Availability (i.e. fully-released in all tenants and suitable for production use) in fall/autumn of 2017. Until this time they are in preview.

        Also be aware that what makes the new extensions possible is Microsoft's updates to tenants (only in developer tenants at the time of writing, not even in First Release), and updates to the Yeoman Generator that developers use to get started - this has a new set of component types which get you started with the right default code.

        Previous limitations with modern pages

        Modern pages have been frustrating because:

        • No possibility to run custom script
          • Global JS added with previous methods (CustomAction + JSLink) did not run here – only on “classic” pages
        • Corresponding lack of page extensibility
          • No way to inject content into the page

        What’s changing here is that Microsoft are providing a hook to run your code, and are also providing named placeholders on modern pages – zones of the page which you can add content to. So long as you stick to these zones and don’t arbitrarily “hack” the page by changing other DOM elements (e.g. with jQuery or similar), then Microsoft effectively guarantee that updates to Office 365 will not impact your customizations.

        The script you provide has to be installed to an app catalog and deployed that way, meaning that there is effectively an approval step. This means that simply editing the page to add a Script Editor web part no longer exists as the easy option – the script must be OK’d by an administrator. Lots of debate on this one of course, but ultimately it’s what Microsoft need to do to facilitate more governance and safeguard Office 365 as a stable platform.

        Targeting placeholders such as the PageHeader and PageFooter zones

        The earlier image showed where the PageHeader and PageFooter zones are. As shown above, these zones are present on “system” pages such as a list/library page, but note that some modern pages such as a regular Site Page (in a standard site or a Group site) don’t get all placeholders. For example, there is no footer here:

        SNAGHTML4c4489

        SNAGHTML5197b2

        And there’s nothing to stop you making that header zone larger if you want to with CSS (this image is zoomed out):

        SNAGHTML2418631

        And of course, all this only applies to modern pages – classic pages do not have these zones or support SPFx extensions in general:

        SNAGHTML48946ed

        I’ll talk about the end-to-end process later, but to get straight to the code - with some minor tweaks/simplification to the suggested code in the documentation, mine looks like this:

        And the CSS is implemented by adding an SCSS file in your extension’s directory – mine is named AppCustomizer.module.scss and has the following content:

        Remember this is imported to the class for your customizer e.g:

        import styles from './AppCustomizer.module.scss';

        So, the key elements here are:

        • A class that derives from the ApplicationBaseCustomizer class
        • Use of the this.context.placeholders collection to get a reference to the appropriate placeholder - and the fact that it gives you the DOM element to manipulate (e.g. set innerHTML)

        In terms of what associates your customizer to the site, this is done declaratively in the app packaging – your customizer has a manifest file which contains it’s ID ([MyCustomizer].manifest.json), and on top of this you actually add an elements.xml file with a CustomAction element (just like the old days!). This has a new "’ClientSideComponentId” attribute, and this must point to the ID of your customizer. But before then, there’s a mode when you can dev/test your customizer before worrying about packaging. This works by running a “gulp serve” locally and adding some querystring parameters to a modern page so that the manifest is loaded from localhost – it’s a bit like the “local SPFx workbench” equivalent but for SPFx extensions/customizers.

        But I don’t need placeholders – I just want to reference some JavaScript on every page!

        In this case, the code is somewhat simpler. If you have an external JS file you want to reference in a quick and dirty way, you could do this by dynamically adding a script tag to the <head> element of the page. My testing shows it seems safe to do this in the onInit method, but the onRender method would be fine also – in any case, it’s just the old-fashioned method like this:

        But consider!

        • If the JS is hosted on another domain, you may need to enable CORS there (depending on what your JS is doing)
        • If you're referencing a module script, you could do this in a cleaner way by referencing it as an external module in the "externals" section of your config.json file (see Add an external library to your SharePoint client-side web part for more). I've tested and this approach does work with an Application Customizer
        • You could also choose to bundle your script if that made sense, and ensure it was referenced in the onRender method for your customizer. That should work too..

        Process

        The process is effectively the same whether you're targeting page placeholders or just referencing script on every page:

        Update the SPFx Yeoman Generator if needed

        The first step you might need to do is to update your SPFx Yeoman Generator – assuming you already have all the bits installed, you can do this by typing “yo” at the command-line and then going through the update process:

        SNAGHTML38f4e932

        Choose the “Update your generators” option and select “@microsoft/sharepoint”:

        SNAGHTML38f64e11

        SNAGHTML38f7128a

        Creating an Application Customizer extension

        [N.B. I’m essentially duplicating/walking through the main “Build your first extension” documentation here – you should reference that too.]

        Once you’re ready to actually create your app customizer, do this by running that generator:

        SNAGHTML3902e5e2

        Give your solution a name, and ensure you select the “Extension” option:

        SNAGHTML1dbcd6b

        In this case, we’re using Application Customizer (rather than ListView Command Set Customizer [CustomAction/toolbar replacement] or Field Customizer [JSLink/field replacement]):

        SNAGHTML1d772eb

        Provide a name for your customizer and then a description:

        SNAGHTML212d82d

        The generator will then get busy creating your application with the appropriate files, and then you’ll see:

        SNAGHTML2114dd4

        Your application has now been created and you’ll get the boilerplate code:

        SNAGHTML2152c30

        It’s a good idea to test running this in debug mode before making any code changes, so do this by running a gulp serve with the “nobrowser” switch:

        SNAGHTML216506c

        The next step is to browse to a modern page, but adding some querystring parameters in the URL so that our *local* manifest for the customizer is loaded. First, open a browser to a modern page – a document library is a good choice:

        SNAGHTML21b7c46

        And then in Notepad or similar, build the querystring parameters you need. This basic format of this is:

        ?loadSPFX=true&
        debugManifestsFile=https://localhost:4321/temp/manifests.js&
        customActions={"badba93c-7f98-4a68-b5ed-c87ea51a3145":{"location":"ClientSideExtension.ApplicationCustomizer","properties":{"testMessage":"Hello as property!"}}}
          

        However, you’ll need to replace the ID with the one from your customizer’s manifest file:

        SNAGHTML224e8a1

        SNAGHTML226aa94

        If you paste that onto the end of the URL to the document library in your browser window and hit enter, you should see a warning message related to debug mode:

        SNAGHTML228610e

        Click the “Load debug scripts” button, and then your code should execute and you should see the results – in the case of the boilerplate code, it’s an alert box:

        SNAGHTML22a488b

        Success! You’ve now run an Application Customizer in debug mode.

        Packaging for production

        For this, I recommend following the steps in the documentation (start at Deploy your extension to SharePoint) – but below is an extract of the main steps. Ultimately it revolves around:

        1. Building your app, and deploying the bundled JS files to somewhere like a CDN (just like an SPFx web part)
        2. Adding some packaging files to your app, so that your customizer is called when the app is added to a site (a bit like feature activation – in fact, it IS feature activation ;))
        3. Deploying the app package to an App Catalog, and then adding the app to a site

        In terms of the process, key steps are:

        • Create SharePoint/Assets folder and add an elements.xml file:

          SNAGHTML3954c9a1
        • Add the contents to elements.xml – set the “ClientSideComponentId” to identifier of your customizer i.e. the one found in the [MyCustomizer].manifest.json file:

          <?xml version="1.0" encoding="utf-8"?>
          <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
              <CustomAction
                  Title="COB Global JS"
                  Location="ClientSideExtension.ApplicationCustomizer"
                  ClientSideComponentId="5dba1a34-6bbe-42ef-be72-94e01b527ce2">
              </CustomAction>
          </Elements>
                

        • Edit the config\package-solution.json file – add a “Features” node to reference your elements.xml file. It needs contents similar to the following:

            "features": [{
                "title": "COB AppCustomizer - global JS",
                "description": "Adds some JavaScript to every page in the site",
                "id": "456da147-ced2-3036-b564-8dad5c1c2e34",
                "version": "1.0.0.0",
                "assets": {        
                  "elementManifests": [
                    "elements.xml"
                  ]
                }
              }]
        •    
        • Take care of some other steps related to CDN-hosting of your JS bundle (e.g. updating the ‘cdnBasePath’ property in the ‘write-manifests.json’ file), and then bundle and package your app using 'gulp bundle --ship' and 'gulp package-solution --ship' respectively.
        • As I say, head to the documentation for the full steps when you actually come to do this.

          The app is then upload to the app catalog:

          SNAGHTML2dc2e6a

          Notice that at this point, the admin needs to trust the application and will see where the remote files are hosted - in my case, I used the Office 365 public CDN:

          SNAGHTML9a5ac5

          You should then see your customizer take effect, and if you go looking you’ll see a web-scoped feauture (by default) which is binding your customizer to the site:

          SNAGHTML2cbe9ae

        Other matters

        • Feature scope – it should be possible to adjust the feature scope from the default of “web” to “site”. I haven’t tried this yet, but expect it to be in the “features” node of package-solution.json
        • Property bag – as shown in the “Build your first extension” page, there’s a property bag of sorts that can be used with customizers. In production mode, properties are specified in the CustomAction element in your elements.xml file. In my example, I chose to use values specified directly in the code, but this property bag provides some level of separation (but it is still burnt into your package)

        Happy customizing!