Making HTML table sortable in AngularJS

 

Problem

We were working on a project and have built its front-end on AngularJS v1.6.6 along with Office UI Fabric, we have used community-driven library ngofficeuifabric when we came across a situation of table sorting and realised that it wasn’t a great fit for our custom sorting and filtering requirements raised during future sprints by our product owners and business in general.

Solution

We have replaced ‘uif-table’ with ‘table’ and added custom events for sorting, the markup  is as follows:

<table class="table ms-Table">
    <thead>
        <tr>
            <th class="col-header col-header-5 pointer" ng-click="headerClick('item.ID', !sortAsc)">
                ID
                <span ng-show="sortField=='item.ID'">
                    <span ng-show="!sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretDown" aria-hidden="true"></i>
                    </span>
                    <span ng-show="sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretUp" aria-hidden="true"></i>
                    </span>
                </span>
            </th>
            <th class="col-header col-header-5 pointer" ng-click="headerClick('item.ObjectID', !sortAsc)">
                Object ID
                <span ng-show="sortField=='item.ObjectID'">
                    <span ng-show="!sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretDown" aria-hidden="true"></i>
                    </span>
                    <span ng-show="sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretUp" aria-hidden="true"></i>
                    </span>
                </span>
            </th>
            <th class="col-header col-header-5 pointer" ng-click="headerClick('item.DateSubmitted', !sortAsc)">
                Object Date Submitted
                <span ng-show="sortField=='item.DateSubmitted'">
                    <span ng-show="!sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretDown" aria-hidden="true"></i>
                    </span>
                    <span ng-show="sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretUp" aria-hidden="true"></i>
                    </span>
                </span>
            </th>
            <th class="col-header col-header-10 pointer" ng-click="headerClick('item.ObjectDate', !sortAsc)">
                Object Date
                <span ng-show="sortField=='item.ObjectDate'">
                    <span ng-show="!sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretDown" aria-hidden="true"></i>
                    </span>
                    <span ng-show="sortAsc">
                        &nbsp;
                        <i class="ms-Icon ms-Icon--caretUp" aria-hidden="true"></i>
                    </span>
                </span>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="item in items | orderBy:'item.ID':sortAsc" ng-click="rowClick(item.Id)">
            <td class="col-body"><a ng-href="{{item.Url}}" target="_self">{{item.ID}}</a></td>
            <td class="col-body">{{item.ObjectID}}</td>
            <td class="col-body">{{item.DateSubmitted | date:'dd MMM yyyy'}}</td>
            <td class="col-body">{{item.ObjectDate | date:'dd MMM yyyy'}}</td>
        </tr>
    </tbody>
</table>

You need to have two variables to store what ‘order’ is required (ascending/descending) and which ‘field’ (column) to sort records on, we have initialised these variables as follows:

//setting sorting variables for the first page load
$scope.sortAsc = false;
$scope.sortField = 'item.ID';

We have attached a function to table header to record a click on a specific column and get the column’s desired sorting order, this will just record at the start of the function to set the direction for sorting.

function headerClick(fieldName, sortType) {
	$scope.sortField = fieldName;
	$scope.sortAsc = sortType;

	var sortedItems = [];

	angular.forEach($scope.items, function (item) {
		sortedItems.push(item);
	});

	$scope.items = [];

	if (fieldName === "item.ObjectDate") {
		// sorting for custom date field as it can include text
		sortedItems.sort(function (a, b) {
			return compareObjectDate(a.Date, b.Date);
		});
	}
	else if (fieldName === "item.DateSubmitted") {
		// sorting for any date field
		sortedItems.sort(function (a, b) {
			return compareDate(a.DateSubmitted, b.DateSubmitted);
		});
	}
	else {
		// sorting for any text field
		sortedItems.sort(function (a, b) {
			return a.fieldName.localeCompare(b.fieldName);
		});
	}

	//check what type of sorting (ascending/descending) is required and then do the needful
	if ($scope.sortAsc) { // ASC
		$scope.items = sortedItems;
	}
	else { // DSC
		$scope.items = sortedItems.reverse();
	}
}

Here is a sample function to sort based on date field. You can create your own sorting function for each column type following the simple logic:

  • if two values are equal, a function should return “0”
  • if the first value is lesser than 2nd value, a function should return “-1”
  • if the first value is greater than 2nd value, a function should return “1”
function compareDate(date1,date2) {
	var dateFirst = new Date(date1);
	var dateSecond = new Date(date2);

	if (dateFirst === dateSecond) {
		return 0;
	}
	else if (dateFirst < dateSecond) {
		return -1;
	}
	else {
		return 1;
	}
}

Pictures below will show custom sorting on the column Object Date as it has got a combination dates and text and client wanted to sort it in a specified order.

Ascending order (custom field)

032018_1123_Creatingsor2.png

Descending order (custom field)

032018_1123_Creatingsor1.png

Another view of looking at the same table but sorting on the column ‘Object Date submitted’ as it contains only dates.

Ascending order (date field)

Capture1

Descending order (date field)

Capture

It’s an easy way to use plain Angular and HTML to order/sort your table as per the needs. This can be enhanced further to cater specific needs or use 3rd party library to deliver rich functionality.

Intro to Site Scripts and Site Designs with a Simple SharePoint Modern Site provisioning

Microsoft announced Site Scripts and Site Designs in late 2017 which became available for Targeted release in Jan 2018, and released to general use recently. It is a quick way to allow users to create custom modern sites, without using any scripting hacks. Hence, in this blog we will go through the steps of Site Scripts and Site design for a Simple SharePoint Modern Site Creation.

Before we get into detailed steps, lets’ get a brief overview about Site Designs and Site Scripts.

Site designs: Site designs are like a template. They can be used each time a new site is created to apply a consistent set of actions. You create site designs and register them in SharePoint to one of the modern template sites: the team site, or communication site. A site design can run multiple scripts. The script IDs are passed in an array, and they will run in the order listed.

Site Scripts: Site script is custom JSON based script that runs when a site design is selected. The site scripts detail the provisioning items such as creating new lists or applying a theme. When the actions in the scripts are completed, SharePoint displays detailed results of those actions in a progress pane. They can even call flow trigger that is essential for site creation.

Software Prerequisites:

  1. PowerShell 3.0 or above
  2. SharePoint Online Management Shell
  3. Notepad or any notes editor for JSON creation – I prefer Notepad++
  4. Windows System to run PowerShell
  5. And a must – SharePoint Tenant J

 Provisioning Process Overview:

The Provisioning process is divided into 4 steps

1. Create a Site Script using JSON template to call actions to be run after a Modern Site is created.
2. Add the Script to your tenant
3. Create a Site Design and add the Site Script to the design. Associate the Site Design to Modern Site Templates – Team Site template is 64 and Communication Site Template is 68
4. Create a Modern Site from SharePoint landing page
5. Wait for the Site Script to apply changes and refresh your site

Quick and Easy right!? Now lets’ get to the “how to”.

Steps

1. JSON Template: We will need to create a JSON template that will have the declarations of site resources that will be provisioned after the site is created. For more details, here is a link to Microsoft docs. The brief schema is below.

{
"$schema": "schema.json",
"actions": [
... [one or more verb   actions]  ...
],
"bindata": { },
"version": 1
};

For our blog here, we will use the below schema where we are creating a custom list with few columns.

2. Site Script: Add the above site script to your tenant using PowerShell. The below code with return the Site Script GUID. Copy that GUID and will be used later

Get-Content '[ JSON Script location ]' -Raw | Add-SPOSiteScript -Title “[ Title of the script ]

3. Site Design: After the Site Script is added, create the Site Design from the Site Script to be added to the dropdown menu options for creating the site.

Add-SPOSiteDesign -Title “[ Site design title ]” -WebTemplate "64"  -SiteScripts “[ script GUID from above step ]”  -Description "[ Description ]"

4. Create a Modern Site: After the Site Design is registered, you could see the design while creating a site as shown below

ModernTeamSiteWIthcustom

5. Click on the Manual Refresh button as per screenshot after the site upgrade process is complete.

SiteScriptFinish

When ready, the final Team site will look like the screenshot below after provisioning is complete.

CustomTeamSiteWithScriptResult

In this blog, we came to know about Site Script, Site design and how to use them to provision modern team sites.

Writing for the Web – that includes your company intranet!

You can have a pool made out of gold – if the water in it is as dirty and old as a swamp- no one will swim in it!

The same can be said about the content of an intranet. You can have the best design, the best developers and the most carefully planned out navigation and taxonomy but if the content and documents are outdated and hard to read, staff will lose confidence in its authority and relevance and start to look elsewhere – or use it as an excuse to get a coffee.

The content of an intranet is usually left to a representative from each department (if you’re lucky!) Usually people that have been working in a company for years. Or worse yet, to the IT guy. They are going to use very different language to a new starter, or to a book keeper, or the CEO. Often content is written for an intranet “because it has to be there” or to “cover ourselves” or because “the big boss said so” with no real thought into how easy it is to read or who will be reading it.

adaptive

Content on the internet has changed and adapted to meet a need that a user has and to find it as quickly as possible. Why isn’t the same attitude used for your company? If your workers weren’t so frustrated finding the information they need to do their job, maybe they’d perform better, maybe that would result in faster sales, maybe investing in the products your staff use is just as important as the products your consumers use.

I’m not saying that you have to employ a copywriter for your intranet but at least train the staff you nominate to be custodians of your land (your intranet- your baby).

Below are some tips for your nominated content authors.

The way people read has changed

People read differently thanks to the web. They don’t read. They skim.

  • They don’t like to feel passive
  • They’re reluctant to invest too much time at one site or your intranet
  • They don’t want to work for the information

People DON’T READ MORE because

  • What they find isn’t relevant to what they need or want.
  • They’re trying to answer a question and they only want the answer.
  • They’re trying to do a task and they only want what’s necessary.

Before you write, identify your audience

People come to an intranet page with a specific task in mind. When developing your pages content, keep your users’ tasks in mind and write to ensure you are helping them accomplish those tasks.  If your page doesn’t help them complete that task, they’ll leave (or call your department!)

Ask these questions

  • Who are they? New starters? Experienced staff? Both? What is the lowest common denominator?
  • Where are they? At work? At home? On the train? (Desktop, mobile, laptop, ipad)
  • What do they want?
  • How educated are they? Are they familiar with business Jargon?

Identify the purpose of your text

As an intranet, the main purpose is to inform and educate. Not so much to entertain or sell.

When writing to present information ensure:

  • Consistency
  • Objectivity
  • Consider tables, diagrams or graphs

Structuring your content

Headings and Sub headings

Use headings and sub headings for each new topic. This provides context and informs readers about what is to come. It provides a bridge between chunks of content.

Sentences and Paragraphs

Use short sentences. And use only 1-3 sentences per paragraph.

‘Front Load’ your sentences. Position key information at the front of sentences and paragraphs.

Chunk your text. Break blocks of text into smaller chunks. Each chunk should address a single concept. Chunks should be self-contained and context-independent.

Layering vs scrolling

It is OK if a page scrolls. It just depends how you break up your page! Users’ habits have changed in the past 10 years due to mobile devices, scrolling is not a dirty word, as long as the user knows there’s more content on the page by using visual cues.

phone.png

Use lists to improve comprehension and retention

  • Bullets for list items that have no logical order
  • Numbered lists for items that have a logical sequence
  • Avoid the lonely bullet point
  • Avoid death by bullet point

General Writing tips

  • Write in plain English
  • Use personal pronouns. Don’t say “Company XYZ prefers you do this” Say “We prefer this”
  • Make your point quickly
  • Reduce print copy – aim for 50% less copy than what you’d write for print
  • Be objective and don’t exaggerate
  • USE WHITE SPACE – this makes content easier to scan, and it is more obvious to the eye that content is broken up into chunks.
  • Avoid jargon
  • Don’t use inflated language

Hyperlinks

  • Avoid explicit link expressions (eg. Click here)
  • Describe the information readers will find when they follow the link
  • Use VERBS (doing word) as links.
  • Warn users of a large file size before they start downloading
  • Use links to remove secondary information from the bulk of the text (layer the content)

Remove

  • Empty words and phrases
  • Long words or phrases that could be shorter
  • Unnecessary jargon and acronyms
  • Repetitive words or phrases
  • Adverbs (e.g., quite, really, basically, generally, etc.)

Avoid Fluff

  • Don’t pad write with unnecessary sentences
  • Stick to the facts
  • Use objective language
  • Avoid adjectives, adverbs, buzzwords and unsubstantiated claims

Tips for proofreading

  1. Give it a rest
  2. Look for one type of problem at a time
  3. Double-check facts, figures, dates, addresses, and proper names
  4. Review a hard copy
  5. Read your text aloud
  6. Use a spellchecker
  7. Trust your dictionary
  8. Read your text backwards
  9. Create your own proofreading checklist
  10. Ask for help!

A Useful App

Hemingwayapp.com assesses how good your content is for the web.

A few examples (from a travel page)

Bad Example

Our Approved an​​​d Preferred Providers

Company XYZ has contracted arrangements with a number of providers for travel.  These arrangements have been established on the basis of extracting best value by aggregating spend across all of Company XYZ.

Why it’s Bad

Use personal pronouns such as we and you, so the user knows you are talking to them. They know where they work. Remove Fluff.

Better Example

Our Approved an​​​d Preferred Providers

We have contracted arrangements with a number of providers for travel to provide best value

Bad Example

Travel consultant:  XYZ Travel Solutions is the approved provider of travel consultant services and must be used to make all business travel bookings.  All airfare, hotel and car rental bookings must be made through FCM Travel Solutions

Why it’s bad

The author is saying the same thing twice in two different ways. This can easily be said in one sentence.

Better Example

Travel consultant

XYZ Travel Solutions must be used to make all airfare, hotel and car rental bookings.

Bad Example

Qantas is Company XYZ preferred airline for both domestic and international air travel and must be used where it services the route and the “lowest logical fare” differential to another airline is less than $50 for domestic travel and less than $400 for international travel

Why it’s bad

This sentence is too long. This is a case of using too much jargon. What does lowest logical fare even mean? And the second part does not make any sense. What exactly are they trying to say here? I am not entirely sure, but if my guess is correct it should read something like below.

Better Example

Qantas is our preferred airline for both domestic and international air travel. When flying, choose the cheapest rate available within reason. You can only choose another airline if it is cheaper by $50 for domestic and cheaper by $400 for international travel.

Bad Example

Ground transportation:  Company XYZ preferred provider for rental vehicle services is Avis.  Please refer to the list of approved rental vehicle types in the “Relevant Documents” link to the right hand side of this page.

Why it’s bad

Front load your sentences. With the most important information first. Don’t make a user dig for a document, have the relevant document right there. Link the Verb. Don’t say CLICK HERE!

Better Example

Ground transportation

Avis is our preferred provider to rent vehicles.

View our list of approved rental vehicles.

Bad Example

Booking lead times:  To ensure that the best airfare and hotel rate can be obtained, domestic travel bookings should be made between 14-21 days prior to travel, and international travel bookings between 21 and 42 days prior to travel.  For international bookings, also consider lead times for any visas that may need to be obtained.

Why it’s bad

Front load your sentence… most important information first. This is a good opportunity to chunk your text.

Better Example

Booking lead times

Ensure your book your travel early

14-21 day prior to travel for domestic

21-42 days prior to travel for internatonal (also consider lead times for visas)

This will ensure that the best airfare and hotel rate can be obtained.

 

Xamarin Application Architecture

In this post, I will talk about strategies for developing a cross-platform Xamarin application with focus on code sharing, increasing testability, and reducing overall development and maintenance efforts.

The application architecture is itself problem specific, but there are certain design patterns that can guide the overall structure of the application. The ones I mostly work with are Model-View-Controller, Model-View-Presenter, and Model-View-ViewModel.

MVC should be adopted for small applications or proof of concept. Since, Android and iOS both natively support MVC, it will mean less roadblocks, and faster implementation.

MVVM reduces platform specific code, and most of the logic is shared across platforms using PCLs. There are great MVVM frameworks out there that work really well with Xamarin, such as MVVM Cross, and the official Xamarin Forms.

MVVM Cross is a data driven pattern, and the presentation logic is quiet centralised. This means any upgrades to the library or to the system, can break custom navigation and screen transitions within the application. As Android and iOS platforms are constantly upgraded, with newer restrictions around security and permissions (background tasks / app permissions), and as user interface (gestures / notifications / newer design guidelines) are greatly improved, support for these can be costly in both time and effort. That being said, it is still a very powerful platform, and most applications can be written with it, with great results.

Xamarin.Forms is a UI first framework, and allows .Net developers to use their existing XAML skills for developing mobile applications. However, this platform is still maturing and needs to reach a more stable stage. Even though native controls can now be used in XAML, but one looses advantage of data binding, and the extra effort required to maintain proper navigation in the application, and catering for various screen types, out does the benefit for now.

MVP is another pattern that works really well with Xamarin cross-platform applications. It is a variant of the MVC pattern and allows full use of platform native capabilities, with great control over the UI of the application. It is the pattern of choice for native development and we will look more into it below.

MVP has 3 major components

Model: This is data that we want to show in our views. Apart from data classes, this carries responsibility for retrieving, storing, validating advanced data sets, and advanced functions such as syncing and conflict resolution, cache maintenance, offline capabilities.

View: This module is responsible for showing data to user and responding to user gestures and actions. It should only be dependent upon the presenter and native platform capabilities for styling.

Presenter: Presenter is the layer below the view and is responsible for providing data the view can use. It relies on the model layer to retrieve data, and can also publish other events to UI, such as loading data state, timeout and error state.

The golden rule of mobile development is to keep the UI layer as dumb as possible. That means UI only needs to know about its data, view transitions and animations, and publishing interaction events, such as gestures, button clicks. As mentioned view is completely dependent upon presenter, and presenter is dependent upon the view for human interaction. However, to promote unit testing for each of the modules, presenter and view need to be decoupled.

To achieve this, we can define a contract between presenter and the view. For a login screen the view’s contract can be:

and the presenter contract can be

The presenter should be platform independent so that it can be shared across different mobile platforms. This means, it does not respond to UI life-cycle methods, unless explicitly told so.

The controllers in iOS and Activities in Android are never directly created using constructor, which means that we cannot use dependency injection to provide a presenter to our view. In this scenario I like to use an anti-pattern called ‘Service Locator’.

Service locator is considered anti-pattern because of the complexities of managing dependencies, and dependency’s child dependencies. This is highly error prone, but in case of multi-threaded programs, where start of the application can run many different initialisation threads, double instance of a service can be created. This pattern works well in simple scenarios and this is exactly what we are trying to solve. A dependency service can be used to locate the presenter implementation inside the view.

If the scenario was anymore complex, it certainly means, that View has been assigned more work than it needs to perform and is against MVP principles. A sample of this is shown below

As shown above the AppDelegate in the application loads all the presenters in the application. When the view loads, it uses the service locator instance to retrieve its presenter.

By abstracting the presenter from the view gives us many advantages.

  • One presenter will not work on all devices. Such as finger print functionality for login can only be used on devices that have the required hardware. In this case inheritance can be used to create versions that can handle extra features, while having no functionality in base presenters.
  • By abstracting the creation of the presenter outside the view, allows to make our UI really passive, and thus we are able to test UI independent of any other module.
  • This method allows to create presenters that can help automate UI testing, performing common testing scenarios automatically. This can also be used for automatic product demos.

 

The above implementation of MVP suffers from one disadvantage. It ignores the asynchronous nature of the mobile applications. Both Android and iOS are quite capable devices. Even a simple Notes application performs a lot of activities when loading. These can be logging in the user, loading the notes from the cache, syncing down any notes created on other device, syncing up any notes created during offline mode, resolving conflicts, showing progress to the user, restoring state to what it was when the application was last closed. These activities can take from few milliseconds to few seconds. The longer the application takes to boot up, the higher the chance that the user will stop using the application, and will eventually remove it from the device.

Enterprise applications are much more complex. In a perfect world, they are developed using mobile-first approach. However, not all companies can follow this and instead of the application interacting with a unified set of APIs, it ends up interacting with multiple legacy systems, combine the result and then provide it to the UI layer. This means that the application load time can be really high especially if there is stale data on the device.

In such a scenario, instead of defining contracts between the presenter and view, a more reactive approach can be used. This allows us to build application with a user centric approach. This means we think of how the user is going to interact with application, and what does the user see while waiting for data to be available in the application. The code below shows this for a login screen.

The above code shows the asynchronous nature of the View, and it follows a push approach, reacting to events when raised by the presenter. This further decouple the bond between the view and the presenter allowing for easier testing, and also helps to identify real life scenarios within the app, such as data being delayed or no connectivity.

Thus, we see how MVP aims at building a very user centric app, with a very passive and light UI layer. Both iOS and Android platforms are competing to enhance user experience. In future, we can see apps that will react and adapt to user habits using machine learning. This also means that they will have to work in a stricter environment, like stricter guidelines for UI, background tasks, app permissions, reduced background tasks, and change in application notification patterns. MVP will definitely allow to handle these changes, without affecting user experience.

Global Navigation and Branding for Modern Site using SharePoint Framework Extensions

Last month at the Microsoft Ignite 2017, SharePoint Framework Extensions became GA. It gave us whole new capabilities how we can customize Modern Team sites and Communication sites.

Even though there are lots of PnP examples on SPFx extensions, while presenting at Office 365 Bootcamp, Melbourne and taking hands-on lab, I realised not many people are aware about the new capabilities that SPFx extensions provide. One of the burning question we often get from clients, if we can have custom header, footer and global navigation in the modern sites and the answer is YES. Here is an example where Global Navigation has been derived from Managed Metadata:

Communication Site with header and footer:

Modern Team Site with header and footer (same navigation):

With the latest Yeoman SharePoint generator, along with the SPFx Web Part now we have options to create extensions:

To create header and footer for the modern site, we need to select the Application Customizer extension.

After the solution has been created, one noticeable difference is TenantGlobalNavBarApplicationCustomizer is extending from BaseApplicationCustomizer and not BaseClientSideWebPart.

export default class TenantGlobalNavBarApplicationCustomizer
extends BaseApplicationCustomizer

Basic Header and Footer

Now to create a very basic Application Customizer with header/footer, make sure to import the React, ReactDom, PlaceholderContent and PlaceholderName:

import * as ReactDom from 'react-dom';
import * as React from 'react';
import {
  BaseApplicationCustomizer,
  PlaceholderContent,
  PlaceholderName
} from '@microsoft/sp-application-base';

In the onInit() function, the top(header) and the bottom (footer) placeholders need to be created:

const topPlaceholder =  this.context.placeholderProvider.tryCreateContent(PlaceholderName.Top);
const bottomPlaceholder =  this.context.placeholderProvider.tryCreateContent(PlaceholderName.Bottom);

Create the appropriate elements for the header and footer:

const topElement =  React.createElement('h1', {}, 'This is Header');
const bottomElement =   React.createElement('h1', {}, 'This is Footer');

Those elements can be render within placeholder domElement:

ReactDom.render(topElement, topPlaceholder.domElement);
ReactDom.render(bottomElement, bottomPlaceholder.domElement);

If you now run the solution:

  • gulp serve –nobrowser
  • Copy the id from src\extensions\.manifest.json file e.g. “7650cbbb-688f-4c62-b5e3-5b3781413223”
  • Open a modern site and append the following URL (change the id as per your solution):
    ?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={“7650cbbb-688f-4c62-b5e3-5b3781413223”:{“location”:”ClientSideExtension.ApplicationCustomizer”}}

The above 6 lines code will give the following outcome:

Managed Metadata Navigation

Now back to the first example. That solution has been copied from SPFx Sample and has been updated.

To get the above header and footer:

Go to command line and run

  • npm i
  • gulp serve –nobrowser
  • To see the code running, go to the SharePoint Online Modern site and append the following with the site URL:

    ?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={“b1efedb9-b371-4f5c-a90f-3742d1842cf3”:{“location”:”ClientSideExtension.ApplicationCustomizer”,”properties”:{“TopMenuTermSet”:”TopNav”,”BottomMenuTermSet”:”Footer”}}}

Deployment

Create an Office 365 CDN

Update config\write-manifests.json file “cdnBasePath” to the new location. E.g.

"cdnBasePath":"https://publiccdn.sharepointonline.com/<YourTenantName>.sharepoint.com//<YourSiteName>//<YourLibName>/<FoldeNameifAny>"

In the command line, run

  • gulp bundle –ship
  • gulp package-solution –ship

and upload all artefacts from \temp\deploy\ to the CDN location

Upload \sharepoint\solution.sppkg to the App Library

Go to the Modern Site > Site Content > New > App > select and add the app:

Hopefully this post has given an overview how to implement SPFx Application Customizers. There are many samples available in the GitHub SharePoint.

7 tips for making UX work in Agile teams

Agile is here to stay. Corporates love it, start-ups embrace it and developers live by it. So there is no denying that Agile is going nowhere and we have to work with it. For a number of years, I’ve tried to align User Experience practices with Agile methods and haven’t met with great success every time.

But nevertheless, there are a lot of lessons that I’ve learnt during the process and I’m going to share 7 tips that always worked for me.

agile-and-ux

Create a shared vision early on

Get all the decision makers (Dev leads, Project managers and Project sponsors) in one room. Get a whiteboard and discuss why are we developing this product? What problems are we trying to solve? Once you have an overall theme, ask more specific questions such as how many app downloads are we targeting in the first week?

This workshop will give you a snapshot of a shared vision and common goals of the organisation. During every checkpoint of this project, this shared vision will serve as a guide, helping teams prioritise user stories and make the right trade-offs along the way.

Engage stakeholders wherever possible

Regardless of how many people in your team are in agreement, most of the times the decision makers are the Project Sponsors or Division Managers. You do not want them to appear randomly during sprint 3 planning and poop on it.

I highly recommend cultivating strong relationships with these stakeholders early on in the project. Invite them to all UX workshops, and if they can’t/don’t attend, find a way to communicate the summary of the meeting in an engaging way (not an email with a PDF attachment). I use to put together a Keynote slide and have it ready on my iPad for a quick 5-minute summary.

Work at least one sprint ahead of the Dev team

The chances of getting everything from research, wireframes, designs and development done for a single card – in one sprint is implausible.

You’ll struggle to get everything going at the same time. When you are designing, the developers are counting sheep because they are waiting on you to give them something to work with. You don’t want to be the reason behind the declining burn chart. Always be at least one sprint (if not two sprints) ahead of the development team. Sometimes it takes longer to research and validate design decisions, but if you are a sprint ahead – you are not holding up the developers, and you have ample time to respond to design challenges.

Foster a collaborative culture

Needless to say – Collaborate as much as you can. Try to get the team involved (just the people sitting around you is fine) for even small things such a changing a button’s colour. It makes them feel important; makes them feel good and fosters a culture of collaboration.

If you don’t collaborate with the team on small (or big) things, don’t expect them to tell you everything either. Your opinion might not be very valuable in most of the Dev discussions such whether to use ReactJS or Angular, but knowing that the Devs are going to use a certain JS Library – will definitely help you in (one or the other way) planning future sprints.

Follow an Iterative Design Process

DO NOT design mock-ups, to begin with. I know all the customers want to see something real that they can sell to their bosses. But the pretty design approach falls on its face every time. I want my customers to detach themselves from aesthetics and focus on structure and interaction first. Once we have worked out the hardware, then we can look at building the software.

Try Iterative Design Process. Sketch on the whiteboard, get the stakeholders to put a vision on paper and come up with a structure first. Then iterate. Here is my design process:

  1. Paper sketches
  2. Low fidelity wireframes (on white board / PC)
  3. Interactive wireframes – B/W (on PC)
  4. Draft Designs – in Colour
  5. Final Designs
  6. Pass onto the build team.

Do a round of user testing with at least 5 people

User testing is not expensive, it does not take days or weeks, and you don’t have to talk to 25 people.

There is a lot of research on how testing only 5 users is highly effective and valuable to product development. Pick users from different demographic, put an interactive wireframe together and run it past them for about 30 – 45 minutes. After 3 users, you’ll start noticing common themes appearing. And after 5, you’ll have enough pointers to take back to the team for another round of iteration. Repeat this process every two to four sprints.

Hold a brief stand-up meeting every day

Hold a stand-up meeting first thing in the morning. The aim is to keep everyone updated on progress, recognise blockers and pick-up new cards.  This ensures all the team members are on the same page and are working towards a common goal.

However, be mindful of the time since some discussions are lengthier and may need to be taken offline. We generally time-box stand-ups for 15 minutes.

ADFS v 2.0 Migration to ADFS 2016

Introduction

Some organisations may still have ADFS v2 or ADFS v2.1 running in their environment, and haven’t yet moved to ADFS v3. In this blog, we will discuss how can you move away from ADFS v2 or ADFS v2.1 and migrate or upgrade to ADFS 2016.

In previous posts, Part 1 and Part 2 we have covered the migration of ADFS v3.0 to ADFS 2016. I have received some messages on LinkedIn to cover the migration process from ADFS v2 to ADFS 2016 as there currently isn’t much information about this.

As you may have noticed from the previous posts, upgrading to ADFS 2016 couldn’t be any easier. In ADFS v2 however, the process is as simple, albeit differently than upgrading from ADFS v2 or ADFS v2.1 to ADFS v3.

Migration Process

Before we begin however, this post assumes you already have a running ADFS v2 or ADFS v2.1 environment. This blog post will not go into a step-by-step installation of ADFSv2/ADFSv2.1, and will only cover the migration or upgrade to ADFS 2016.

This blog post assumes you already have a running Windows Server 2016 with the ADFS 2016 role installed, if not, please follow the procedures outlined in part 2.

Prerequisites

Prior to commencing the upgrade, there are few tasks you need to perform.

  1. Take a note of your ADFS Server Display Name
  2. Take a note of your Federation Service Name
  3. Take note of your federation Service Identifier
  4. Export the service communication certificate (if you don’t already have a copy of it)
  5. Install/Import the service communication certificate onto ADFS 2016 server

Notes:

  • There is no need to make your ADFS 2016 server as primary, since this should have been a new installation. You can’t add to an ADFS v2/ADFS v2.1 farm anyway.
  • There is no need to raise the farm behavior level, since this is not a farm member like we did when migrating from ADFS v3 to ADFS 2016.
  • However, you will still need to upgrade the schema as outlined in part 2.

Before you begin, you will need to download the following PowerShell script found here.

Those scripts can also be found in the support\adfs location in the Windows Server 2016 installation file. Those scripts are provided by Microsoft and not Kloud.

The two main functions, are the export and import federation configuration.

Let’s begin

Firstly, we will need to export the federation configuration by running the “export-federationconfiguration.ps1”.

Here are the current relying party trust I have in the ADFS v2.1.

The “Claims Provider Trust” is Active Directory, this toll will be exported and imported.

1

1- Navigate to the folder you have just downloaded:

Then, type

.\export-federationconfiguration.ps1 -path "c:\users\username\desktop\exported adfs configuration"

 

 

 

3

Once successful, you will see the same results in the above picture.

Open your folder, and you should see the extracted configuration in .xml files.

4

2- Head over your ADFS 2016 Server and copy/paste both the folder in which you have extracted your federation configuration, and the one you downloaded that includes the scripts.

Then open PowerShell and run:

.\import-federationconfiguration.ps1 -path "c:\users\username\desktop\exported adfs configuration"

 

6

When successful, you will see a similar message as above.

And now when you open the ADFS management you should see the same relying party trust as you had in ADFS v2/ADFS v2.1.

7

Basically, by now you have completed the move from ADFSv2/ADFSv2.1 to ADFS 2016.

Notice how the token-signing and token-decrypting certificates are the same. The screenshots below are only of the token-signing certificates only, for the purpose of this blog.

ADFS v2.1:

8

ADFS 2016:

9

You can also check the certificates through PowerShell:

Get-AdfsCertificate

Last thing, make sure that service account that was running the Active Direction Federation Services in ADFS v2/ADFS v2.1 is the same one running in ADFS 2016.

Notice the message in the exported results:

Ensure that the destination farm has the farm name ‘adfs.iknowtech.com.au’ and uses service account ‘IKNOWTECH\svc-adfs’.

If this is not setup, then head over your services and select the account that you were originally using to run the ADFS service.

In addition, make sure that the service account has read-only access to the certificate private key.

10

Conclusion

This is a very straight forward process, all that you need to be sure of is to have the right components in place, service certificate installed, service account setup, etc.

After you have complete the steps, follow the steps here to configure your Web Application Proxy. Although this covers a migration, but it also helps you in configuring a new deployment.

I hope you’ve found this informative. Should you have any question or feedback please leave a comment below.

 

WAP (2012 R2) Migration to WAP (2016)

In Part 1, and Part 2 of this series we have covered the migration from ADFS v3 to ADFS 2016. In part 3 we have discussed the integration of Azure MFA with ADFS 2016, and in this post (technically part 4) we will cover the migration or better yet upgrade WAP 2012 R2 to WAP 2016.

Again, this blog assumes you already have installed the Web Application Proxy feature while adding the Remote Access role. And have prepared the WAP server to be able to establish a trust with the Federation Service.

In addition, a friendly reminder once again that the domain name and federation service name have changed from swayit.com.au to iknowtech.com.au. The certificate of swayit.com.au expired before completing the lab, hence the change.

Before we begin however, the current WAP servers (WAP01, WAP02) are the only connected servers that are part of the cluster:

1

To install the WebApplicationProxy, run the following cmdlet in PowerShell:

Install-WindowsFeature Web-Application-Proxy -IncludeManagementTools

Once installed, follow these steps:

Step 1: Specify the federation service name, and provide the local Administrator account for your ADFS server.

2

Step2: Select your certificate

3

Step 3: Confirm the Configuration4

Do this for both the WAP servers you’re adding to the cluster.

Alternatively, you could do so via PowerShell:


$credential = Get-Credential
Install-WebApplicationProxy -FederationServiceName "sts.swayit.com.au" -FederationServiceTrustCredential $credential -CertificateThumbprint "071E6FD450A9D10FEB42C77F75AC3FD16F4ADD5F" 

Once complete, the WAP servers will be added to the cluster.

Run the following cmdlet to get the WebApplication Configuration:

Get-WebApplicationProxyConfiguration

You will notice that we now have all four WAP servers in the ConnectedServersName and are part of the cluster.

You will also notice that the ConfigurationVersion is Windows Server 2012 R2. Which we will need to upgrade to Windows Server 2016.

5

Head back to the one of the previous WAP servers running in Windows Server 2012 R2, and run the following cmdlet to remove the old servers from the cluster, and keep only the WAP 2016 Servers:

 Set-WebApplicationProxyConfiguration -ConnectedServersName WAP03, WAP04 

Once complete, check the WebApplicationProxyConfiguration by running the Get-WebApplicationProxyConfiguration cmdlet.

Notice the change in the ConnectServersName (this information is obtained from WAP Server 2012 R2).

6

If you run the Get-WebApplicationProxyConfiguration from WAP 2016, you will get a more detailed information.

6-1

The last remaining step before publishing a Web Application (in my case) was to upgrade the ConfigurationVersion, as it was still in Windows Server 2012 R2 mode.

If you already have published Web Application, you can do this any time.

Set-WebApplicationProxyConfiguration -UpgradeConfigurationVersion

When successful, check again your WebApplicationProxyConfiguration by running

Get-WebApplicationProxyConfiguration

Notice the ConfigurationVersion:

8

You have now completed the upgrade and migration of your Web Application Proxy servers.

If this is a new deployment, of course you don’t need to go through this whole process. You WAP 2016 servers would already be in a Windows Server 2016 ConfigurationVersion.

Assuming this was a new deployment or if you simply need to publish a new Web Application, continue reading and follow the steps below.

Publishing a Web Application

There’s nothing new or different in publishing a Web Application in WAP 2016. It’s pretty similar to WAP 2012 R2. The only addition Microsoft added, is a redirection from HTTP to HTTPS.

Steps 1: Publishing a New Web Application

9

Step 2: Once complete, it will appear on the published Web Applications. Also notice that we only have WAP03, and WAP04 as the only WAP servers in the cluster as we have previously remove WAP01 and WAP02 running Windows Server 2012 R2.

7

There you have it, you have now upgraded your WAP servers that were previously running WAP 2012 R2 to WAP 2016.

By now, you have completed migrating from ADFS v3 to ADFS 2016, integrated Azure MFA with ADFS 2016, and upgraded WAP 2012 R2 to WAP 2016. No additional configuration is required, we have reached the end of our series, and this concludes the migration and upgrade of your SSO environment.

I hope you’ve enjoyed those posts and found them helpful. For any feedback or questions, please leave a comment below.

ADFS v 3.0 (2012 R2) Migration to ADFS 4.0 (2016) – Part 3 – Azure MFA Integration

In Part 1 and Part 2 of this series we have covered the migration from ADFS v3 to ADFS 2016. In this series we will continue our venture in configuring Azure MFA in ADFS 2016.

Azure MFA – What is it about?

It is a bit confusing when we mention that we need to enable Azure MFA on ADFS. Technically, this method is actually integrating Azure MFA with ADFS. MFA itself is authenticating on Azure AD, however, ADFS is prompting you enter an MFA code which will be verified with the Azure AD to sign you in.

In theory, this by itself is not a multi-factor authentication. When users choose to login with a multi-factor authentication on ADFS, they’re not prompted to enter a password, they simply will login with the six digit code they receive on their mobile devices.

Is this secure enough? Arguably. Of course users had to previously set up their MFA to be able to login by choosing this method, but if someone has control or possession of your device they could simply login with the six digit code. Assuming the device is not locked, or MFA is setup to receive calls or messages (on some phones message notifications will appear on the main display), almost anyone could login.

Technically, this is how Azure MFA will look once integrated with the ADFS server. I will outline the process below, and show you how we got this far.

7

Once you select Azure Multi-Factor Authentication you will be redirected to another page

8

And when you click on “Sign In” you will simply sign in to the Office or Azure Portal, without any other prompt.

The whole idea here is not much about security as much as it is about simplicity.

Integrating Azure MFA on ADFS 2016

Important note before you begin: Before integrating Azure MFA on ADFS 2016, please be aware that users should already have setup MFA using the Microsoft Authenticator mobile app. Or they can do it while first signing in, after being redirected to the ADFS page. The aim of this post is to use the six digit code generated by the mobile app.

If users have MFA setup to receive calls or texts, the configuration in this blog (making Azure MFA as primary) will not support that. To continue using SMS or a call, whilst using Azure MFA, the “Azure MFA” need to be configured as a secondary authentication method, under “Multi-Factor”, and “Azure MFA” under “Primary” should be disabled.

Integrating Azure MFA on ADFS 2016, couldn’t be any easier. All that is required, is running few PowerShell cmdlets and enabling the authentication method.

Before we do so however, let’s have a look at our current authentication methods.

0

As you have noticed, that we couldn’t enable Azure MFA without first configuring Azure AD Tenant.

The steps below are intended to be performed on all AD FS servers in the farm.

Step 1: Open PowerShell and connect to your tenant by running the following:

Connect-MsolService

Step 2: Once connected, you need to run the follow cmdlets to configure the AAD tenant:

$cert = New-AdfsAzureMfaTenantCertificate -TenantID swayit.onmicrosoft.com

When successful, head to the Certificate snap in, and check that a certificate with the name of your tenant has been added in the Personal folder.

2a22

Step 3: In order to enable the AD FS servers to communicate with the Azure Multi-Factor Auth Client, you need to add the credentials to the SPN for the Azure Multi-Factor Auth Client. The certificate that we generated in a previsou step,  will serve as these credentials.

To do so run the following cmdlet:

New-MsolServicePrincipalCredential -AppPrincipalId 981f26a1-7f43-403b-a875-f8b09b8cd720 -Type asymmetric -Usage verify -Value $cert

3

Note that the GUID 981f26a1-7f43-403b-a875-f8b09b8cd720 is not made up, and it is the GUID for the Azure Multi Factor Authentication client. So you basically can copy/paste the cmdlet as is.

Step 4: When you have completed the previous steps, you can now configure the ADFS Farm by running the following cmdlet:

Set-AdfsAzureMfaTenant -TenantId swayit.onmicrosoft.com -ClientId 981f26a1-7f43-403b-a875-f8b09b8cd720

Note how we used the same GUID from the previous step.

4

When that is complete, restart the ADFS service on all your ADFS farm servers.

net stop adfssrv

net start adfssrv

Head back to your ADFS Management Console and open the Authentication method and you will notice that Azure MFA has been enabled, and the message prompt disappeared.

5

6

If the Azure MFA Authentication methods were not enabled, then enable them manually and restart the services again (on all your ADFS servers in the farm).

Now that you have completed all the steps, when you try and access Office 365 or the Azure Portal you will be redirected to the pages posted above.

Choose Azure Multi-Factor Authentication

7

Enter the six digit code you have received.

8

And then you’re signed in.

10

By now you have completed migrating from ADFS v3 to ADFS 2016, and in addition have integrated Azure MFA authentication with your ADFS farm.

The last part in this series will be about WAP 2012 R2 upgrade to WAP 2016. So please make sure to come back tomorrow and check in details the upgrade process.

I hope you’ve enjoyed the posts so far. For any feedback or questions, please leave a comment below.

 

 

ADFS v 3.0 (2012 R2) Migration to ADFS 4.0 (2016) – Part 2

In Part 1 of this series we have been getting ready for our ADFS v3.0 migration to ADFS v4.0 (ADFS 2016).

In part 2 we will cover the migration process, step-by-step. However, a friendly reminder that this series does not cover installation of ADFS and federation from scratch. This post assumes you already have a federated domain and Single Sign On (SSO) for your applications.

You may notice domain change and federation service name change from swayit.com.au to iknowtech.com.au. This doesn’t impact our migration, the certificate for swayit.com.au expired before completing the lab. : )

Migration Process – ADFS – Phase 1:

Assuming you already have installed the Active Directory Federation Services on your new ADFS 2016 servers, and if not, then you could do so through PowerShell:

Install-windowsfeature adfs-federation -IncludeManagementTools

Once complete, follow these steps:

Step 1: Add the new ADFS 2016 server to the existing farm

1-add-farm

Step 2: Connect to AD2

Step 3: Specify the primary Federation server (or federation service).3

Step 4: Select your certificate4

Step 5: Select your service account. For the sake of this lab, I created a user and gave it permission to run the ADFS service. It is advisable however, to use a group managed service account (gMSA).5

Step 6: Complete.

The warnings below are irrelevant to the ADFS 2016 server being added to the farm.6

Alternatively, you could do so through PowerShell:

If you’re using Windows Internal Database:

 Import-Module ADFS

#Get the credential used for the federation service account

$serviceAccountCredential = Get-Credential -Message "Enter the credential for the Federation Service Account."

Add-AdfsFarmNode `
-CertificateThumbprint:"071E6FD450A9D10FEB42C77F75AC3FD16F4ADD5F" `
-PrimaryComputerName:"sts.swayit.com.au" `
-ServiceAccountCredential:$serviceAccountCredential 

or:

Import-Module ADFS

$credentials = Get-Credential

Install-AdfsFarm `
-CertificateThumbprint:"071E6FD450A9D10FEB42C77F75AC3FD16F4ADD5F" `
-FederationServiceDisplayName:"SwayIT" `
-FederationServiceName:"sts.swayit.com.au" `
-GroupServiceAccountIdentifier:"SWAYIT\ADFSgMSA`$"
Once the machine has restarted, open the ADFS Management Console, and you’ll notice it’s not the primary federation server in the farm. Now you need to make the newly added ADFS 2016 server as primary. Follow the steps below.

Once the newly added ADFS 2016 server run the following cmdlet:

Step 1:

Set-AdfsSyncProperties -Role PrimaryComputer

8

Open the ADFS Management Console and you’ll notice that ADFS03 (our ADFS2016 server) is now primary:

10

Step 2: Run the following cmdlet on all other federation servers in the farm

Set-AdfsSyncProperties -Role SecondaryComputer -PrimaryComputerName ADFS03.swayit.com.au 

Step 3: Run the following cmdlet on the secondary server to confirm that the ADFS Properties are correct.

Get-AdfsSyncProperties

9-5

Migration Process – ADPREP – Phase 2

Now that we’ve made our new ADFS 2016 Server as primary, it is time to upgrade the schema.

Assuming you had already downloaded Windows Server 2016 ISO file, and if not, you can obtain a copy from TechNet Evaluation Centre.

I performed these steps on the ADFS2016 server:

  1. Open a command prompt and navigate to support\adprep directory.
  2. Type in: adprep /forestprep

1

Once the first step is complete, you will get “The command has completed successfully.”

Next run: adprep /domainprep2

Migration Process – ADFS – Phase 3:

At this stage we had already completed:

  • Adding ADFS 2016 to the existing farm
  • Promoting one of the new ADFS2016 server as primary
  • Pointing all secondary server to the primary server
  • Upgraded the schema

Next phase is to remove the existing ADFS v3 (ADFS 2012 R2) from the Azure Load Balancer (or any load balancer you have in place).

After you have removed ADFS v3 from the load balancer, and possibly from the farm (or simply by having them turned off) you will need to raise the Farm Behavior Level (FBL).

When raising the FBL, any ADFS v3 server will be removed from the farm automatically. So you don’t have to remove them yourself.

When the ADFS v3 servers are no longer part of the farm, I would like to recommend to keep them turned off, should anything go wrong you simply can go back on turning the ADFS v3 servers, make one primary, and in this case you may avoid impacting the business.

If you find yourself in this situation, just make sure everything else is pointing to the ADFS v3.

When you’re ready again, just start from the beginning in adding ADFS 2016 back to the farm.

Here are the steps:

  1. On the Primary ADFS 2016 server open an elevated PowerShell and run the following cmdlet:
Invoke-AdfsFarmBehaviorLevelRaise

12

As you may have noticed, it automatically detected which ADFS servers the operation will be performed on. Both ADFS03 and ADFS04 are ADFS 2016 versions.

During the process, you will see the usual PowerShell execution message:

12-1

Once complete, you will see a successful message:

13

If the service account had failed to be added to the Enterprise Key Admins group, do it manually.

In order to confirm the Farm Behavior Level, run the following cmdlet:

Get-AdfsFarmInformation

14

If you go to https://portal.office.com, and enter the email address of a federated domain, you should be redirected to your ADFS login page:

15

And this is it. You have successfully migrated from ADFS v3.0 to ADFS 2016.

The next post in our series is on Azure MFA integration with ADFS 2016, so make sure to please come back tomorrow to check in details the configuration process.

I hope you’ve enjoyed this post. For any feedback or questions, please leave a comment below.