More
Jump List
The jump list is a configurable categorized list of actions that can be shown in the context menu when the user right-clicks on a taskbar icon of an interop-enabled app or a group of such icons:
⚠️ Note that currently the jump list isn't available for web groups.
Configuration
The jump list can be enabled, disabled and configured globally and per app. The app definition will override the global system configuration.
⚠️ Note that the jump list configuration allows you to enable or disable the jump list and configure the predefined actions (e.g., change their names or icons), but in order to add custom jump list categories and actions for your apps, you must use the jump list API.
To configure the jump list system-wide, use the "jumpList"
property of the "windows"
top-level key in the system.json
file of io.Connect Desktop. The following is the default system jump list configuration:
{
"windows": {
"jumpList": {
"enabled": true,
"categories": [
{
"title": "Tasks",
"actions": [
{
"icon": "%GDDIR%/assets/images/center.ico",
"type": "centerScreen",
"singleInstanceTitle": "Center on Primary Screen",
"multiInstanceTitle": "Center all on Primary Screen"
}
]
}
]
}
}
}
The "jumpList"
object has the following properties:
Property | Type | Description |
---|---|---|
"categories" |
object[] |
Categorized lists with actions to execute when the user clicks on them. |
"enabled" |
boolean |
If true (default), will enable the jump list. |
Each object in the "categories"
array has the following properties:
Property | Type | Description |
---|---|---|
"actions" |
object[] |
List of actions contained in the category. |
"title" |
string |
Title of the category to be displayed in the context menu. |
Each object in the "actions"
array has the following properties:
Property | Type | Description |
---|---|---|
"icon" |
string |
Icon for the action to be displayed in the context menu. Must point to a local file. |
"multiInstanceTitle" |
string |
Title of the action to be displayed in the context menu when there are multiple instances with grouped taskbar icons. |
"singleInstanceTitle" |
string |
Title of the action to be displayed in the context menu when there is a single instance with a single taskbar icon. |
"type" |
string |
Type of the predefined action to execute. |
To override the system configuration per app, use the "jumpList"
property of the "details"
top-level key in the app definition file. The following example demonstrates how to disable the jump list for an app:
{
"title": "My App",
"type": "window",
"name": "my-app",
"details": {
"url": "https://downloadtestfiles.com/",
"jumpList": {
"enabled": false
}
}
}
Predefined Actions
To use a predefined action, set the "type"
property of the action object to the respective value (see Jump List > Configuration). The following are the currently supported predefined actions:
"centerScreen"
- centers an app or a group of app instances on the primary screen. This action is extremely useful when you have many windows open on multiple displays and can't find the app you need. Use this action to find an app that: you may have moved to another screen or outside the screen bounds altogether; may be hidden behind other windows; may have been resized and become too small to notice; or may have simply blended visually with other apps:
"newWorkspace"
- opens a new Workspace. This action by default is part of the jump list for the Workspaces App. Clicking on the action opens a new empty Workspace in the last opened instance of the Workspaces App. If this action is part of the jump list for another app and the Workspaces App isn't currently open when the user clicks on the action, it will be started:
Jump List API
The jump list API is accessible through the IOConnectWindow
object which describes an instance of an io.Connect Window:
const myWindow = io.windows.my();
// Check whether the jump list is enabled for the current window.
const isJumpListEnabled = await myWindow.jumpList.isEnabled();
Enable or Disable the Jump List
To enable or disable the jump list dynamically, use the setEnabled()
method and pass a Boolean value as an argument:
const myWindow = io.windows.my();
// Checking whether the jump list is enabled for the current window.
const isJumpListEnabled = await myWindow.jumpList.isEnabled();
if (!isJumpListEnabled) {
// Enabling the jump list.
await myWindow.jumpList.setEnabled(true);
};
Categories
Jump list categories are used for grouping actions in a section under a common name. You can find a category by name, get a list of all available categories, create a new category or remove an existing one. The categories API is accessible through the jumpList.categories
object.
To find a category by name, use the find()
method:
const myCategory = await myWindow.jumpList.categories.find("My Category");
To get a list of all available categories, use the list()
method:
const categoryList = await myWindow.jumpList.categories.list();
To create a category, use the create()
method. Pass a title for the category and a list of JumpListActionSettings
objects describing the actions in the category:
// Category settings.
const title = "My Category";
const actions = [
{
// Icon for the action. Must point to a local file.
icon: "../images/action-one.ico",
// Callback that will be executed when the user clicks on the action.
callback: () => console.log("Action 1"),
// Title of the action when there is a single instance with a single taskbar icon.
singleInstanceTitle: "Execute Action 1",
// Title of the action when there are multiple instances with grouped taskbar icons.
multiInstanceTitle: "Execute Action 1 for All"
},
{
icon: "../images/action-two.ico",
callback: () => console.log("Action 2"),
singleInstanceTitle: "Execute Action 2",
multiInstanceTitle: "Execute Action 2 for All"
}
];
// Creating a category.
await myWindow.jumpList.categories.create(title, actions);
To remove a category, use the remove()
method and pass the category title as an argument:
await myWindow.jumpList.categories.remove("My Category");
Actions
Each JumpListCategory
object has an actions
property through which you can access the actions API. You can create, remove or list all available actions in the current category.
To get a list of all available actions in a category, use the list()
method:
const myCategory = await myWindow.jumpList.categories.find("My Category");
const actions = await myCategory.actions.list();
To create an action in a category, use the create()
method. Pass a list of JumpListActionSettings
objects describing the actions.
The following example demonstrates creating an action in the "Tasks" category that will toggle the io.Connect theme:
// Finding a category.
const category = await myWindow.jumpList.categories.find("Tasks");
// Action settings.
const actions = [
{
icon: "../images/toggle-theme.ico",
// This action will toggle the io.Connect theme.
callback: async () => {
const currentTheme = await io.themes.getCurrent();
if (currentTheme.name === "dark") {
io.themes.select("light");
} else {
io.themes.select("dark");
};
},
singleInstanceTitle: "Toggle Theme",
multiInstanceTitle: "Toggle Theme"
}
];
// Creating actions for an existing category.
await category.actions.create(actions);
To remove one or more actions from a category, use the remove()
method and pass a list of JumpListActionSettings
objects to remove:
const actions = [
{
icon: "../images/action-one.ico",
callback: () => console.log("Action 1"),
singleInstanceTitle: "Execute Action 1",
multiInstanceTitle: "Execute Action 1 for All"
},
{
icon: "../images/action-two.ico",
callback: () => console.log("Action 2"),
singleInstanceTitle: "Execute Action 2",
multiInstanceTitle: "Execute Action 2 for All"
}
];
// Removing actions from a category.
await category.actions.remove(actions);
Hotkeys
The Hotkeys API allows apps to register key combinations and receive notifications when a key combination is pressed by the user irrespective of whether the app is on focus or not. Hotkeys are useful for web apps that don't have access to system resources and can't register global shortcuts.
Configuration
You can control the hotkeys behavior from the "hotkeys"
top-level key in the system.json
file located in the %LocalAppData%/interop.io/io.Connect Desktop/Desktop/config
folder.
Hotkeys configuration example:
{
"hotkeys": {
"enabled": true,
"blacklist": ["appManager"],
"reservedHotkeys": ["ctrl+c", "ctrl+p", "ctrl+s"]
}
}
The "hotkeys"
object has the following properties:
Property | Type | Description |
---|---|---|
"enabled" |
boolean |
If true , hotkeys will be enabled. |
"blacklist" |
string[] |
List of names of apps that won't be able to register hotkeys. |
"reservedHotkeys" |
string[] |
List of reserved (system or other) hotkeys that app won't be able to override. |
"whitelist" |
string[] |
List of names of apps that will be able to register hotkeys. |
Hotkeys API
The Hotkeys API is accessible through the io.hotkeys
object.
To register a hotkey, use the register()
method:
// Define a hotkey.
const hotkeyDefinition = {
hotkey: "shift+alt+c",
description: "Open Client Details"
};
// This function will be invoked when the hotkey is pressed.
const hotkeyHandler = () => {
io.appManager.application("Client Details").start();
};
// Register the hotkey.
await io.hotkeys.register(hotkeyDefinition, hotkeyHandler);
To remove a hotkey, use the unregister()
and pass the value of the hotkey combination as an argument:
await io.hotkeys.unregister("shift+alt+c");
To remove all hotkeys registered by your app, use the unregisterAll()
method:
await io.hotkeys.unregisterAll();
To check if your app has registered a specific hotkey, use the isRegistered()
method:
// Returns a Boolean value.
const isRegistered = io.hotkeys.isRegistered("shift+alt+c");
Hotkeys View
There is a utility view that allows you to see all hotkeys registered by different apps. You can open it from the io.Connect Desktop 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:
For a complete list of the available Hotkeys API methods and properties, see the Hotkeys API Reference Documentation.
Displays
io.Connect Desktop provides a way for apps 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.
Configuration
To enable display capturing you must add the "allowCapture"
property to your app definition file and set it to true
.
{
"name": "MyApp",
"type": "window",
"allowCapture": true,
"details": {
"url": "http://localhost:3000"
}
}
Displays API
The Displays API is accessible through the io.displays
object.
All Displays
To get all displays, use the all()
method. It returns an array of all available Display
objects:
const allDsiplays = await io.displays.all();
Primary Display
You can get the primary display with the getPrimary()
method:
// Returns the primary display.
const primaryDisplay = await io.displays.getPrimary();
Example of finding and capturing the primary display:
const display = await io.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 resolves with a Display
object:
const displayID = 2528732444;
// returns a display by ID
const display = await io.displays.get(displayID);
The Display Object
The Display
object has the following properties:
Property | Description |
---|---|
aspectRatio |
Display aspect ratio (e.g., 16:9). |
bounds |
A Bounds object with height , width , left and top properties, describing the bounds of the display. |
dpi |
Dots per inch resolution of the display. |
id |
Unique identifier associated with the display. |
index |
Index assigned to the display by the operating system. |
isPrimary |
A boolean value specifying whether this is the primary display. |
name |
Name assigned to the display by the operating system. |
scaleFactor |
The scale factor of the returned display (e.g., 1.25 = 125%). |
workArea |
A Bounds object describing the working area of the display (the desktop area, excluding taskbars, docked windows and toolbars). |
Capturing All Displays
To capture all displays, use the captureAll()
method. It accepts a CaptureAllOptions
object and returns a Base64 encoded string or an array of Base64 encoded strings depending on the specified combined
option.
The following example demonstrates how to 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 io.displays.captureAll({ combined: true, size: { width: 2000 } });
The CaptureAllOptions
object has the following properties:
Property | Type | Description |
---|---|---|
combined |
boolean |
Required. If true , will return a single image of all captured displays. If false , will return separate images for all captured displays. |
size |
object |
Optional. Accepts either a ScaleOptions or an AbsoluteSizeOptions object, specifying the size of the output image. |
Capturing Single Displays
To capture a single display, use the capture()
method at top level of the API or on a Display
instance.
When you use the capture()
method at top level of the API, pass a CaptureOptions
object. The following example demonstrates how to use the display ID to find and capture the desired display and also how to 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:
const displayID = 2528732444;
const captureOptions = {
id: displayID,
size: { scale: 0.5 }
}
const screenshot = await io.displays.capture(captureOptions);
The CaptureOptions
object has the following properties:
Property | Type | Description |
---|---|---|
id |
number |
Required. ID of the targeted display. |
size |
object |
Optional. Accepts either a ScaleOptions or an AbsoluteSizeOptions object, specifying the size of the output image. |
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:
Property | Type | Description |
---|---|---|
height |
number |
Specifies the height of the output image. Defaults to the captured display height. |
keepAspectRatio |
boolean |
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. |
width |
number |
Specifies the width of the output image. Defaults to the captured display width. |
When you use the capture()
method of a Display
instance, pass either a ScaleOptions
or an AbsoluteSizeOptions
object, specifying the size of the output image. The following example demonstrates how to find and capture all non-primary displays:
const screenshots = await Promise.all(
// Get all displays.
(await io.displays.all())
// Filter out the primary display.
.filter(display => !display.isPrimary)
.map(display => display.capture({ scale: 0.5 })));
Capturing Windows & Window Groups
You can use the capture()
method of an io.Connect Window instance or an io.Connect Window group to capture the respective window or window group. This method works also for minimized windows and window groups but doesn't work for hidden windows.
// Capture the current window.
const windowScreenshot = await io.windows.my().capture();
// Capture the current group.
const groupScreenshot = await io.windows.groups.my.capture();
Events
The onDisplayChanged()
method allows you to handle the event that fires when a display has been modified - its resolution or position has changed, a display has been connected or disconnected, etc. Pass a handler that will be invoked each time a display changes and use the list of Display
objects that it receives as an argument to react to the changes:
const handler = (displays) => {
// React to DPI changes, display connected or disconnected, monitor position changed, etc.
console.log(displays);
};
io.displays.onDisplayChanged(handler);
For a complete list of the available Displays API methods and properties, see the Displays API Reference Documentation.
Logging
io.Connect Desktop offers a Logger API which enables JavaScript apps to create a hierarchy of sub-loggers mapped to app 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 or an external output (usually a rolling file on the desktop, but actually any target the log4net
library supports).
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.
For details on how to customize the system logging mechanisms of io.Connect Desktop, see the Developers > System > Logging section.
Configuration
Logging for apps in io.Connect Desktop is disabled by default. To allow it, use the "allowLogging"
top-level key in the app definition file:
{
"allowLogging": true
}
Logger API
The Logger API is accessible through the io.logger
object.
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 app 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 interop-enabled apps, create a logger instance with the subLogger()
method and assign the logger a name:
const logger = io.logger.subLogger("main-component");
Next, 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, either use the log()
method of the logger instance, or the respective logging level methods - error()
, trace()
, etc.
// The log() method accepts a message and logging level as arguments.
logger.log("Couldn't load component!", "error");
// or
// Each logging level method accepts only a message as an argument.
logger.error("Couldn't load component!");
For a complete list of the available Logger API methods and properties, see the Logger API Reference Documentation.
Location & Output
User app log files are located in the %LocalAppData%/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/logs/applications
folder, where <ENV>-<REG>
represents the environment and region of io.Connect Desktop (e.g., DEMO-INTEROP.IO
). A separate log file is created for each app that has logging enabled. The file is named after the app and is created after the app starts to output log entries. All instances of an app 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>
The following example demonstrates an actual log entry:
[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
System Logs
Streaming & Consuming
You can configure io.Connect Desktop to stream the system logs so that they can be consumed by your apps. You can specify the log level and the interval at which the logs to be streamed. Use the "streaming"
property of the "logging"
top-level key in the system.json
system configuration file of io.Connect Desktop to specify the log streaming configuration:
{
"logging": {
"streaming": {
"enabled": true,
"minLevel": "warn",
"interval": 60
}
}
}
The "streaming"
object has the following properties:
Property | Type | Description |
---|---|---|
"enabled" |
boolean |
If true , will enable streaming system log entries. Defaults to false . |
"interval" |
number |
Interval in seconds at which the log entries will be streamed. Defaults to 120 . |
"minLevel" |
"error" | "warn" | "info" |
The minimum level of the log entries to be streamed. Defaults to "error" . |
To consume the log entries in your apps, you must implement and register an Interop method named "T42.Logs.Listen"
. This method will be invoked whenever io.Connect Desktop streams the system logs. The method handler will receive an object with an entries
property as an argument which holds an array of objects each describing the individual log entries:
const name = "T42.Logs.Listen";
const handler = logs => logs.entries.forEach(e => console.log(e.source, e.logEntry));
await io.interop.register(name, handler);
Each log entry has the following properties:
Property | Type | Description |
---|---|---|
logEntry |
object |
A LoggingEvent object as described in the log4js-node types. |
source |
"application" | "bridge" | "gw" |
Source of the system log entry. Log entries may come from the io.Connect Desktop app itself, from the internal window management app, or from the io.Connect Gateway. |
Log Files
Available since io.Connect Desktop 9.3
To specify settings for handling the system log files, use the "files"
property of the "logging"
top-level key in the system.json
file:
{
"logging": {
"files": {
"onStartup": "archive",
"moveOldTo": "%LocalAppData%/my-org/logs"
}
}
}
The "files"
object has the following properties:
Property | Type | Description |
---|---|---|
"moveOldTo" |
string |
Absolute path pointing to the location where the log files from the previous session (if any) will be moved on startup of io.Connect Desktop. You can use environment variables. Defaults to "%GLUE-USER-DATA%/logs/archive" . |
"onStartup" |
string |
Specifies how to handle the log files on system startup. Set to "archive" to archive the existing log files. Set to "delete" to delete the existing log files. Set to "keep" (default) to leave the existing log files intact. |
⚠️ Note that by design the
gilding.log
file won't be archived or deleted.
Logger API
The Logger API is accessible through the io.logger
object.
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-separated string containing all names of the loggers constituting an hierarchy line from the base logger (the app 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 interop-enabled apps, create a logger instance with the subLogger()
method and assign the logger a name:
const logger = io.logger.subLogger("main-component");
Next, 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, either use the log()
method of the logger instance, or the respective logging level methods - error()
, trace()
, etc.
// The log() method accepts a message and logging level as arguments.
logger.log("Couldn't load component!", "error");
// or
// Each logging level method accepts only a message as an argument.
logger.error("Couldn't load component!");
For a complete list of the available Logger API methods and properties, see the Logger API Reference Documentation.
Cookies
Web apps can retrieve, filter, set and remove cookies programmatically by using the io.Connect Cookies API.
Configuration
By default, interop-enabled web apps aren't allowed to manipulate cookies. To allow an app to manipulate cookies, use the "allowCookiesManipulation"
property of the "details"
top-level key in the app definition file:
{
"details": {
"allowCookiesManipulation": true
}
}
Cookies API
The Cookies API is accessible through the io.cookies
object.
Get
To retrieve all cookies, use the get()
method:
const allCookies = await io.cookies.get();
The get()
method returns a list of Cookie
objects.
To filter the cookies, pass a CookiesGetFilter
object with the properties which you want to use as a filter.
The following example demonstrates filtering cookies by domain:
const filter = { domain: "interop.io" };
// Get a list of cookies for the same domain.
const filteredCookies = await io.cookies.get(filter);
The CookiesGetFilter
object has the following optional properties, which you can use in any combination to filter the cookies:
Property | Type | Description |
---|---|---|
domain |
string |
Retrieves the cookies whose domains match or are subdomains of the specified domain. |
name |
string |
Filters the cookies by name. |
path |
string |
Retrieves the cookies whose path matches the specified path. |
secure |
boolean |
Filters cookies by their Secure attribute. |
session |
boolean |
If true , will return only the session cookies. If false , will return only the persistent cookies. |
url |
string |
Retrieves the cookies which are associated with the specified URL. If not specified, will retrieve the cookies for all URLs. |
Set
To create a cookie, use the set()
method. It accepts as a required argument a CookiesSetDetails
object with a required url
property:
const cookie = {
url: "https://example.com",
name: "MyCookie",
value: "42"
};
await io.cookies.set(cookie);
The CookiesSetDetails
object has the following properties:
Property | Type | Description |
---|---|---|
domain |
string |
Domain for the cookie. Will be normalized with a preceding dot in order to be valid for subdomains too. |
expirationDate |
number |
The expiration date of the cookie as a number of seconds since the UNIX epoch. If not specified, the cookie will become a session cookie and won't be persisted between sessions. |
httpOnly |
boolean |
If true , the cookie will be marked with an HttpOnly attribute. Default is false . |
name |
string |
Name for the cookie. |
path |
string |
Path for the cookie. |
sameSite |
"unspecified" | "no_restriction" | "lax" | "strict" |
The value to be applied to the SameSite attribute. If set to "no_restriction" , the secure property will be set automatically to true . Default is "lax" . |
secure |
boolean |
If true , the cookie will be marked with a Secure attribute. Default is false , unless the SameSite attribute has been set to None . |
url |
string |
Required. URL to associate with the cookie. |
value |
string |
Value for the cookie. |
Remove
To remove a cookie, use the remove()
method and pass the cookie URL and name:
const url = "https://example.com";
const name = "MyCookie";
await io.cookies.remove(url, name);
Dialogs
io.Connect Desktop offers default confirmation dialogs that will be shown on system shutdown or restart and when a window that prevents closing is about to be closed:
Configuration
The default dialogs are configurable via the "dialogs"
top-level key in the system.json
system configuration file of io.Connect Desktop. You can specify size for them, disable them, or provide a URL pointing to you own custom dialog app to be used by io.Connect Desktop:
{
"dialogs": {
"url": "https://my-custom-dialog.com",
"width": 380,
"height": 150,
"enableDefaultDialogs": {
"preventShutdown": false,
"preventWindowClose": false
}
}
}
The "dialogs"
object has the following properties:
Property | Type | Description |
---|---|---|
"enableDefaultDialogs" |
object |
Enable or disable the default io.Connect dialog messages. |
"height" |
number |
Height in pixels for the io.Connect dialogs. |
"transparent" |
boolean |
If true , the io.Connect Window containing the dialog will be transparent. |
"url" |
string |
URL pointing to the location of the io.Connect dialog app. |
"width" |
number |
Width in pixels for the io.Connect dialogs. |
The "enableDefaultDialogs"
object has the following properties:
Property | Type | Description |
---|---|---|
"preventShutdown" |
boolean |
If true (default), will enable the dialog message that appears when io.Connect Desktop is about to shutdown. |
"preventWindowClose" |
boolean |
If true (default), will enable the dialog message that appears when the user tries to close an io.Connect Window that is programmatically prevented from closing. This dialog will appear also when such window participates in a Layout that is being closed. |
"unsavedLayoutChanges" |
boolean |
If true (default), will enable the dialog message that appears when the user modifies the current Global Layout and tries to restore another Global Layout. Available since io.Connect Desktop 9.2. |
Using Dialogs Programmatically
The showDialog()
method of the IOConnectWindow
object allows you to show dialogs at runtime. It accepts a DialogOptions
object as an argument in which you can specify dialog options - select a predefined io.Connect dialog type and fine-tune it, or create a completely customized one. The only required options are type
and message
for the dialog to show.
Predefined Dialogs
The following dialog types are available:
Dialog Type | Description |
---|---|
"SingleInputDialog" |
Contains an input field, "Save" and "Don't Save" buttons. |
"Ok" |
Contains an "OK" button. |
"OkCancel" |
Contains "OK" and "Cancel" buttons. |
"YesNo" |
Contains "Yes" and "No" buttons. |
"YesNoCancel" |
Contains "Yes", "No" and "Cancel" buttons. |
The following example demonstrates using a predefined io.Connect dialog:
const myDialog = {
type: "SingleInputDialog",
title: "Email Required",
message: "Please, provide your email address:",
inputPlaceholder: "john.doe@example.com",
inputPattern: "[a-z0-9]@my-org.com",
inputPatternErrorMessage: "Invalid email address!"
};
await myWindow.showDialog(myDialog);
Custom Dialogs
The following example demonstrates creating a custom dialog using the options provided in the DialogOptions
object:
const myDialog = {
type: "MyCustomDialog",
title: "Custom Title",
message: "Custom Message",
showTimer: true,
timerDuration: 5,
size: { height: 158 },
showAffirmativeButton: true,
affirmativeButtonName: "Confirm"
};
await myWindow.showDialog(myDialog);
Dialog Mode
The DialogOptions
object has an optional mode
property which determines the blocking behavior of the dialog. The mode
property is of type DialogMode
which is an enumeration with two possible values:
Value | Description |
---|---|
"Global" |
All visible containers (including frameless io.Connect Windows) will be blocked for user interaction. |
"WindowContainer" |
Only the container (a Workspaces Frame, or an io.Connect Window group) of the window that is showing the dialog will be blocked for user interaction. All windows within a blocked container are blocked too. |
const myDialog = {
type: "MyCustomDialog",
title: "Custom Title",
message: "Custom Message",
// Will block all visible window containers for user interaction.
mode: "Global"
};
await myWindow.showDialog(myDialog);
Functionality
To provide functionality to the dialog buttons or react when the user closes the dialog, use the DialogResult
object returned from showing the dialog. The result is returned when the user clicks on a dialog button or closes the dialog.
The following example demonstrates showing a predefined io.Connect dialog with "OK" and "Cancel" buttons and responding to the user interaction:
const myDialog = {
type: "OkCancel",
title: "My Dialog Title",
message: "My dialog message."
};
const handleDialogResult = (action, button) => {
if (action === "closed") {
// React to user closing the dialog.
console.log("Dialog closed.");
return;
} else {
if (button === "affirmative") {
// React to user clicking the "OK" button.
console.log("OK button clicked.");
} else {
// React to user clicking the "Cancel" button.
console.log("Cancel button clicked.");
};
};
};
const { action, button } = await myWindow.showDialog(myDialog);
handleDialogResult(action, button);
Zooming
io.Connect Desktop supports zooming in and out of windows of JavaScript apps. Zooming can be controlled via configuration (system-wide or per app) or programmatically via the available methods/properties of a window instance.
You can zoom in and out of windows in several ways:
CTRL + =
(zoom in) andCTRL + -
(zoom out);CTRL + MOUSE SCROLL
;CTRL + 0
- resets to the default zoom factor;- mouse pad gestures;
- using the right-click context menu (if enabled);
⚠️ Note that zooming is based on domain - i.e., if you open two apps with the same domain and change the zoom factor of one of them, the zoom factor of the other will change accordingly.
⚠️ Note that if your app logic includes both zooming a window and retrieving its size with the
window.innerHeight
orwindow.innerWidth
DOM properties, you have to consider the fact that the browser will report adjusted size values based on the zoom factor. In such cases, it's recommended to usewindow.outerHeight
andwindow.outerWidth
, or thebounds
property of anIOConnectWindow
instance.
Configuration
You can configure window zooming globally from the system.json
system configuration file of io.Connect Desktop located in the %LocalAppData%/interop.io/io.Connect Desktop/Desktop/config
folder. Use the "zoom"
property of 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
}
}
}
The "zoom"
object has the following properties:
Property | Type | Description |
---|---|---|
"defaultFactor" |
number |
Default zoom factor within the range of 25 to 500 . Avoid negative values. Defaults to 100 . |
"enabled" |
boolean |
If true (default), will enable zooming. |
"factors" |
number[] |
List of 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 behavior. Defaults to [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500] . |
"mouseWheelZoom" |
boolean |
If true , will enable zooming with CTRL + mouse scroll . Defaults to false . |
You can also enable zooming per app from the app definition, which will override the global zoom configuration. Use the "zoom"
property of the "details"
top-level key:
[
{
"title": "My App",
"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
}
}
}
]
Using Zoom Programmatically
There are several methods and properties exposed on the window instance, which you can use to control zoom behavior.
Get the current zoom factor:
const myWindow = io.windows.my();
console.log(myWindow.zoomFactor);
Zoom in:
// Will zoom in the window to the next factor in the "factors" array.
await myWindow.zoomIn();
Zoom out:
// Will zoom out the window to the previous factor in the "factors" array
await myWindow.zoomOut();
Set a desired zoom factor:
await myWindow.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 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.
Listening for zoom factor changes:
// Returns a function which you can use to unsubscribe from events for zoom factor changes.
const unsubscribe = myWindow.onZoomFactorChanged(w => {
console.log(`Zoom factor changed to ${w.zoomFactor}`)
});
unsubscribe();
Downloads
io.Connect Desktop allows for files to be downloaded in io.Connect Windows. Users can pause and cancel downloads, and open the location of completed downloads by clicking on them.
Available since io.Connect Desktop 9.2
The io.Connect Download Manager is a central place for managing all downloads. It maintains and displays a list of ongoing, paused, completed, and canceled downloads (download items). Users can pause, resume or cancel downloads from it, open the location of a downloaded file, clear the list of downloads or remove individual download items from it, search for downloads, set the default location for downloading files. The Download Manager can be started via a configurable keyboard shortcut (CTRL + J
by default), and can also be configured to open automatically when a download is initiated. Programmatic changes to download items are reflected in the Download Manager.
Configuration
Download configuration settings are available both for downloading files in io.Connect Windows and for the io.Connect Download Manager.
io.Connect Windows
The window download behavior is controlled globally via the system.json
system configuration file of io.Connect Desktop located in the %LocalAppData%/interop.io/io.Connect Desktop/Desktop/config
folder. You can alternatively override the download behavior per app in the app definition.
To specify global download settings for all io.Connect Windows, use the "downloadSettings"
property of the "windows"
top-level key:
{
"windows": {
"downloadSettings": {
"autoSave": true,
"autoOpenPath": false,
"autoOpenDownload": false,
"enable": true,
"enableDownloadBar": true,
"path": "%DownloadsFolder%"
}
}
}
The "downloadSettings"
object has the following properties:
Property | Type | Description |
---|---|---|
"autoOpenDownload" |
boolean |
If true , will open the download file after the download is completed. Defaults to false . |
"autoOpenPath" |
boolean |
If true , will open the folder that contains the downloaded file after the download is completed. Defaults to false . |
"autoSave" |
boolean |
If true (default), will auto save the file (without asking the user where to save it). If false , a system save dialog will appear. |
"enable" |
boolean |
If true (default), will enable the window to download files. |
"enableDownloadBar" |
boolean |
If true (default), a download bar tracking the download progress will appear at the bottom of the window. If false , the download process will be invisible. |
"path" |
string |
Location where the downloaded file will be saved. Due to security reasons, there are only two possible locations for downloads: the Windows "Temp" or "Downloads" folder. Defaults to "%DownloadsFolder%" . |
To override the default system download behavior per app in the app definition, use the "downloadSettings"
property of the "details"
top-level key:
{
"details": {
"downloadSettings": {
"autoSave": false
}
}
}
Download Manager
Available since io.Connect Desktop 9.2
To configure the Download Manager of io.Connect Desktop, use the "downloadManager"
top-level key in the system.json
system configuration file:
{
"downloadManager": {
"autoStartOnDownload": true,
"shortcut": "ctrl+alt+d"
}
}
The "downloadManager"
object has the following properties:
Property | Type | Description |
---|---|---|
"appName" |
string |
Name of an io.Connect app, as specified in its definition, to be used as a Download Manager. Defaults to "io-connect-download-manager" . |
"autoStartOnDownload" |
boolean |
If true , the Download Manager app will be started automatically when a download is initiated. Defaults to false . |
"shortcut" |
string |
Shortcut for starting the Download Manager app. Defaults to "ctrl+j" . |
Using Downloads Programmatically
To download a file programmatically from an io.Connect Window, use the download()
method of an IOConnectWindow
instance. Pass a URL to the file to download and an optional DownloadOptions
object:
const myWindow = io.windows.my();
const url = "https://example.com/logo.png";
// Optional download settings.
const options = {
autoOpenDownload: true,
// The file extension is taken from the downloaded file.
name: "my-logo"
};
const { path, size, url } = await myWindow.download(url, options);
console.log(`Download path: ${path}, File size: ${size}, URL: ${url}`);
The method returns a DownloadResult
object containing the path to the downloaded file, the file size and the download URL.
Available since io.Connect Desktop 9.2
The downloads
property of the iodesktop
object injected in the global window
object allows you to programmatically control the download items of the Download Manager and to retrieve and set the default location for downloads.
To retrieve or set the default download location, use the getSavePath()
and the setSavePath()
methods:
// Get the current location for downloaded files.
const currentPath = await iodesktop.downloads.getSavePath();
// Set the location for downloaded files.
await iodesktop.downloads.setSavePath("C:\\Users\\Me\\Desktop");
To get a list of all download items available in the Download Manager, use the list()
method:
const downloads = await iodesktop.downloads.list();
The list()
method resolves with a list of DownloadItem
objects, each with the following properties:
Property | Type | Description |
---|---|---|
"id" |
string |
ID of the download item. |
"displayInfo" |
object |
Information about the download item. |
The "displayInfo"
object has the following properties:
Property | Type | Description |
---|---|---|
"filename" |
string |
Name of the download item. |
"receivedBytes" |
number |
Bytes from the download item already received. |
"speed" |
number |
Download speed in bits per second. |
"startTime" |
number |
Download start time in seconds since the UNIX epoch. |
"state" |
"progressing" | "paused" | "completed" | "interrupted" | "cancelled" |
Current state of the download. |
"timeRemaining" |
number |
Computed remaining time in seconds for the download to complete. |
"totalBytes" |
number |
Total size in bytes of the download item. |
"url" |
string |
Download URL. |
To manipulate download items, use the pauseResume()
and removeItem()
methods and pass the ID of the download item as an argument:
const id = "13534_56";
// If the download is paused, it will be resumed and vice versa.
await iodesktop.downloads.pauseResume(id);
// Remove the download item from the downloads list.
await iodesktop.downloads.removeItem(id);
To get notified of download item state changes, use the onUpdate()
method and pass a callback for handling the event. The callback will receive a DownloadItem
object as an argument. The event will be fired each time a chunk of any download item has been downloaded:
const handler = item => console.log(`State of download with ID ${item.id} is "${item.displayInfo.state}".`);
iodesktop.downloads.onUpdate(handler);
To clear all items from the download list, use the clearDownloadList()
method:
await iodesktop.downloads.clearDownloadList();
To open the location of a downloaded item, use the showInFolder()
method and pass the ID of the download item as an argument:
const id = "13534_56";
await iodesktop.downloads.showInFolder(id);
Environment Variables
io.Connect apps can be allowed runtime access to the available environment variables through configuration.
Configuration
To allow an app to access environment variables, use the "allowEnvVars"
property of the "details"
top-level key in the app definition:
{
"details": {
"allowEnvVars": true
}
}
Runtime Access
To access the available environment variables at runtime, use the env
property of the iodesktop
object injected in the global window
object. The env
property is an object containing all environment variables as properties:
const envVars = iodesktop.env;
Object.entries(envVars).forEach((envVar) => {
const [envVarName, envVarValue] = envVar;
console.log(`${envVarName}: "${envVarValue}"`);
});
Request Headers
You can allow io.Connect web apps to manipulate the headers for web requests at runtime.
Configuration
To allow web apps to manipulate request headers at runtime, use the "allowHeadersManipulation"
top-level key in the app definition:
{
"allowHeadersManipulation": true
}
Runtime Manipulation
To manipulate the request headers for web requests at runtime, use the customHeaders
property of the iodesktop
object injected in the global window
object.
To set custom request headers, use the set()
method. You can use the returned header ID later to retrieve or remove the header:
const header = { "My-Custom-Header": "custom-header-value" };
const headerId = await iodesktop.customHeaders.set(header);
You can also supply a web request filter as a second argument to set()
, specifying which requests to target:
const header = { "My-Custom-Header": "custom-header-value" };
const filter = {
urls: ["https://my-app.com/assets/*"],
applications: ["my-app"],
types: ["mainFrame", "image", "stylesheet"]
};
const headerId = await iodesktop.customHeaders.set(header, filter);
The filter object has the following properties:
Property | Type | Description |
---|---|---|
applications |
string[] |
Array of io.Connect app names. The headers of all web requests sent from the specified apps will be modified. |
types |
string[] |
Array of web request types. The possible array item values are "mainFrame" , "subFrame" , "stylesheet" , "script" , "image" , "font" , "object" , "xhr" , "ping" , "cspReport" , "media" , "webSocket" and "other" . You can target requests originating from the main frame or the sub frames, or specify the content type of the targeted web request. |
urls |
string[] |
Array of URLs. The headers of all web requests sent to the specified URLs will be modified. You can use the * wildcard symbol in the URL. |
To retrieve all custom request headers, use the getAll()
method:
const allCustomHeaders = await iodesktop.customHeaders.getAll();
To retrieve a specific header, use the get()
method and pass its ID as an argument:
const header = await iodesktop.customHeaders.get(headerId);
To remove all custom request headers, use the removeAll()
method:
await iodesktop.customHeaders.removeAll();
To remove a specific header, use the remove()
method and pass its ID as an argument:
await iodesktop.customHeaders.remove(headerId);
Proxy Settings
You can configure the proxy settings on a system level for all users, or allow io.Connect apps to manipulate them at runtime if different user groups must use different proxy settings.
Configuration
Available since io.Connect Desktop 9.3
⚠️ Note that the following proxy settings are fully aligned with the Electron proxy settings. For more details about the available settings and example usage, see the Electron documentation. If you are experiencing unresolvable problems with the Electron proxy settings, you can try using the settings described in the Legacy Settings section.
The proxy settings can be changed from the "proxy"
top-level key in the system.json
system configuration file of io.Connect Desktop:
{
"proxy": {
"mode": "pac_script",
"pacScript": "https://my-pac-script.js"
}
}
The "proxy"
object has the following properties:
Property | Type | Description |
---|---|---|
"legacy" |
object |
Legacy io.Connect proxy settings. |
"mode" |
"direct" | "auto_detect" | "pac_script" | "fixed_servers" | "system" |
Proxy mode. |
"pacScript" |
string |
URL pointing to a proxy auto-configuration script (PAC). |
"proxyBypassRules" |
string |
Rules indicating which URLs should bypass the proxy settings. |
"proxyRules" |
string |
Rules indicating which proxies to use. |
To allow an app to manipulate proxy settings at runtime, use the "allowProxySettingManipulation"
property of the "details"
top-level key in the app definition file:
{
"details": {
"allowProxySettingManipulation": true
}
}
Legacy Settings
⚠️ Note that the following properties that used to be under the
"proxy"
top-level key are now moved to the"legacy"
object. These settings should be used only if you are experiencing unresolvable problems with the proxy settings which are now fully aligned with Electron proxy settings and are described in the previous section.
The "legacy"
object has the following properties:
Property | Type | Description |
---|---|---|
"autodetectTimeoutMs" |
number |
Interval in milliseconds to wait for response when attempting to detect a PAC script. |
"bypassRules" |
string |
Semicolon-separated list of host patterns that will always use direct connection. For syntax, see the Electron Set Proxy Config documentation. |
"pacScript" |
string |
URL to a proxy auto-configuration script (PAC). |
"rules" |
string |
Semicolon-separated list of proxy rules. For syntax, see the Electron Set Proxy Config documentation. |
"url" |
string |
Proxy URL to use. |
"useSystemSettings" |
boolean |
If true (default), will use the OS proxy settings. |
Runtime Manipulation
To manipulate the proxy settings at runtime, use the iodesktop
object injected in the global window
object:
const settings = {
mode: "pac_script",
pacScript: "https://my-pac-script.js"
};
// Set proxy settings.
iodesktop.setProxySettings(settings);
// Get proxy settings.
const proxySettings = await iodesktop.getProxySettings();
The object passed as an argument to setProxySettings()
has the same shape as the "proxy"
object described in the Configuration section.
OS Info
You can allow apps to access OS information (list of running processes, OS version, io.Connect start time) through their app definition. The information can then be retrieved through the iodesktop
object injected in the global window
object when the app is started.
Configuration
To allow an app to access OS information, set the "allowOSInfo"
property to true
in the "details"
top-level key:
{
"details": {
"allowOSInfo": true
}
}
Runtime Access
To retrieve the necessary OS information, use the iodesktop
object injected in the global window
object:
// Returns a list of all running processes.
const processes = await iodesktop.os.getProcesses();
// Extracting the PID, name and start time of the first process from the list.
const { pid, name, startTime } = processes[0];
// Returns the OS version as a string.
const version = iodesktop.os.getVersion();
// Returns the io.Connect start time as a string - e.g., "2021-10-20T06:54:49.411Z".
const startTime = iodesktop.glue42StartTime;
Clearing DNS & HTTP Cache
To allow an app to clear the DNS or HTTP cache, use the "allowClearingCache"
top-level key in the app definition file. Methods for clearing the cache are available on the iodesktop
object injected in the global window
object.
Allowing an app to clear cache:
{
"allowClearingCache": true
}
Clearing HTTP and DNS cache:
// Clearing the HTTP cache.
await iodesktop.clearCache();
// Clearing the DNS cache.
await iodesktop.clearHostResolverCache();
Hide & Show Windows
Available since io.Connect Desktop 9.4
If you need to show or hide a window dynamically (e.g., an authentication app) but don't want to initialize the entire @interopio/desktop
library, use the showWindow()
and hideWindow()
methods of the iodesktop
object injected in the global window
object:
// Hide a window.
await iodesktop.hideWindow();
// Show a hidden window.
await iodesktop.showWindow();