Glue42 Platform Features

Running Multiple Instances

Glue42 Enterprise supports running multiple instances in different environments/regions and any combination of these. Environments usually include development, testing, quality assurance, production environments in which Glue42 Enterprise is developed, tested or integrated. Regions can be any semantic groups, defined by our clients - geographic regions, user groups, product categories, etc. This allows running multiple instances of Glue42 Enterprise simultaneously on a single machine with different settings and configurations, which is useful when testing application integration in various environments. Environment/region can be set in the system.json configuration file located in %LocalAppData%\Tick42\GlueDesktop\config. You can run multiple instances of Glue42 Enterprise by defining different system configuration files for the respective environments/regions.

Service Windows

Service windows are hidden windows which perform a specific supporting role for your application(s). They can be configured as any normal window (name, URL, etc.), the difference being that a UI configuration is not necessary as it is assumed that the purpose of these windows is to provide some "behind-the-scenes" (hidden) service to your application(s). Therefore, the user does not need to see them or interact with them.

Service windows may be useful in many scenarios. For instance, you may have a number of applications that need to receive and process data from several different providers. Instead of setting up each application to receive and then process the data from every provider, you can create a hidden service window which will communicate with the providers, collect the data, pre-process it and route it to the respective application(s). This way, your applications have to handle communication with only one end point, all the necessary data is consolidated,processed, filtered, etc., at one central data hub from where it can be sent to any window needing it. Depending on your needs or goals, you can configure your service windows to auto start on system startup, or to start when an application requests that service. The service windows approach offers you additional flexibility and versatility in designing solutions for the application services you need.

Service Window

Splash Screen

Glue42 Enterprise has a built-in splash screen, but also supports showing a custom splash screen. Your custom splash screen is loaded from a local file.

Configuration

You can replace the splash screen .html file itself in %LocalAppData%\Tick42\GlueDesktop\assets\splash with your own custom file. You can also set the size of the splash screen - the splash screen configuration can be set in the system.json file under the splash key:

"splash": {
        "width": 350,
        "height": 233
    }

Splash

For the splash screen setup to work, you need to handle the following events:

// using `ipcMain`

const { ipcRenderer, remote } = require("electron");

// updateStatus event
ipcRenderer.on("updateStatus", (event, arg) => {
    console.log(`updating status to ${arg.text}`);
    var status = document.getElementById("status");    
    status.innerHTML = arg.text + "...";
});

// setVersion event
ipcRenderer.on("setVersion", (event, arg) => {
    var status = document.getElementById("version");
    status.innerHTML = arg.text;
});

// setEdition event
ipcRenderer.on("setEdition", (event, arg) => {
    var edition = document.getElementById("version");
    edition.innerHTML += ` (${arg.text})`;
});

// setEnvRegion event
ipcRenderer.on("setEnvRegion", (event, arg) => {
    var edition = document.getElementById("version");
    edition.innerHTML += ` -${arg.text}`;
});

Downloading Files

Glue42 Enterprise allows for files to be downloaded:

  • by clicking on a link in the web page;
  • by invoking an Interop method;

Downloading Files

Configuration

The file download behavior is controlled by the system configuration. It can be alternatively overridden by the application configuration. The system download behavior configuration can be set in the system.json file of Glue42 Enterprise from the downloadSettings property of the windows top-level key:

{
    // if `true`, will autosave the file (without asking the user where to save it). If `false`, a system save dialog will appear
    "autoSave": true,
    // if `true`, will open the folder that contains the downloaded file after the download is completed
    "autoOpenPath": false,
    // if `true`, will open the download file after the download is completed
    "autoOpenDownload": false,
    // if `true`, enables windows to download files
    "enable": true,
    // if `true`, a download bar tracking the progress will appear at the bottom of the window when downloading. If `false`, the download process will be invisible
    "enableDownloadBar": true,
    // Path where the file will be saved
    "path": "%DownloadsFolder%"
}

System configuration example:

"windows" {
    "downloadSettings": {
        "autoSave": true,
        "autoOpenPath": false,
        "autoOpenDownload": false,
        "enable": true,
        "enableDownloadBar": true,
        "path": "%DownloadsFolder%"
    }
}

You can also override the default system download behavior in the application configuration .json file:

{
    "title": "Download Test Files",
    "type": "window",
    "name": "download-test-files",
    "details": {
        "url": "https://downloadtestfiles.com/",
        "top": 100,
        "left": 400,
        "width": 800,
        "height": 800,
        "allowCollapse": false,
        "startLocation": "center",
        "downloadSettings": {
            "autoSave": false
        }
    }
}

Clicking on a Link in the Web Page

When a user clicks on a download link in the website, the download will start and Glue42 Enterprise will show the download bar in the page.

The user has options to:

  • cancel the download;
  • to pause and later resume the download;
  • or to open the downloaded file in the containing folder;

Pause/Resume

Open

Invoking an Interop Method

The window facade registers a new method T42.Wnd.DownloadFile(), which accepts:

  • url - mandatory download link;
  • name - the file name;
  • autoOpenDownload - whether to open the file or not. The default is false.
  • autoOpenPath- whether to open the location of the file. The default is false.

When downloading the selected file, the cookies for that domain are taken and sent together with the request.

Note: If the file exists, it will be saved as NAME (INCREMENTAL INDEX).ext (e.g., mydocs (2).docs).

Using the Window Management API

Downloads can also be initiated by means of the Window Management API. See the Initiating Downloads section of the Window Management documentation for more information on how to do that.

Adding Extensions to Web Apps

Glue42 Enterprise allows adding extensions to some of the web-based applications it hosts. The extensions are external scripts which have access to the web page. They are useful when trying to control or inject behavior in externally developed applications.

We have prepared an example of how to add extensions to your web apps hosted in Glue42 Enterprise, which you can download from GitHub. The \examples folder contains complete extension samples with instructions on how to run them. You can use these examples to explore how the extensions work in Glue42 Enterprise. We have also included an extension template, which you can use to create and add your own extensions to your Glue42 enabled web apps.

Hotkeys

The Hotkeys API allows applications to register key combinations and receive notifications when a key combination is pressed by the user irrespective of whether the application is on focus or not.
Hotkeys is useful for web applications that do not have access to system resources and cannot register global shortcuts.

Configuration

You can control the hotkeys behavior from the system.json file under the hotkeys top-level key. You can find the system.json in the %LocalAppData%\Tick42\GlueDesktop\config folder. See the Configuration section for more details on configuring your apps. The system.json has the following properties:

  • enabled - if true, hotkeys will be enabled;
  • whitelist - list of applications that can register hotkeys; any app not on the list cannot register hotkeys;
  • blacklist - list of applications that cannot register hotkeys; any app not on the list can register hotkeys;
  • reservedHotkeys - list of reserved (system or other) hotkeys that cannot be overridden by other applications;

Hotkeys configuration example:

{
    "hotkeys": {
        "enabled": true,
        "blacklist": ["appManager"],
        "reservedHotkeys": ["ctrl+c", "ctrl+p", "ctrl+s"]
    }
}

Hotkeys API

The Hotkeys API is exposed through the glue.hotkeys object. To register a hotkey, your application must be using a glue.js version newer than 4.3.5.

Registering a hotkey:

// define a hotkey object
const hotkeyClientDetails = {
    hotkey: "shift+alt+c",
    description: "Open Client Details"
};

// register the hotkey
glue.hotkeys.register(hotkeyClientDetails, (details) => {
    // this function will be invoked when the hotkey is pressed
    glue.appManager.application("Client Details").start()
});

To remove a hotkey, use the glue.hotkeys.unregister() and pass the value of the hotkey property as an argument:

glue.hotkeys.unregister("shift+alt+c");

To remove all hotkeys, registered by your app, use the unregisterAll() method:

glue.hotkeys.unregisterAll();

To check if your app has registered a hotkey:

// returns true if this application has registered the specified hotkey
isRegistered(hotkey: string): void;

Hotkeys View

There is a utility view that allows you to see all hotkeys registered by different applications. You can open it from the Glue42 Enterprise tray icon menu - right-click on the tray icon to display the menu. When you click on the Hotkeys item you will see a list of the hotkeys registered by your app:

Hotkeys

Reference

Zooming

Glue42 Enterprise supports zooming in and out of windows of JavaScript applications. Zooming can be controlled via configuration (system-wide or per application) or programmatically via the available methods/properties of a window instance.

You can zoom in and out of windows in several ways:

  • CTRL + =/-
  • CTRL + mouse scroll
  • CTRL + 0 - resets to the default zoom factor
  • Mousepad gestures
  • using the right-click context menu (if enabled)

Note: Zooming is based on domain - i.e., if you open two applications with the same domain and change the zoom factor of one of them, the zoom factor of the other will change accordingly.

Zooming

Configuration

You can configure window zooming system-wide from the system.json file in the %LocalAppData%\Tick42\GlueDesktop\config folder. The zoom configuration is under the windows top-level key:

"windows": {
    "zoom": {
        "enabled": true,
        "mouseWheelZoom": true,
        "factors": [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500],
        "defaultFactor": 100
    }
}
  • enabled - has to be true, if you want to enable zooming;
  • mouseWheelZoom - enables zooming with CTRL + mouse scroll;
  • factors - array with zoom factors to be used when the user zooms in or out of the window. The factors must be in ascending order and may have integer or floating point values. Zooming will only work with factor values within the range of 25 to 500. Avoid passing negative values when setting the zoom factor (via configuration or programmatically), as this will cause unexpected or undesirable behavior.
  • defaultFactor - default zoom factor within the range of 25 to 500. Again, avoid negative values.

You can also enable zooming per application which will override the system-wide zoom configuration (if any). When you want to set up zooming per application, the zoom configuration should be under the details top-level key of the application configuration file:

[
    {
        "title": "MyApp",
        "type": "window",
        "name": "myApp",
        "details": {
            "url": "http://localhost:22080/my-app/index.html",
            "zoom": {
                "enabled": true,
                "mouseWheelZoom": true,
                "factors": [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500],
                "defaultFactor": 100
            }
        }
    }
]

You can enable the right-click context menu, from which the user can also control the zoom factor, using the contextMenu property and setting it to true:

  • globally, under the windows top-level key in the system.json file:
{
    "windows": {
        ...
        "contextMenu": true
    }
}
  • per application, under the details top-level key of the application configuration file:
[
    {
       ...
        "details": {
            ...
            "zoom": {
                ...
            },
            "contextMenu": true
        }
    }
]

Zoom menu

Using Zoom Programmatically

There are several methods and properties exposed on the window instance, which you can use to:

  • get the current zoom factor:
const win = glue.windows.my();

console.log(win.zoomFactor);
  • zoom in:
// will zoom in the window to the next factor in the "factors" array
win.zoomIn(); 
  • zoom out:
// will zoom out the window to the previous factor in the "factors" array
win.zoomOut();  
  • set a desired zoom factor:
win.setZoomFactor(number); 

Carefully consider all cases if you intend to pass a zoom factor value based on a logic in your app. Negative values will cause unexpected or undesired behavior. Passing positive values lower than 25 will cause zoom out with a factor of 25, positive values higher than 500 will cause zoom in with a factor of 500 and passing zero as a factor will preserve the previous zoom factor.

  • listen for zoom factor changes. The method onZoomFactorChanged() returns a function which you can use to unsubscribe from events for zoom factor changes:
const unsubscribe = win.onZoomFactorChanged(w => {
    console.log(`Zoom factor changed to ${w.zoomFactor}`)
});

unsubscribe();

Displays

Glue42 Enterprise provides a way for applications to programmatically capture screenshots of the available monitors. Based on custom logic you can capture one or all monitors in order to save a snapshot of the visual state at a given moment.

The Displays API is accessible through glue.displays.

Configuration

To enable display capturing you must add the "allowCapture": true property to your application configuration file.

{
    "name": "MyApp",
    "type": "window",
    ...
    "allowCapture": true,
    "details": {
        "url": "http://localhost:3000"
        ...
    }
}

Displays API

All displays

You can get all displays by using the all() method. It returns a Promise that resolves with an array of Display objects:

glue.displays.all(); // returns all available displays

The returned Display objects have the following properties and methods:

  • id - unique identifier associated with the display;
  • bounds - a Bounds object with height, width, left and top properties, describing the bounds of the display;
  • workingArea - a Bounds object describing the working area of the display (the desktop area, excluding taskbars, docked windows and toolbars).
  • dpi - dots per inch resolution of the display;
  • isPrimary - a boolean value specifying whether this is the primary display;
  • index - index assigned to the display by the operating system;
  • name - name assigned to the display by the operating system;
  • aspectRatio - display aspect ratio (e.g., 16:9);
  • scaleFactor - the scale factor of the returned display (e.g., 1.25 = 125%).
  • capture() - method for capturing the selected display instance. Accepts either a ScaleOptions or an AbsoluteSizeOptions object, specifying the size of the output image. Returns an image as a base64 encoded string;

The ScaleOptions object has only one property - scale, which accepts a number. The value you pass to it specifies the size of the output image relative to the actual screen size. For instance, if you use scale: 0.5 the height and width of the output image will be half the height and width of the captured screen.

The AbsoluteSizeOptions object has the following properties, all of which are optional:

  • width - a number specifying the width of the output image. Defaults to the captured display width;
  • height - a number specifying the height of the output image. Defaults to the captured display height;
  • keepAspectRatio - a boolean value specifying whether to keep the aspect ratio of the output image when you specify width and/or height of the output image. If true and both width and height are set, then the specified width will be used as a basis for the output image aspect ratio;

Below is an example of finding and capturing all non-primary displays:

const screenshots = await Promise.all(
            (await glue.displays.all()) // get all displays
            .filter(display => !display.isPrimary)  // filter out the primary display
            .map(display => display.capture({ scale: 0.5 })));

Primary display

You can get the primary display with the getPrimary() method:

// returns the primary display
const primaryDisplay =  await glue.displays.getPrimary(); 

Example of finding and capturing the primary display:

const display = await glue.displays.getPrimary();
const screenshot = await display.capture({ scale:0.5 });

Specific display

To get a specific display, use the get() method. It accepts a display ID as an argument and returns a Promise that resolves with a Display object:

const displayID = 2528732444;

// returns a display by ID
const display = await glue.displays.get(displayID); 

Capturing all displays

To capture all displays, use the captureAll() method. It accepts a CaptureAllOptions object and returns a Promise that resolves with a base64 encoded string or an array of base64 encoded strings, depending on the specified combined option.

In the example below, we will capture all available displays and combine the screenshots into a single image with width set to 2000 pixels. The aspect ratio of the combined images will be preserved (the omitted keepAspectRatio property in the size object defaults to true) and the images will be arranged the way you have arranged your displays from your operating system settings:

const screenshot = await glue.displays.captureAll({ combined: true, size: { width: 2000 } });

The CaptureAllOptions object has the following properties:

  • combined - Required. Specifies whether to return a single image (if true) of all captured displays or a separate image (if false) for each captured display;
  • size - Optional. Accepts either a ScaleOptions or an AbsoluteSizeOptions object, specifying the size of the output image;

Capturing a single display

To find and capture a single display by ID, use the capture() method. It accepts a CaptureOptions object and returns a Promise that resolves with an image as a base64 encoded string.

In the example below we use the display ID to find and capture the desired display. We also specify capturing options - the width and height of the output image will be half the width and height of the captured monitor. The captured image is returned as a base64 encoded string:

// specify the display ID and the capture options
const displayID = 2528732444;
const captureOptions = {
    id: displayID,
    size: { scale: 0.5 }
}

const screenshot = await glue.displays.capture(captureOptions);

The CaptureOptions object has the following properties:

  • id - Required. A number specifying the ID of the targeted display;
  • size - Optional. Accepts either a ScaleOptions or an AbsoluteSizeOptions object, specifying the size of the output image;

Capturing windows and window groups

You can use the capture() method of a window instance or a window group to capture the respective window or window group. This method works also for minimized windows/window groups but does not work for hidden windows.

// capture the current window
const windowScreenshot = await glue.windows.my().capture();

// capture the current window group
const groupScreenshot = await glue.windows.groups.my.capture();

Reference

Logging

Glue42 Enterprise offers a Logger API which enables JavaScript applications to create a hierarchy of sub-loggers mapped to application components where you can control the level of logging for each component. You can also route the output of log messages (depending on the logging level) to a variety of targets:

  • the developer console;
  • an external output - usually a rolling file on the desktop, but actually any target the log4net library supports;

Logging to Files from Your JavaScript Application

Adding logging to files to your JavaScript apps can be helpful in a variety of ways. Having a well-designed and meaningful logging structure in your apps and their components can save a lot of time when debugging an app during development or troubleshooting problems with an app in production.

Logging to files for JavaScript applications is available from version 4.8.0 or later of Glue42 JavaScript and Glue42 Enterprise 3.9 or later.

Logging Configuration

Logging for applications in Glue42 Enterprise is disabled by default. To allow it, you need to add an allowLogging key to your application configuration file and set it to true:

{
    "name": "my-app",
    ...
    "allowLogging": true,
    "details": {
        ...
    }
}

Using a Logger

The Logger API allows you to design a logging mechanism with a hierarchical structure in your app. Logger instances have a subLogger() method that creates a new sub-logger of the current logger. The name of each logger instance is a dot delimited string containing all names of the loggers constituting an hierarchy line from the base logger (the application name) down to the current logger. This allows an effective and intuitive logging structure which can be easily adjusted to the component hierarchy in your app. For instance, a structure like app-name.main-component.sub-component gives you a clear idea from where the respective log entry originates and helps you find the necessary information much faster in a log file that may (and usually does) contain thousands of entries.

To use a logger in your Glue42 enabled applications, create a logger instance with the subLogger() method and assign the logger a name:

const logger = glue.logger.subLogger("main-component");

Next, you need to set the logging level at which to publish log entries to the file. Use the publishLevel() method of the logger instance:

logger.publishLevel("info");

Everything at and above the specified logging level will be logged, all else will be skipped. The available logging levels are trace, debug, info, warn and error.

To log messages, you can either use the log() method of the logger instance which accepts the message and the logging level as string parameters, or you can use the respective logging level methods (error(), trace(), etc.) which accept a log message as a parameter.

logger.log("Could not load component!", "error");

// or

logger.error("Could not load component!");

Location and Output

User application log files are located in the %LocalAppData%\Tick42\UserData\<ENV>-<REG>\logs\applications folder. A separate log file is created for each application that has logging enabled. The file is named after the application and is created after the app actually starts to output log entries. All instances of an application log to the same file.

The log file entries are in the following format:

[<DATE>T<TIME>] [<LOGGING_LEVEL>] [<INSTANCE_ID>] [<LOGGER_NAME>] - <LOG_MESAGE>

Here is how an actual entry in a log file looks like:

[2020-03-11T14:27:58.087] [ERROR] [30760_11] [client-list.test-logger] - test-error
    at t.error (http://localhost:22080/client-list/desktop-4.8.0.js:1:39269)
    at <anonymous>:1:8

Reference

Process Reuse

Glue42 Enterprise is an Electron based application and as such, uses the built-in process management mechanisms of Electron - each window has a separate renderer process. This, however, may lead to a large memory footprint. The concept of process reuse helps you achieve balance between performance and consumption of system resources.

Glue42 Enterprise offers configurable grouping of application instances in a single process. Process reuse can be configured both on a system and on an application level from the system.json file of Glue42 Enterprise or, respectively, from the application configuration file.

Here are some basic use-cases and the configurations needed for them:

  • If you want every instance of your app to go into a dedicated process, set the dedicatedProcess property (under details.processAffinity) to true in your application configuration file:
"details": {
    ...
    "processAffinity": {
        "dedicatedProcess": true
    }
}
  • If you want to group all instances of your application into a single process, assign a unique string value to the affinity property (under details.processAffinity) in your application configuration file:
"details": {
    ...
    "processAffinity": {
        "affinity": "XYZ"
    }
}

But also bear in mind that the number of instances that can be grouped into a single process is restricted by the value of the maxAppsInProcess property in the global process reuse configuration of the system.json file. You can set it to a high number (e.g. maxAppsInProcess: 1000) in order to be able to group all instances of your app in a single process with the affinity property.

  • If you want to group several apps into a single process, assign the same string value to the affinity property (under details.processAffinity) in the application configuration file of each app you want to group in the process:

Client List App

"name": "clientlist",
...
"details": {
    ...
    "processAffinity": {
        "affinity": "XYZ"
    }
}

Portfolio App

"name": "portfolio",
...
"details": {
    ...
    "processAffinity": {
        "affinity": "XYZ"
    }
}

Again, consider setting the global process reuse configuration in the system.json file in order to achieve the desired results when grouping applications and application instances in a process. The maxAppsInProcess defines the maximum number of (any) instances that can go in the process and the appSlotSize property defines how many slots in that process are reserved for instances of the same application.

  • If you want to increase the number of apps in a single process, use the maxAppsInPocess property of the global process reuse configuration in the system.json file:
"processReuse": {
        "enabled": true,
        "visibleApps": {
            "maxAppsInProcess": 50,
            "appSlotSize": 2
        },
        "hiddenApps": {
            "maxAppsInProcess": 20,
            "appSlotSize": 1
        }
    }

You can use the Applications View to monitor how applications are grouped in processes.

System Configuration

You can configure process reuse on a system level for both visible and hidden apps:

"processReuse": {
        "enabled": true,
        "visibleApps": {
            "maxAppsInProcess": 12,
            "appSlotSize": 3
        },
        "hiddenApps": {
            "maxAppsInProcess": 20,
            "appSlotSize": 1
        }
    }
  • enabled - if true, will enable process reuse;
  • maxAppsInProcess - the maximum number of application instances in a process (maximum slots in a process).
  • appSlotSize - this sets the number of slots reserved for instances of the same application within a process. The total number of slots in the process is defined by the maxAppsInProcess.

If you want more apps to use the same process, you can increase the maxAppsInProcess value, or decrease the appSlotSize value. If you set maxAppsInProcess to 1, then all apps and their instances will be in a separate process.

If we use the settings for visible apps above ({"maxAppsInProcess": 12, "appSlotSize": 3}), then we have a maximum of 12 slots per process and 3 slots reserved for instances of the same app in that process. This translates to the following:

  • If we start four different app instances and after that we start more instances of any of these four apps, when the slots for an app are filled (each of the four apps has 3 slots reserved for itself), the fourth instance of any of the apps will go in another process:

Process Reuse

  • If we start, say, two different app instances and then we start only instances of any of these two apps, their instances will run in the same process until the remaining two sets of three slots in the process are filled too:

Process Reuse

Application Configuration

To set the process reuse behavior on an application level, use the processAffinity property under the details top-level key in the application configuration file:

"details": {
    ...
    "processAffinity": {
        "dedicatedProcess": false,
        "affinity": "XYZ"
    }
}
  • dedicatedProcess - if set to true, each instance of the app will be started in a separate dedicated process. This property is useful if you have an important application and you want each instance of it to start in a dedicated process.
  • affinity - this property accepts any string value you define. All apps with the same affinity values will be grouped in the same process until the maximum number of slots (defined globally in the maxAppsInProcess property) in the process is reached. When affinity is set, the global appSlotSize property is ignored. This means that you can group different app instances with the same affinity however you like within the limits of the maxAppsInProcess property. Use this property if you want to group several apps in a process.

Here is an example of grouping by affinity (we have set the affinity property of several apps to XYZ and maxAppsInProcess is set globally to 12):

Affinity

Flash Plugin

By default, Flash plugins are disabled in Glue42 Windows. To enable Flash plugins, you need to add the respective configuration in the system.json file of Glue42 Enterprise under the flash top-level key.

To enable the default Flash plugin that comes with Glue42 Enterprise:

{
    ...
    "flash": true,
    ...
}

To enable a specific Flash plugin, provide its path:

{
    ...
    "flash": "C:\\Users\\user\\AppData\\Local\\Tick42\\GlueDesktop\\assets\\flash\\32.0.0.330\\pepflashplayer.dll",
    ...
}

Issue Reporting

Glue42 Enterprise has a built-in feedback form that allows users to send feedback with improvement suggestions or bug reports. The user can describe the problem/suggestion in the "Description" field and can optionally attach screenshots/logs to the report. The form can be configured to send an email with the report to our team and/or to automatically create a Jira ticket with the issue reported by the user.

The feedback form is an HTML app, which can be re-designed and re-configured to suit specific client needs and requirements. For more details, see the system configuration schema.

Feedback form

Adding DevTools Extensions

You can extend the Chrome DevTools in Glue42 Enterprise with additional extensions. To add a DevTools Extension supported by Electron, you need to have the extension installed and add a configuration for it in the system.json file of Glue42 Enterprise and in the configuration file of your application. The example below demonstrates adding the React DevTools Extension to Glue42 Enterprise:

  1. Install the React DevTools Chrome extension.

  2. Locate the extension on your local machine - the default location for the React DevTools Extension is %LocalAppData%\Google\Chrome\User Data\Default\Extensions\fmkadmapgofadopljbjfkapdkoienihi. (You can move the extension installation folder wherever you like.)

  3. Open the system.json configuration file of Glue42Desktop located in %LocalAppData%\Tick42\GlueDesktop\config and add the path to the React DevTools Extension under the devToolsExtensions top-level array:

"devToolsExtensions": [
    "C:\\Users\\<username>\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Extensions\\fmkadmapgofadopljbjfkapdkoienihi"
]

Replace <username> with your local username. Remember to escape the backslash characters.

  1. Open the .json configuration file of your application and add the following configuration under the details top-level key:
"security": {
    "sandbox": false
}

For instance:

{
    "name": "My App",
    ...
    "details": {
        "url": "http://localhost:3000",
        ...
        "security": {
            "sandbox": false
        }
    }
}
  1. Start Glue42 Enterprise, open your Glue42 enabled app and you should be able to see the added extension to the Chrome DevTools when you open the developer console. In this case, you would need a React app in order to be able to see the React DevTools Extension.

Extensible Installer Guide

The Glue42 Enterprise installer supports extensibility mode, meaning you can repackage the installer with custom resources and installation settings. Some of the customizable features include replacing the icons, the installation screen, adding/removing or setting default install options or features of Glue42 Enterprise, adding other programs to be installed together with Glue42 Enterprise.

Extensibility Mode

The Glue42 Enterprise installer can be run with an argument /ext:path\to\extensibility-file.json, which defines the path to a file that allows the operation of the installer to be controlled.

The installer defines a number of extensibility points, representing stages of the installation flow, each of which can be populated with one or more extensibility items, representing tasks to perform or settings to change. These items are listed in the extensibility file with the following structure:

{
    "<extensibility point 1>": [
      { "type": "<extensibility item type>", "args": { "<arg>": <value>, ... }},
      { "type": "<extensibility item type>", "args": { "<arg>": <value>, ... }},
    ],
    "<extensibility point 2>": [
      { "type": "<extensibility item type>", "args": { "<arg>": <value>, ... }},
      { "type": "<extensibility item type>", "args": { "<arg>": <value>, ... }},
    ],
}

In case of no arguments, an extensibility item can be shortened to just a string with its type:

{ "type": "unattended", "args": {} } is shortened to "unattended".

Here is an example extensibility file content, listing most of the available extensibility points and items:

Note: This is just for illustrative purposes. Some of the following settings don't make sense together.

{
    "startup": [
        // uninstall Glue42 Enterprise
        "uninstall",

        // unattended installation
        "unattended",

        // NB: the installation cannot run while certain applications are running,
        // e.g. a previous installation of Glue42 Enterprise, or Excel/Word/Outlook
        // (unless the corresponding plugin is disabled in the artifacts extensibility point)

        // By default, an unattended installer will exit with a non-zero exit code,
        // but you can make it retry by adding the following arguments:

        // - pop a message box for the user to dismiss (NB: this might cause
        // the installation to stall if there is no user present)
        // "args": { "conflictHandling": "ask" }

        // - retry 10 times, with an interval of 1 second
        // "args": { "conflictHandling": "retry", "waitMs": 1000, "retries": 10 }

        // hidden installation: similar to "unattended", but without showing a window
        "hidden",

        // use a predefined license file
        {
            "type": "license",
            "args": {
                // either path or url
                "file": "license.json",
                "url": "https://example.com/license.json"
            }
        },

        // logo to display in top-left corner
        {
            "type": "logo",
            "args": {
                // either path or url
                "file": "logo.png",
                "url": "https://example.com/logo.png",
                "onClick": "https://example.com/example"
            }
        },

        // large banner during installation
        {
            "type": "banner",
            "args": {
                // either path or url
                "file": "banner.png",
                "url": "https://example.com/banner.png",
                "onClick": "https://example.com/example"
            }
        }
    ],
    "artifacts": [

        // disable GlueXL artifact
        {
            "type": "GlueXL",
            "args": {
                "remove": true
            }
        },

        // make GlueOutlook not selected by default;
        // in unattended installations, this is the same as "remove"
        {
            "type": "GlueOutlook",
            "args": {
                "checkedByDefault": false
            }
        },

        // make GlueWord required
        {
            "type": "GlueWord",
            "args": {
                "required": true
            }
        },
    ],

    // welcome screen
    "welcome": [
        {
            "type": "run",
            "args": {
                "filename": "cmd.exe",
                "args": "/c somebatchfile.bat",
                // by default, exit code 0 is success,
                // while any other means error message, followed by installer exiting
                // you can override with "success" for success, any other string for error message
                // (error messages are not shown in unattended installation to avoid stalling)
                "exitCode1": "There was an error validating your installation",
                "exitCode2": "There was an error contacting server",
                "exitCode3": "success",
                //other exit codes

                // whether to hide the started process
                "hide": true,

                // whether to hide the installer while the process is running
                "hideInstaller": false
            }
        }
    ],

    // ... other screens: downloadProgress, packages, previewAndConfirm, uninstall, ...

    // package the Glue42 Enterprise installer with custom configuration files
    "finalizing": [ 
        {
            "type": "gdConfig",
            "args": {
                // archive with custom config files for Glue42 Enterprise
                "file": "custom-config.zip",
                // If `false` (default), will merge the custom config files with the default ones from the installer
                // by replacing any default file with the respective custom config file with the same name.
                // If `true`, the default config files will be deleted and replaced by the specified custom config files.
                // This means that you must provide all required configuration files for Glue42 Enterprise to function properly.
                "wipe": false
            }
        }
    ],

    // final screen
    "done": [
        // show Glue42 Enterprise shortcut location - like the current "Launch" button behavior
        "showGD",

        // launch the Glue42 Enterprise executable - like the old "Launch" button behavior
        "launchGD",

        // shows a message box
        {
            "type": "message",
            "args": {
                "text": "Don't forget to be awesome!",
                "title": "Reminder"
            }
        },

        // this is a good place to use a "run" item if something else needs to
        // happen after the installer is finished, e.g., run another installer

        // exit from final screen without user having to click "Done"
        {
            "type": "exit",
            "args": {
                "exitCode": 0
            }
        }
    ]
}

Some types of extensibility items are only applicable to some extensibility points, e.g., "unattended" (which enables an unattended installation) is only applicable to the "startup" extensibility point. Others can be used anywhere - such as "run", which executes an external program and waits for it to finish; or "message", which shows a message to the user.

Extensibility items are executed in the order they are specified. Multiple items of the same type can be present in the same extensibility point.

Step-By-Step Example

You can download the extensible installer example we have prepared for you in order to get you started. You can use it to test how the extensible installer works, to tweak the setting, add your own files and, ultimately, create your own extensible installer.

In this step-by-step guide you will be creating a custom Glue42 Enterprise extensible installer with the following additions and changes:

  • adding custom logos;

  • installing Glue42 Enterprise with custom system.json properties, in order to setup Glue42 Enterprise to retrieve application configuration settings from a REST service;

It is assumed that you have your icon and install screen banner files ready, and also - you have set up your REST service and have it up and running.

Note: If you have your own Glue42 Enterprise installer file, then rename your installer to GlueInstaller.exe and in the installer-and-other-files folder replace the existing GlueInstaller.exe file with your own installer file.

  1. Navigate to the directory where you have downloaded the sfx-installer-example.zip and extract the files in it.

  2. Open the installer-and-other-files folder and replace the provided logo.png and banner.png example files with your own logo and banner files.

  3. Open the example-extensibility.json in your preferred text editor and under the startup top key array edit the arguments object of the respective extensibility items for the installation banner and logo:

  • replace the file property values with the respective names of your logo and banner files;
  • if you want clicking on the logo or the banner during installation to open your site, replace the URL in the onClick property with a link to your site. Otherwise, remove it altogether;
"startup": [
    {
        "type": "logo",
        "args": {
            "file": "MyCustomLogo.png",
            "onClick": "https://www.my-site.com"
        }
    },
    {
        "type": "banner",
        "args": {
            "file": "MyCustomBanner.png",
            "onClick": "https://my-site.com"
        }
    }
]
  1. The provided system.json file in sfx-installer-example.zip may not be the latest one, so you have to replace it with the system.json file from your Glue42 Enterprise copy located in %LocalAppData%\Tick42\GlueDesktop\config. Open the system.json file in your text editor and add the following configuration in order to enable Glue42 Enterprise to retrieve the application configuration settings directly from a REST service:
"appStores": [
    {
        "type": "rest",
        "details": {
            "url": "http://localhost:3000/appd/v1/apps/search", // URL to your remote application store
            "auth": "no-auth",
            "pollInterval": 30000,
            "enablePersistentCache": true,
            "cacheFolder": "%LocalAppData%/Tick42/UserData/%GLUE-ENV%-%GLUE-REGION%/gcsCache/"
        }
    }
]
  1. Go back to the folder, where you extracted the files, and double click on the produce-sfx-installer.bat file to produce the installer file. The output installer file is named sfx-installer.exe.

  2. Run sfx-installer.exe to install the product.

Note: The SFX installer should be Authenticode signed to avoid antivirus software raising false alerts. Also, to change its icon or file properties, you can use a resource editor, e.g. Resource Hacker. It is best to use a multi-size icon, to support various resolutions and Windows Explorer view modes; the example used the Greenfish icon editor for this purpose.