# io.Connect Desktop 9.5

Source: https://docs.interop.io/desktop/getting-started/changelog/platform/9-5/index.html

## io.Connect Desktop 9.5

*Release date: 03.09.2024*

| Components | Version |
|------------|---------|
| Electron | [31.2.0](https://releases.electronjs.org/release/v31.2.0) |
| Chromium | 126.0.6478.127 |
| Node.js | 20.15.0 |

The following libraries are bundled with **io.Connect Desktop** 9.5 and will be used for [auto injection](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/javascript/index.md#auto_injection):

| Injected Library | Version |
|------------------|---------|
| [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop) | [6.7](https://docs.interop.io/desktop/getting-started/changelog/libraries/interopio-desktop/index.md#67-670) |
| [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) | 2.3 |

## New Features

> ### Executing JavaScript Code in a Window
>
> Executing JavaScript code within the context of the current or another io.Connect Window is disabled by default. To enable it, set the `"allowScriptExecution"` top-level key in the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) to `true`:
>
> ```json
> {
>     "allowScriptExecution": true
> }
> ```
>
> To [execute code](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-execute_code) in the context of an io.Connect Window, use the [`executeCode()`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md#IOConnectWindow-executeCode) method of an [`IOConnectWindow`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md) instance. It accepts as a required argument the code to execute provided as a string. The method resolves with the result returned from the executed code, or rejects if the result of the code is a rejected `Promise`:
>
> ```javascript
> // Find the io.Connect Window in which you want to execute the code.
> const ID = "2506_04";
> const ioConnectWindow = io.windows.findById(ID);
> // Provide the code to execute as a string.
> const myCode = "(() => { return 42; })()";
>
> const result = await ioConnectWindow.executeCode(myCode);
>
> console.log(result);
> ```

> ### Splash Screen
>
> The **io.Connect Desktop** [splash screen](https://docs.interop.io/desktop/getting-started/how-to/rebrand-io-connect/user-interface/index.md#splash_screen) by default is shown always on top of any other windows. To disable this behavior, set the `"alwaysOnTop"` property of the `"splash"` top-level key in the `system.json` [system configuration](https://docs.interop.io/desktop/developers/configuration/system/index.md#splash_screen) file to `false`:
>
> ```json
> {
>     "splash": {
>         "alwaysOnTop": false
>     }
> }
> ```

> ### Telemetry Data
>
> You can now instruct **io.Connect Desktop** what type of [telemetry data](https://docs.interop.io/desktop/capabilities/more/features/index.md#telemetry_data-configuration) to gather. To specify the desired telemetry data sets, use the `"features"` property of the `"telemetry"` top-level key in the `system.json` [system configuration](https://docs.interop.io/desktop/developers/configuration/system/index.md) file:
>
> The following example demonstrates how to instruct **io.Connect Desktop** to gather only system telemetry data:
>
> ```json
> {
>     "telemetry": {
>         "enabled": true,
>         "features": {
>             "apps": false,
>             "stores": false,
>             "system": true
>         }
>     }
> }
> ```
>
> The `"features"` object has the following properties:
>
> | Property | Type | Description |
> |----------|------|-------------|
> | `"apps"` | `boolean` | If `true`, will enable publishing telemetry data related to web app performance. |
> | `"stores"` | `boolean` | If `true`, will enable publishing telemetry data related to app stores. |
> | `"system"` | `boolean` | If `true`, will enable publishing telemetry data related to system performance. |

> ### Boot Sequence Start & Completion Signals
>
> To [receive signals](https://docs.interop.io/desktop/capabilities/more/features/index.md#boot_sequence-app_batch_start__completion_signals) from **io.Connect Desktop** when a batch of apps with the same run priority starts and completes loading, register an Interop method and name it `"T42.AppManager.AutoStart.Stage"`. If such method is registered, it will be invoked at the completion of the current priority batch, and then at the start and at the completion of all remaining run priority batches within the current and within all following boot sequence stages:
>
> ```javascript
> const methodName = "T42.AppManager.AutoStart.Stage";
> const handler = ({ stage, phase, runPriority, apps }) => {
>     console.log(`Run priority batch "${runPriority}" in stage "${stage}" is ${phase === "stageStarting" ? "starting" : "completed"}.`);
>
>     console.log(`Apps: ${apps}`);
> };
>
> await io.interop.register(methodName, handler);
> ```
>
> Each invocation of the method will return data in the shape of an object with the following properties:
>
> | Property | Type | Description |
> |----------|------|-------------|
> | `apps` | `string[]` | List of names of the apps participating in the current run priority batch. |
> | `phase` | `"stageStarting"` \| `"stageCompleted"` | Indicates whether the current run priority batch of apps > is starting to load or has completed loading. |
> | `runPriority` | `number` | The run priority value of the current app batch. |
> | `stage` | `"core"` \| `"pre-sso"` \| `"post-sso"` \| `"user"` | The name of the current boot sequence stage. |

> ### Log Appenders per App
>
> By default, **io.Connect Desktop** uses a `multiFile` appender named `"applications"` for logging events related to io.Connect client apps. To define separate [log appenders per app](https://docs.interop.io/desktop/developers/configuration/system/index.md#logging-log_appenders_per_app), execute the following steps:
>
> 1. Define a log appender to be used for your app:
>
> ```json
> {
>     "appenders": {
>         "my-app-appender": {
>             "type": "file",
>             "filename": "%GLUE-USER-DATA%/logs/my-app.log",
>             "maxLogSize": 10485760,
>             "backups": 5,
>             "minLevel": "info",
>             "keepFileExt": true,
>             "compress": true
>         }
>     }
> }
> ```
>
> 2. Create a category with the name of your app as defined in its app definition and assign the log appender to it. This will instruct **io.Connect Desktop** to use the specified log appender for your app:
>
> ```json
> {
>     "categories": {
>         "my-app": {
>             "appenders": [
>                 "my-app-appender"
>             ],
>             "level": "trace"
>         }
>     }
> }
> ```

> ### Controlling Dropping Windows in Workspaces
>
> To specify programmatically whether an io.Connect Window can be [dropped in a Workspace](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-workspace_drop), use the [`setAllowWorkspaceDrop()`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md#IOConnectWindow-setAllowWorkspaceDrop) method of an [`IOConnectWindow`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md) instance. It accepts a Boolean value as an argument determining whether the user will be able to drop the current window in a Workspace:
>
> ```javascript
> // Preventing the user from dropping the window in a Workspace.
> await myWindow.setAllowWorkspaceDrop(false);
> ```
>
> To check whether the current window can be dropped in a Workspace, use the `allowWorkspaceDrop` property of the io.Connect Window object:
>
> ```javascript
> const canBeDropped = myWindow.allowWorkspaceDrop;
>
> console.log(`The current window ${canBeDropped ? "can" : "can't"} be dropped in a Workspace.`);
> ```

> ### Pinning & Unpinning Tabs for Web Groups
>
> The tabs of io.Connect Windows in web groups can now be pinned. Pinned tabs are placed before the regular tab windows and they contain only the window title. Pinned tab windows don't have a "Close" button, effectively preventing the user from closing them:
>
> ![Pinned Tab](https://docs.interop.io/desktop/images/window-management/pinned-tab.png)
>
> ⚠️ *Note that pinning and unpinning window tabs is available only for tab windows in [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups).*
>
> To make your tab window pinned via configuration, use the `"isPinned"` property of the `"details"` top-level key in the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md):
>
> ```json
> {
>     "details": {
>         "isPinned": true
>     }
> }
> ```
>
> To [pin and unpin tab windows](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-pinning__unpinning_tabs) programmatically, use the [`pin()`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md#IOConnectWindow-pin) and [`unpin()`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md#IOConnectWindow-unpin) methods of an [`IOConnectWindow`](https://docs.interop.io/desktop/reference/javascript/windows/ioconnectwindow/index.md) instance:
>
> ```javascript
> // Pins the tab of the current window.
> await myWindow.pin();
>
> // Unpins the tab of the current window, reverting it to a normal tab with a "Close" button.
> await myWindow.unpin();
> ```
>
> To check whether a tab window is pinned, use the `isPinned` property of the io.Connect Window object:
>
> ```javascript
> const isPinned = myWindow.isPinned;
>
> console.log(`The tab window is ${isPinned ? "pinned": "not pinned."}.`);
> ```

> ### Drag Mode for Windows in Workspaces
>
> By default, when the user starts to drag a window participating in a Workspace, the window is ejected from the Workspace. The user can drop it outside the Workspace or back inside the Workspace. To change this behavior, use the `"windowDragMode"` property of the `"details"` top-level key in the [Workspaces App definition](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#extending_workspaces-configuration). It accepts `"autoEject"` (default) or `"keepInside"` as values.
>
> The following example demonstrates how to prevent the Workspaces App from ejecting the windows in a Workspace when the user drags them:
>
> ```json
> {
>     "details": {
>         "windowDragMode": "keepInside"
>     }
> }
> ```
>
> To set the window drag mode for an existing Workspace programmatically, use the [`setWindowDragMode()`](https://docs.interop.io/desktop/reference/javascript/workspaces/workspace/index.md#Workspace-setWindowDragMode) method of a [`Workspace`](https://docs.interop.io/desktop/reference/javascript/workspaces/workspace/index.md) instance:
>
> ```javascript
> // Windows won't be ejected from the Workspace when the user drags them.
> await myWorkspace.setWindowDragMode("keepInside");
> ```
>
> To check the current window drag mode setting of an existing Workspace, use the `windowDragMode` property of the Workspace object:
>
> ```javascript
> const dragMode = myWorkspace.windowDragMode;
> ```
>
> To specify the window drag mode when creating a Workspace, use the `windowDragMode` property of the `config` object in the [`WorkspaceDefinition`](https://docs.interop.io/desktop/reference/javascript/workspaces/workspacedefinition/index.md):
>
> ```javascript
> const definition = {
>     config: {
>         title: "My Workspace",
>         windowDragMode: "keepInside"
>     }
> };
>
> const myWorkspace = await io.workspaces.createWorkspace(definition);
> ```

> ### Channel Restrictions
>
> #### Subscribing for Channel Restriction Changes
>
> To get notified when the [Channel restrictions](https://docs.interop.io/desktop/capabilities/data-sharing/channels/javascript/index.md#events-channel_restrictions_changed) for any window have changed, use the [`onChannelRestrictionsChanged()`](https://docs.interop.io/desktop/reference/javascript/channels/api/index.md#API-onChannelRestrictionsChanged) method and provide a handler for the event. The handler will receive as arguments the current set of Channel restrictions and the ID of the window for which the Channel restrictions have changed:
>
> ```javascript
> const handler = (restrictions, windowID) => {
>     console.log(`Channel restrictions changed for window with ID: "${windowID}"`);
>     console.log(restrictions.channels);
> };
>
> const unsubscribe = io.channels.onChannelRestrictionsChanged(handler);
> ```
>
> #### Preventing Apps from Modifying Channel Restrictions
>
> To prevent an app from modifying Channel restrictions, use the `"preventModifyingRestrictionsFor"` property of the `"channelSelector"` object under the `"details"` top-level key in the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md#channels-channel_selector). Provide the names of the Channels whose restrictions the app won't be able to modify:
>
> ```json
> {
>     "details": {
>         "channelSelector": {
>             "preventModifyingRestrictionsFor": ["Red", "Green"]
>         }
>     }
> }
> ```
>
> > ⚠️ *Note that the `"preventModifyingRestrictionsFor"` property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"` and `"citrix"`.*

> ### Electron Cache
>
> The `"copy"` property of the `"cache"` object under the `"folders"` top-level key in the `system.json` [system configuration](https://docs.interop.io/desktop/developers/configuration/system/index.md) file of **io.Connect Desktop** can now accept either an object or a Boolean value.
>
> To specify a location from where to [copy the Electron cache](https://docs.interop.io/desktop/developers/configuration/system/index.md#folders) from the closest previously installed **io.Connect Desktop** version and add it to the cache files for the upgraded version of **io.Connect Desktop**, use the `"path"` property of the `"copy"` object. Provide an absolute path pointing to the location of the Electron cache you want to migrate:
>
> ```json
> {
>     "folders": {
>         "cache": {
>             "copy": {
>                 "path": "%LocalAppData%/MyElectronCache/"
>             }
>         }
>     }
> }
> ```

> ### Notifications API
>
> Added methods for [snoozing](https://docs.interop.io/desktop/capabilities/notifications/javascript/index.md#snoozing_notifications), [clearing](https://docs.interop.io/desktop/capabilities/notifications/javascript/index.md#clearing_notifications), and [updating the state](https://docs.interop.io/desktop/capabilities/notifications/javascript/index.md#notification_state) of multiple notifications at a time - [`snoozeMany()`](https://docs.interop.io/desktop/reference/javascript/notifications/api/index.md#API-snoozeMany), [`clearMany()`](https://docs.interop.io/desktop/reference/javascript/notifications/api/index.md#API-clearMany), and [`setStates()`](https://docs.interop.io/desktop/reference/javascript/notifications/api/index.md#API-setStates):
>
> ```javascript
> // List of IDs of the notifications to snooze, to clear, or whose states to set.
> const notificationIDs = notifications.map(notification => notification.id);
>
> // Snoozing multiple notifications.
> const snoozeDurationMS = 600000;
>
> await io.notifications.snoozeMany(notificationIDs, snoozeDurationMS);
>
> // Setting the state of multiple notifications.
> const notificationState = "Seen";
>
> await io.notifications.setStates(notificationIDs, notificationState);
>
> // Clearing multiple notifications.
> await io.notifications.clearMany(notificationIDs);
> ```

## Improvements & Bug Fixes

> - Improved support for adding additional apps during a boot sequence stage.
>
> - Improved handling theme changes for the web page search triggered with `CTRL + F`.
>
> - Added an error message displayed in the io.Connect launcher UI when a Layout fails to save.
>
> - Improved handling of opening windows with invalid values for width and height when using the browser native `window.open()` method.
>
> - Improved handling invocations of Interop methods when an Interop server has been removed.
>
> - Improved tab drag and move behavior in web groups.
