# Setup

Source: https://docs.interop.io/browser/capabilities/windows/layouts/setup/index.html

## Overview

End users in large enterprises often have multi-monitor setups on which they arrange the necessary apps in the most convenient way for executing daily tasks. The **io.Connect Browser** Layouts feature allows them to save and later restore the exact arrangement and context of their environment - windows, apps, [Workspaces](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md), and their bounds and context. Users can save multiple apps and Workspaces in different Layouts, each corresponding to a specific task or workflow. Restoring the saved Layout happens with a single click and saves time and effort for finding, launching and arranging the desired apps.

The Layouts library has the following capabilities:

- importing, exporting, removing, and retrieving Layouts;
- saving and restoring Layouts;
- events related to adding, removing, changing, saving Layouts, and more;
- requesting [permission for the browser Window Management API](#requirements__limitations-window_management_permission);

The **io.Connect Browser** Layouts library supports different types of Layouts:

- **Global**

This type of Layout can contain floating windows, apps and [Workspaces](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md). A Global Layout describes the bounds and context of all components participating in it.

> ⚠️ *Note that the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) isn't saved in a Global Layout, as it's assumed that the Main app is the entry point of an **io.Connect Browser** project from where all Global Layouts are to be handled.*

- **Workspace**

The Layout of a [Workspace](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace) instance describes the arrangement of the Workspace elements, its bounds and the context of the apps participating in it.

## Configuration

To provide configuration for the Layouts library, use the `layouts` property of the configuration object for initializing the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library. The following example demonstrates configuring the Layouts library and enabling the Workspaces API, so that [Workspace Layouts](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace_layout) can be restored too:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";
import IOWorkspaces from "@interopio/workspaces-api";

const config = {
    licenseKey: "my-license-key",
    workspaces: {
        src: "http://localhost:3000"
    },
    browser: {
        libraries: [IOWorkspaces]
    },
    layouts: {
        mode: "session",
        // Layout definition objects.
        local: [ {...}, {...}]
    }
};

const { io } = await IOBrowserPlatform(config);
```

The `layouts` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `local` | `object[]` | Array of [`Layout`](https://docs.interop.io/browser/reference/javascript/layouts/layout/index.md) objects. On startup, these predefined Layouts will be imported and merged with the already existing Layouts and the Layouts with the same names will be replaced. This ensures that the user-created Layouts won't be removed when in `"idb"` mode. |
| `mode` | `"session"` \| `"idb"` \| `"rest"` \| `"manager"` | Mode for storing Layouts. For more details, see the [Layout Stores](#layout_stores) section. Defaults to `"idb"`. If you want to use a REST service or **io.Manager** as a Layout store, you must explicitly set this property to `"rest"` or `"manager"` respectively and also add the required configuration for connecting to the REST service or **io.Manager**. For more details, see the [Layout Stores > REST](#layout_stores-rest) and [Layout Stores > io.Manager](#layout_stores-iomanager) sections. |
| `rest` | `object` | Settings for a REST Layout store. Valid only in `"rest"` mode. For more details, see the [Layout Stores > REST](#layout_stores-rest) section. *Available since **io.Connect Browser** 4.0.* |

Enabling the [Workspaces API](https://www.npmjs.com/package/@interopio/workspaces-api) isn't strictly required in order to use Global Layouts, but it's highly recommended, because you can never be completely sure what type of Layout your system will need to restore. If the Global Layout you want to restore describes one or more components which are [Workspace Layouts](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace_layout), then a missing [Workspaces configuration](https://docs.interop.io/browser/capabilities/windows/workspaces/enabling-workspaces/index.md) will result in errors.

## Layout Stores

**io.Connect Browser** can obtain Layouts from a local store, from a remote REST service, or from [**io.Manager**](https://docs.interop.io/manager/overview/index.md).

In the standard **io.Connect Browser** deployment model, Layouts aren't stored locally on the user machine, but are served remotely. If **io.Connect Browser** is configured to use a remote Layout store, it will poll it periodically and discover new Layouts. The store implementation is usually connected to an entitlement system based on which different users can have different Layouts.

To provide settings for Layout stores, use the `layouts` property of the configuration object for initializing the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library.

### Local

To instruct **io.Connect Browser** to manage Layouts using a local Layout store, set the `mode` property of the `layouts` object to `"session"` or `"idb"`.

Use `"session"` to handle the Layouts by using the browser session storage. Once the browser session is over (e.g., the user closes the Main app window), all user-created Layouts will be lost. If the Main app is only refreshed, however, the Layouts will still be available.

Use the `"idb"` setting if you want the Layouts to be persisted using the `IndexedDB` API of the browser. This option is useful for testing and PoC purposes, because it simulates persisting and manipulating Layouts on a server.

The following example demonstrates how to configure the platform to use the session storage as a local Layout store:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    layouts: {
        mode: "session"
    }
};

const { io } = await IOBrowserPlatform(config);
```

### REST

Available since io.Connect Browser 4.0

Layout definitions can also be obtained from remote Layout stores via a REST service.

> ℹ️ *For a reference implementation of a remote Layout definitions store, see the [Node.js REST Config](https://github.com/InteropIO/rest-config-example-node-js) example.*

To instruct **io.Connect Browser** to manage Layouts using a remote REST service, set the `mode` property of the `layouts` object to `"rest"` and provide settings for the REST store by using the `rest` object.

The `rest` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `cache` | `object` | Settings for caching the Layouts. *Available since **io.Connect Browser** 4.1.* |
| `customHeaders` | `object` | Object containing key/value pairs of headers that will be appended to every request to the remote store. |
| `getRequestInit` | `function` | Function that must return a [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) object. This object will be merged with the default one and will be appended to every request sent to the remote store. Use this to provide custom request options or to override the default ones. *Available since **io.Connect Browser** 3.5.* |
| `pollingInterval` | `number` | Interval in milliseconds at which to poll the remote store for updates. If not provided, the platform will fetch the Layout definitions only once on startup. Defaults to `0`. |
| `requestTimeout` | `number` | Interval in milliseconds to wait for a response to the request for fetching Layout definitions from the remote store. Defaults to `30000`. |
| `url` | `string` | **Required.** URL pointing to the remote store. |
| `waitInitialResponse` | `boolean` | If `true` (default), the platform will wait for an initial response before proceeding with the platform initialization. In case of an error or no response within the specified request timeout, the platform won't initialize. *Available since **io.Connect Browser** 4.1.* |

The `cache` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `enabled` | `boolean` | If `true`, the retrieved Layouts will be cached by using the browser `IndexedDB` API and the cached Layouts will be returned as a response to any API calls. If caching is enabled, you must also set the `pollingInterval` property to instruct the platform at what interval to retrieve Layouts from the remote store. Defaults to `false`. |

The following example demonstrates how to configure the platform to use a remote REST service as a Layout store:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    layouts: {
        mode: "rest",
        // Settings for the REST store.
        rest: {
            url: "https://my-remote-store/layouts"
        }
    }
};

const { io } = await IOBrowserPlatform(config);
```

The remote store must return Layout definitions in the following response shape:

```json
{
    "layouts": [
        // List of Layout definition objects.
        {}, {}
    ]
}
```

### io.Manager

Available since io.Connect Browser 4.0

You can also use [**io.Manager**](https://docs.interop.io/manager/overview/index.md) for hosting and retrieving Layouts. To instruct **io.Connect Browser** to manage Layouts using **io.Manager**, set the `mode` property of the `layouts` object to `"manager"` and provide settings for connecting to **io.Manager** by using the `manager` top-level key.

The following example demonstrates how to configure the platform to use **io.Manager** as a Layout store:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    layouts: {
        mode: "manager"
    },
    manager: {
        // Settings for connecting to io.Manager.
    }
};

const { io } = await IOBrowserPlatform(config);
```

> ℹ️ *For more details on how to configure **io.Connect Browser** to connect to **io.Manager**, see the [io.Manager](https://docs.interop.io/browser/capabilities/manager/index.md) section.*

> ⚠️ *Note that when using **io.Manager** as a Layout store, Layout files aren't only fetched from the server, but are also saved on the server (e.g., when the user edits and saves an existing Layout).*

## Compatibility with io.Connect Desktop

Global Layouts in **io.Connect Browser** and in **io.Connect Desktop** are optimally, but not entirely compatible. When using the same Layouts in **io.Connect Browser** and in **io.Connect Desktop**, you have to consider the following:

- All Layouts saved in **io.Connect Browser** can be imported and restored in **io.Connect Desktop**, provided that the apps described in the Layout are also part of **io.Connect Desktop**.

- All Layouts saved in **io.Connect Desktop** can be imported and will be restored as accurately as possible in **io.Connect Browser**. This is due to the fact that **io.Connect Desktop** has advanced window management capabilities like support for different [window types](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_modes), [advanced window tabs](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_modes-tab_windows), native apps and much more, which can't be translated to a web Layout, because most of these features aren't available in the standard browsers, or in the case of window tabs, the browser tabbing significantly restricts and complicates the io.Connect [Window Management](https://docs.interop.io/browser/capabilities/windows/window-management/index.md) capabilities. If an **io.Connect Desktop** Layout contains tabbed windows, in an **io.Connect Browser** Layout, they will be restored as separate browser windows with the same bounds on the screen. If an **io.Connect Desktop** Layout contains a native app participating in a [Workspace](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace), in an **io.Connect Browser** Layout, the Workspace will be restored with an empty component containing a "+" button in it from which the user can add a new app.

- When an **io.Connect Desktop** Layout is imported, restored and saved again in **io.Connect Browser**, only a soft update is performed on the original components of the Layout. This means that only the bounds and the context of the original components are updated. This preserves all properties specific to **io.Connect Desktop**.

- To ensure optimal control over how and what is saved and restored in a Layout, it's recommended to use the `metadata` property of a [`Layout`](https://docs.interop.io/browser/reference/javascript/layouts/layout/index.md) object to indicate the target environment for the Layout. This will allow you to import and restore only the Layouts for the environment in which your app is currently running.

## Requirements & Limitations

### Browser Requirements

Global Layouts require that the browser supports the [Window Management API](https://www.w3.org/TR/window-management/), which was introduced in Chrome 100 and in Edge 100. If this API isn't available, Global Layouts won't be able to initialize, resulting in an error.

### Window Management Permission

The [Window Management API](https://www.w3.org/TR/window-management/) of the browser, required for using Global Layouts, in turn requires an explicit permission by the user. Requesting this permission must be done carefully and must be planned well, because should the user deny the permission, then there is no programmatic way to ask them again or revert their decision. That's why the Global Layouts library offers methods containing all necessary tools for the developer to ask the user for the Window Management permission at the right moment and in a well-designed way. For more details and examples, see the [Layouts API > Requesting Window Management Permission](https://docs.interop.io/browser/capabilities/windows/layouts/layouts-api/index.md#requesting_window_management_permission) and [Layouts API > Checking the Global Layouts State](https://docs.interop.io/browser/capabilities/windows/layouts/layouts-api/index.md#checking_the_global_layouts_state) sections.

> ⚠️ *Note that if requesting this permission isn't handled with the provided methods, the Global Layouts library will automatically request it the first time a Layout is saved or restored, but this default behavior isn't recommended, as it isn't ideal for the user experience.*

### Non-io.Connect Windows and Apps

Not all of your windows and apps will use one of the io.Connect libraries and be interop-enabled. In such a situation, **io.Connect Browser** has limited options - programmatically moving, resizing and getting the current position of such windows isn't possible. In this case, all windows and apps that aren't interop-enabled will be saved in a Global Layout, but they will be restored with their initial bounds, no matter how the user has moved or resized them after loading the Layout.

Non-io.Connect windows and apps participating in a [Workspace](https://docs.interop.io/browser/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace) will be saved and restored just like any other interop-enabled window, because the [Workspaces App](https://docs.interop.io/browser/capabilities/windows/workspaces/workspaces-app/index.md) controls the bounds of the components in which the windows are placed.

### Window State

Current browsers don't allow for programmatic getting or changing the state of the window (minimized, maximized, normal). As a result, all components in a saved Global Layout in **io.Connect Browser** will be set to window state `"normal"`. Windows that are manually maximized by the user will be saved and restored to fit the entire window, but won't be maximized. Windows that are minimized by the user will be saved and restored in a normal state.
