How to implement Sort with Microsoft Flow in 3 actions within a loop

Photo by Sophie Elvis on Unsplash

Photo by Sophie Elvis on Unsplash

For some reason, Flow (and LogicApps) doesn’t have a built in sort() method.

So after much nudging from Paul Culmsee, I brooded about this and sat down and built one. There’s three actions within a loop, packing quite a lot of tricks, this is how it all works.

Plan

How does it work conceptually?

Build your own Sort in Microsoft Flow

Simplify it to 3 actions within a loop

Extend it to sort objects and beyond.


Defining what we need


Let’s set up some input and outputs - we want to have our initial variable within the variable “initial-array” and we want to have our final sorted result within the variable “sorted-array”

We want to do a simple insertion sort - for the academic - this is an O(n^2) sort. Not the fastest, but simple enough to understand and express with logic expressions.

How does it work conceptually?

For each element in the initial-array, we will loop add it to a final ‘sorted-array’ in a sorted position.

In the first loop, the sorted array would be empty - but as we progress, for each new value we are considering - we would split the sorted-array into two sets of sub-arrays, ones that are smaller than the current value, and ones that are larger than the current value.

Finally, we combine everything back together in a union, set that to be the new “sorted-array” value, and proceed with the next element in the initial-array.

Build your own Sort in Microsoft Flow

So extending our Flow - add a loop over the initial-array.

Within the loop, we want to put the current item into a compose action. (going with the example above, this would be the element ‘4’ )

Add a compose at the end to see the final output of sorted-array.

Cutting sorted-array into lesser half, greater half

We do this in a parallel branch - these two don’t affect each other - add two Filter Array

Left, set the item() of the sorted-array to be <= the current value of the initial-array
Right, set the item() of the sorted-array to be > the current value of the initial-array

Union the arrays together. That is, the left-array, the right array, and in the middle, the current value, but put that inside an array of 1 element with createArray( <current-value> )

Before the apply to each ends, write the union result back into the “sorted-array” that concludes this loop, getting us ready for the next value.

See how it runs:

The result is a sorted-array.

See for example, loop 6, when the value is ‘4’

Clean up and simplify

We can remove some of the blocks to make the sort ‘smaller’

The final result

3 actions within one loop

Sorting complex (JSON) Objects

It is best to build an sort-array like this with numbers to understand how it works, before attempting to tweak it to sort complex object arrays.

Say for example - if we want to sort by the Date of a complex object array (our scenario was an RSS feed) - within the apply to each, we want to isolate the property we want to compare.

Because the current item’s property is used several times - we add the top compose back into the apply to each loop, we can consider the Compose is a kind of temporary variable used to hold the value that we are using to compare with.

We need to compare against the date in the two Filter-Arrays, but we don’t actually use it for the final Union - because we want to union the arrays together, not union the dates together.

And that’s Sort. Complex explanations, but very elegant with 3 actions inside a loop.

Hot-patching our dependencies with patch-package

lego-644x450.jpg

This is also a quick blog post.

Let me tell you the tale of patch-package. Not many people have heard the tale of patch-package. Many prefer to walk the path forked.

Well, the path of patch-package works like this.

About patch-package

Your favourite NPM library has a problem. You need to hot fix it. You send in a PR and it’s stuck in review hell. The poor maintainer is on stress leave and you really don’t want to trouble her/him - they are in Finland, don’t wear shoes, and can’t possibly scale any further.

This is the patch-package path https://www.npmjs.com/package/patch-package

  1. yarn / npm lock the dependency on that specific version so our entire team and the build pipeline gets the same version

  2. npm install patch-package --save-dev

  3. make changes in node_modules against that library, e.g. “package-banana”

  4. npx patch-package “package-banana” - this creates a folder
    /patches/package-banana-version.patch

  5. add “postinstall": "patch-package" to scripts section in package.json

  6. check in / commit everything. Package.json and /patches/package-banana-*.patch

Now when anyone get latest and run npm install, the build chain will automatically grab that version of the library package-banana and apply your patch.

Then it will build as normal. This works great on Azure DevOps (VSTS) too.

When the library package-banana is finally fixed - update the library version and the patch file won’t work against newer versions.

Bad JavaScript. Expected '(' in our webpack eval chunk

This is a quick blog post for resolving an issue this morning from webpack uglified/minified JavaScript. The error happens in IE and Edge, it simply says:

Expected ‘(‘

This was happening in the middle of a webpack minified chunk so the entire block was wrapped inside eval(““)

Steps

  1. Navigate to the end of the webpack chunk, which will tell us the source of this chunk. Scroll past the sourcemap section to the end of the chunk (not the end of the file).

  2. Find the original file that the chunk was created from - now run ESLint over it.
    I didn’t have this handy in the build chain, so I ran it online https://eslint.org/demo/

  3. The error was spotted as there was a catch{} statement - in plain JavaScript - catch has to collect an argument. So the first syntax is incorrect. It must be the second syntax.

try {
    // do something
}
catch {
    // incorrect  
}
  
try {
    // do something
}
catch(e) {
    // correct, even if we don't use e  
}


Modern browsers are more lenient so this error did not appear on all browsers.

Migrate Angular SPA from ADALJS to MSAL because it is awesome

jon-tyson-420512-unsplash-resized.jpg

This is a public service announcement for all office devs.

If you are using ADALJS - you need to upgrade your project to MSAL. It is awesome. It has everything you want, and it worked the way we expected it to, right out of the box. Plus a bunch more new features.

It is 2018, we can finally put away ADALJS. Do it ASAP.


Plan

  • High level ideas - replace A with B

  • New things we can now do

  • Code diff snippets (if you want to compare notes with your own)

High Level

ADALJS was never released stand-alone. It was released as part of an Adal-AngularJS library. In the many years after several community produced wrappers were created to wrap ADALJS into various frameworks. The one I was using is ng2-adal. But there are others.

  • AdalService -> MsalService

  • this.adalService.userInfo -> this.msalService.getUser()

  • replace auth route guards with MsalGuard

  • move adalService.config(adalConfig) to MsalModule imports dependency injection

  • add msalInterceptor to HTTP_INTERCEPTORS which automatically attach the correct bearer token

  • switch http (from httpModule) to httpClient (from httpClientModule) which listens to HTTP_INTERCEPTORS

  • a handy tip to detect if SPA is running inside an adalFrame and disable route-outlets (this disables sub-components from loading inside the iframe - this is a great tip for adaljs as well)

MSAL provides three libraries with examples - make sure you switch to the relevant library instead.

MSAL is Awesome!

  • Listen to BroadcastService observables to be notified when tokens are received successfully or expired, or if consent level has changed.

  • MSAL supports incremental consent.

  • Can use acquireTokenSilent to obtain tokens silently, listen to event subscription to catch if grant isn’t available - then call acquireTokenRedirect or acquireTokenPopUp.
    Generally listen to “consent_required” or “interaction_required”.

  • App should be registered with the set of permissions that an admin can grant for the whole organization.

  • But MSAL can request additional consent separately. Users will have to grant those.

  • MSAL can issue both v1 and v2 tokens so it has no problems talking to APIs that still need v1 tokens.

  • Switch library has no visible effect to your end users - they will not see any new consent and everything will happen silently in the back.

The conversion took me two evenings to wrap up. I’m now in the process of adding new incremental consent.

Code Diff Snippets

While the whole thing is still fresh in my mind, I want to write this blog post.

Here’s what I start with

  • Angular 7

  • ng2-adal

  • adal-angular (includes adal.js)

I end up with

  • @azure/msal-angular

npm

npm install @azure/msal-angular --save

npm uninstall ng2-adal adal-angular --save-dev

app.module.ts

Change imports to msal-angular, remove my own auth.guard and use MsalGuard instead.

Use MsalIntercepter to automatically add bearer token on HttpClient calls (so replacing HttpModule’s Http with the new HttpClientModule’s HttpClient).

Initialize MsalModule with config (this is traditionally the adalConfig.

// remove
import { AdalService } from 'ng2-adal/dist/core';
import { AuthGuard } from "./my/auth.guard";
// replace
import { MsalModule } from "@azure/msal-angular";
import { MsalInterceptor } from "@azure/msal-angular";
import { LogLevel } from 'msal';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';

export function loggerCallback(logLevel, message, piiEnabled) {
    console.log("client logging" + message);
}
export const protectedResourceMap: [string, string[]][] = [
    ['https://graph.microsoft.com/v1.0/me', ['user.read']],
    // ... other scopes
];

// imports
imports: [
    ...
    // HttpModule // remove
    HttpClientModule, // replace
    MsalModule.forRoot({
        clientID: '00000000-0000-0000-0000-000000000000',
        authority: "https://login.microsoftonline.com/common/",
        validateAuthority: true,
        redirectUri: window.location.origin,
        cacheLocation: 'localStorage',
        postLogoutRedirectUri: window.location.origin,
        navigateToLoginRequestUrl: false,
        popUp: false,
        unprotectedResources: ["https://www.microsoft.com/en-us/"],
        protectedResourceMap: protectedResourceMap,
        logger: loggerCallback,
        correlationId: "1000",
        level: LogLevel.Info,
        piiLoggingEnabled: true
    })
    ....
],
providers: [
    // AdalService,  // remove
    // AuthGuard,    // remove
    {provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true}   // add
    ],

app.component.ts

constructor(
  ...
  //private adalService: AdalService,
  private broadcastService: BroadcastService,
  private authService: MsalService
) {
  this.isIframe = window !== window.parent && !window.opener;
  //this.adalService.init(this.secretService.adalConfig);
  //this is moved to app.module.ts
}

ngOnInit(): void {
  this.subscription = this.broadcastService.subscribe("msal:loginSuccess", 
    (payload) => {
      console.log("login success " + JSON.stringify(payload));    
      this.loggedIn = true;
      this.user = this.msalService.getUser();
    });  
}

ngOnDestroy() {
  // disconnect from broadcast service on component destroy
  this.broadcastService.getMSALSubject().next(1);
  if (this.subscription) {
    this.subscription.unsubscribe();
  }
}

app.component.html

<div>
  ...
  <router-outlet style="text-align:center;" *ngIf="!isIframe"></router-outlet>
</div>

app.routing-module.ts

...
import { MsalGuard } from '@azure/msal-angular';

const routes: Routes = [
    { path: '', 
        component: DemoComponent,
        canActivate: [MsalGuard],
        children: [
          ...
        ]
    },
];

Summary

TLDR - the first two paragraphs outline the high level changes we need to apply.

Sorry for the big massive screens and screens of text - these code are from my Flow Studio - and I have to cut out parts of the code to show specific changes that we need to make.

Flow Studio subscription discount finishes very soon

Photo by Fabian Blank on Unsplash

Photo by Fabian Blank on Unsplash

This will very brief.

At the end of this weekend - Most of the Flow Studio customer’s accounts will flip from Trial to Free status. There is a current discount that will expire in less than two days.

Going forward, I intend to build out more and more features but they will all be behind the subscription. Aside from general UX changes the free tier is unlikely to receive additional features.

Subscriptions

As part of this initial roll over, I wanted to do a special discount to thank my current customers and encourage everyone to move to subscription. This discount is set at $70 / first year.

Future Discounts?

Since I believe Flow Studio to be excellent value at $10/month (or $100/year), I’m unlikely to offer any future discounts. I’m more interested in building compelling features that Makers, partners and businesses needs to be extra-successful.

I didn’t make this a big marketing fanfare, as I’m a learning startup founder and selling things is something I’m learning.

Currently status: I’m still better at making things than actually selling them.

Partnerships

Many of the current subscriptions are sold and tied to the Service User account that enterprise Flows are running under. Essentially this is a “prod” license.

We see a lot of conversations in the months ahead with Makers directly for their business, or with the consultancies that are implementing Microsoft Flow across tenants, to make sure the Flow Studio subscription is a great product both for creating better Flows as well as monitoring your running Flows.

Talk to us about these partnerships. Whether it is bulk licensing, or multiple tenant scenarios. We are very early in this stage so you get to get in the door first.

Some upcoming plans over the next two months:

  • Two major features still under development - if you are interested let me know we can talk privately about feature priorities.

  • A series of short YouTube videos that explains the hundreds of use cases that you need Flow Studio.

  • Probably a FlowStudio main site make over for users visiting and not logged in.

  • May be look for a co-founder?


Thank you

Thank you so much for your time, energy, support over the last 6 months since I pushed Flow Studio out the door. It’s a journey I’m very much enjoying, and I loved talking to you all about how to use it and why you would need it.

P.S sorry I said brief and then posted a wall of text again!