Gravatar

Innovation Studio

Q2developer.com


Tecton is now 1.0

Overview

After 3 years Tecton is 1.0! IE support is dropped as well as some small syntax and argument refactors which are spelled out step by step in this guide. Tecton 1.0 upgrade guide. Here is a brief description of Tecton our versioning system. Including why there are no new features in 1.0 and how to write your apps with our progressive enhancement system.

Tecton Description and History

Tecton has been in development since September 2017 and was created out of a need for reliable APIs when writing embedded applications for Q2's UUX banking platform. Previously UUX had allowed apps to be embedded by dynamically injecting html into its application. Although there were global APIs available and workarounds for interacting with the app the injected html was embedded in, they were not a part of a versioned API and sometimes changes by the core app developers created incompatibilities and forced upgrades for the embedded apps. There were also many issues around library incompatibility and other JavaScript conflicts which led to a lot of manual review.

Tecton's system uses iframes to provide each embedded app with their own private execution context enabling use of any libraries or frameworks desired. Tecton provides a core set of HTML elements and styles that enable the embedded apps to strongly resemble the application they are embedded in. Additionally it provides a JavaScript SDK(API) that gives access to functionality in the parent application(UUX). These APIs are broken into two categories: sources and actions. Sources are APIs that are called to give you information from the parent app such as fetching data. Actions are APIs that invoke some sort of visual or programmatic change like logging the user out or showing an alert or modal. You can review the documentation for these APIs by version in the capabilities section of the Tecton docs.

How versioning works in Tecton

Lots of things are new in Tecton but nothing is new in the 1.0 release! Here is why.

Tecton follows semantic versioning which is explained in detail here. The most important thing to understand is that there are three parts to a Tecton version all delimited with periods. Major, minor, and patch. It looks like this:

MAJOR.MINOR.PATCH or 1.0.0 or 0.42.1

MINOR version releases contain new features which are added in a backward compatible way. PATCH releases will only fix bugs and will also be backward compatible these releases will not introduce new features. Finally MAJOR releases are the only time you will have to refactor your code to take the release, and sometimes you still won't have to.

As we do minor releases, we will deprecate a feature or a way of using a feature for future removal. It will still work but will let you know that in the next major release it will work in a new way. That new way will already be available to you and you can refactor you code as you have time in advance to be ready to take the next major version when the time comes.

How to rely on Tecton versioning for confidence in planning releases

Currently our plan is to release a major version once a year, with all deprecations being announced and the new APIs that will replace them being available 6 months before the major version is released.

Our MINOR (feature) releases happen ever 3 to 4 weeks and our PATCH (bug fix) releases happen as needed.

We will spend the first half of a major release focusing on any work that involves deprecations and new APIs that require refactoring. The second half of the major release cycle (6 months) will be new additions that are completely backward compatible and require no development planning.

Our goal is for all extensions running tecton-sdk to be compatible with platforms even on a previous version. So if you upgrade your extension to Tecton 1.0 you can still be embedded into a UUX platform running Tecton 0.40.0. However if a platform is upgraded to a major version like 1.0 to run on that platform you may be required to upgrade your extension to also be on the same major version. This may not always be the case but are the compatibility rules we have set out to adhere by.

Here is an example:

  • UUX Platform running 0.40.0 w/ Extension running 1.1 (IS COMPATIBLE)
  • UUX Platform running 1.3 w/ Extension running 1.0 (IS COMPATIBLE)
  • UUX Platform running 1.3 w/ Extension running 0.42.0 (IS NOT COMPATIBLE)

We are proud of this release pattern, and hope it brings stability to your software and saneness to your development planning. Tecton is built with ease of use and reliability as its main goals. We welcome all feedback that helps us reach that. You can message any feedback or feature requests by opening a support ticket on the Q2 Developer Portal. Additionally, you can also email me personally at daniel.chappell@q2.com if you need help thinking through your request.

Why now?

We have mostly been ready for 1.0 for a while now but knew that our 1.0 would drop support for Internet Explorer. Which as a company we were not ready to do. We feel that finally the day has come that we can safely do that as IE browser share has dropped and migration paths to different browsers are better than ever with Chromium Edge being offered as a Microsoft replacement. There are other breaking changes which are listed in a separate 1.0 migration guide linked here.

Staying on the cutting edge with progressive enhancement

Many, but not all, of our javascript features rely on a "platform" element as well. This means that if a feature is introduced in Tecton 1.2.0. The extension (embedded app) would run tecton-sdk 1.2.0 but the parent application would need to run tecton-platform 1.2.0 for that feature to be supported. This is unfortunately a hard truth about our product as most of our features are connecting you to features provided in the parent app. Old versions of the platform app won't know about your new feature and cannot provide the necessary connecting code to make it work.

This can be a real pain point because one of the benefits of developing with Tecton is the ability to deploy one application to many different versions of the platform app (UUX).

THERE IS A SOLUTION

To solve the problem of wanting to use a new Tecton API without limiting the versions of the platform you can embed in Tecton created a capability system to enable building with progressive enhancement in mind.

Progressive Enhancement: The design philosophy that provides a baseline of essential functionality to as many users as possible, while delivering the best possible experience to users of the most modern (up to date) platforms (UUX running the appropriate tecton-platform version) cite Mozilla

To connect to the platform app tecton provides the connect method. It returns a promise that contains all of the sources and actions available.

    import { connect } from 'tecton-sdk';

    connect().then((capabilities ) => {
        //capabilities will include all actions and sources
        // available on the platform you have connected to
        capabilities.sources.requestExtensionData('fetchEligibleAccounts').then(response => {
            let accounts = reponse.data;
            displayAccountsOnPage(accounts); //Hypothetical next action in program

            capabilities.actions.setFetching(false);
        })
    });

In the example above our program on startup connects to the platform application through Tecton and is provided both the actions and sources that are available on this platform version. Every application has functionality that it will require to do its most essential tasks I would refer to as the baseline functionality and a platform would require that to embed you app. In this example both the source api requestExtensionData (fetching data from your extension's own service) and the action setFetching (turning off and on the global spinner and toggling the visibility of your iframe) are safe APIs that have existed since the beginning of Tecton.

If an application installs a version of 'tecton-sdk' that supports a new feature, for example showing a modal, and the platform it is being embedded in is also on a version that supports that feature, then the function providing that feature, in this case, showModal, would be returned from the connect promise. If the platform does not yet support this feature Tecton's connect function will intelligently not return the showModal function in the returned promise.

This enables you to use if statements to check if a feature is available before using it and provide fall back strategies and safely handle when it is not.

Lets expand this application with some enhancement functionality that may not be available to everyone.

    import { connect } from 'tecton-sdk';

    connect().then((capabilities ) => {
        //capabilities will include all actions and sources
        // available on the platform you have connected to
        capabilities.sources.requestExtensionData('fetchEligibleAccounts').then(response => {
            let accounts = reponse.data;
            displayAccountsOnPage(accounts); //Hypothetical next action in program

            capabilities.actions.setFetching(false);
        }).catch(err => {
            if (capabilities.actions.showModal) {
                capabilities.actions.showModal({title: 'Could Not Load Accounts', message: err.message}).then(() => {
                    capabilities.actions.navigateTo('landingPage');
                });
            } else {
                //Hypothetical way to show error in your application iframe instead of modal
                showErrorMessageOnPage('Could Not Load Accounts', err.message); 
            }
        });
    });

In this example, we expanded our previous scenario to handle an error fetching the accounts. Because fetching the accounts is something our application needs to continue, we handle the error by showing a blocking modal explaining to the user what happens. When the modal is closed, the promise returned by showModal is resolved. After that, the navigateTo action, provided by Tecton, navigates back to the starting page of the platform application (landingPage in UUX). If showModal is not available in the platform we are being embedded in showModal will be undefined and we will fall back to showing the error in our iframe instead and optionally taking other action after that like navigating away (this last part is not in the code example).

This progressive enhancement strategy that Tecton provides not only helps in situations where you want to use new features while not excluding the possibility to deploy your app in older platforms. It also enables the use of Tecton APIs that might be device specific.

Let's add the feature to take a picture to represent your avatar. In the below example assume we already have the code in the above examples so it does not have to be repeated.

    //In this code example we have already called connect
    //and capabilities is a variable in scope

    function takePictureForProfile() {
        if (capabilities.sources.takePicture) {
            return capabilities.sources.takePicture();
        } else {
            return fileUploadDialog();
        }
    }

In this example, the API takePicture may not be available not only because of platform version limitations but also device limitations as it requires the device to have a camera. Here we chose to check if takePicture is available and if so open the camera to capture a picture via the Tecton takePicture API, if it is not available we have fallen back to a hypothetical file upload workflow that would be available to everyone. You can also use this strategy to omit entire workflows instead of providing fallbacks.

Finally it is very common that an extension will want to navigate to another location in the platform application or navigate to another extension. This is also an action that can limit the platforms you are able to embed in as a feature or extension may not be available in all version of a platform. For this we have provided the isNavigable API that checks first if you can navigate to a location. In our previous example we navigated to the 'landingPage' in UUX this is completely safe as it has existed since the beginning. Lets look at an example where we might need a fallback.

    //In this code example we have already called connect
    //and capabilities is a variable in scope
    function reportFraudOnAccount(accountId) {
        capabilities.sources.isNavigable('reportFraud').then(canNavigateToFraudReport => {
            if (canNavigateToFraudReport) {
                capabilities.actions.navigateTo('reportFraud', accountId);
            } else {
                capabilities.actions.showModal({title: 'How to Report Fraud', message: 'Please call (123) 456-7890 to speak with a representive that will help you'})
            }
        });
    }

Here we are allowing the user to transition to a fraud report page if it is available but otherwise giving them information on how to report if it is not. You might notice that I used showModal here with out first check if it is available. showModal is a well supported API that mostly does not need this check and my earlier example was for demonstration purposes. On each capability documentation page, at the bottom, we list the earliest platform version in which that capability is available. Here is the showModal documentation. See at the bottom in the section titled Platform Compatibility & Notes.

To clean these conditionals up a forward thinking team could create abstractions that would encompass the fallback (or multiple fallbacks) every time. This would make you code a lot simpler to read and cylomatic complexity which is generally frowned upon.

    function myShowModal(modalInfo) {
        if (capabilities.actions.showModal) {
           return capabilities.actions.showModal(modalInfo);
        } else {
            //Hypothetical fallback showing info inside application iframe
            return builtInModalFallback(modalInfo);
        }
    }

This extension would now use their own myShowModal convience function to have a built in fallback.

Highlighted APIs

showOverpanel - closeOverpanel

As we reach 1.0 I want to take time to highlight what I consider some of Tecton's neatest APIs.

In v0.19.0 we introduced the concept of overpanels which are large (near fullscreen) modals that are meant for workflows that will return data back to the main program.

If you were a billpay app showing all payees with a option to add a payee, you might want to open the workflow to add a new Payee in a modal and when that modal closed your app would already be showing the new payee.

The showOverpanel Tecton action launches an overpanel with an iframe loading another embedded application with the desired workflow. This can be your same application opening at a different route, a different application that you have written, or some other extension that you are integrating with.

showOverpanel is paired with another tecton action named closeOverpanel. The opening app calls showOverpanel recieving a promise that is resolved with the data passed to closeOverpanel, which is called at the completion of the workflow to close the overpanel and also pass the data aggregated back to the primary application.

// billpay-payees.js the main extension
    
    addPayee() {
        capabilities.actions.showOverpanel('addPayee').then(newPayee => {
            addNewPayeesAndReRender(newPayee);
        });
    }

// add-payee.js running in the overpanel

savePayee(payeeData) {
    capabilities.actions.closeOverpanel(payeeData);
}

promptForMFA

Another valuable feature we have added is the ability to open up a multi factor authentication workflow in the parent application and receive back and a promise that resolves or rejects based on the successful authentication of the user. This is especially helpful for extension that require increased security for their transactions and gives a more integrated feel that recreating that workflow inside the embedded application.


promptForMFA('Authorization required to perform this transaction.').then(() => {
    performTransaction();
}).catch((err) => {
    capabilities.actions.showModal({title: 'Authorization Failed', message: err.message}).then(() => {
        clearForm();
    });
});

Highlighted Elements

We have added a lot of robust elements that are fully accessible! Here are a few that I think really shine. The Elements in Tecton are fully provided with out any dependency on the platform app so you never have to worry about compatibility when using them.

In v0.39.0 we added the Carousel element that can be used to show case lists of all kinds of dynamic content. It is navigable via the keyboard, mouse/drag, touch/swipe, on screen controls carousel controls, and is voice over accessible! It contains more options that I can list here and code examples don't do it justice. Check out the carousel documentation for interactive examples and code snippets.

While Tecton was launched with a select element it has only become more robust and accessible with each release. It supports full keyboard controls and voice over, while have a multi select and searchable presentation. You can even yield in any html into an option, for more complex presentations. Check out all the interactive examples in the select documentation.

Plans for the future

In the 1.x series of releases we plan focus on improving our style APIs by adding better choices for colors and theming variables, Add improvements to the calendar, and improve documentation all around. More things are in the works, watch the blog for periodic feature announcements! If like what we are doing and want to join the team, or just want to help us do it better! Please apply here We are always looking for people ready to geek out on micro-frontends and building enabling technologies. Tecton is build with love at Q2 using Typescript and RXJS with a functional style, and Stenciljs for the WebComponents.