# JavaScript

Source: https://docs.interop.io/desktop/capabilities/windows/layouts/javascript/index.html

## Overview

The Layouts API is accessible via the [`io.layouts`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md) object.

## Configuration

It's possible to configure the [Layouts API](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md) by using the `layouts` property of the optional [`Config`](https://docs.interop.io/desktop/reference/javascript/io.connect%20desktop/config/index.md) object for initializing the [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop) library.

The Layouts API supports different modes of initialization which can be specified by using the values described in the [`Mode`](https://docs.interop.io/desktop/reference/javascript/layouts/mode/index.md) enumeration. It can also be configured whether to auto save the context of individual windows and for which Layout types (Global, App Default, Workspace) to save it.

The following example demonstrates how to configure the Layouts API:

```javascript
import IODesktop from "@interopio/desktop";

const config = {
    layouts: {
        mode: "full",
        // Individual window context will be saved only when saving the specified types of Layouts.
        autoSaveWindowContext: ["Global", "Workspace"]
    }
};

const io = await IODesktop(config);
```

The different modes of the Layouts API restrict or enable certain functionalities. In `"slim"` mode (default), Layouts can't be manipulated (created, removed, renamed) and Layout events aren't available, but custom context data can still be saved. In `"full"` mode, all functionalities are available. In `"fullWaitSnapshot"` mode, the Layouts library will notify that it is ready a little later than in `"full"` mode - when a snapshot of the available Layouts has been received.

## Layout Operations

### Current Global Layout

To retrieve the currently restored Global Layout, use the [`getCurrentLayout()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getCurrentLayout) method:

```javascript
const currentLayout = await io.layouts.getCurrentLayout();
```

### Listing All Layouts

To retrieve a collection of all currently available [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) objects, use the [`list()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-list) method:

```javascript
const layouts = io.layouts.list();
```

> ⚠️ *Note that the `list()` method isn't available in `"slim"` mode. Use [`export()`](#layout_operations-export__import) instead.*

### All Layouts by Type

To retrieve all Layouts by type, use the [`getAll()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getAll) method and specify the Layout type. It resolves with a collection of [`LayoutSummary`](https://docs.interop.io/desktop/reference/javascript/layouts/layoutsummary/index.md) objects, which don't contain the extensive objects describing the actual [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) components:

```javascript
const allGlobalLayouts = await io.layouts.getAll("Global");
```

### Specific Layout

To retrieve a specific Layout, use the [`get()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-get) method and provide the name of the Layout and the Layout type as arguments. It resolves with the requested [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) object or `undefined` if a Layout with the specified name and type doesn't exist:

```javascript
const name = "My Layout";
const type = "Global";

const myLayout = await io.layouts.get(name, type);
```

### Save

To save a Layout, use the [`save()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-save) method and pass a [`NewLayoutOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/newlayoutoptions/index.md) object with a required `name` property. If a Layout with that name already exists, it will be replaced. The method resolves with the saved [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) object:

```javascript
const options = {
    name: "My Layout"
};

const savedLayout = await io.layouts.save(options);
```

Available since io.Connect Desktop 9.1

When saving a Layout, you can specify whether to set it as the currently active Global Layout by using the `setAsCurrent` property of the [`NewLayoutOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/newlayoutoptions/index.md) object:

```javascript
const options = {
    name: "My Layout",
    setAsCurrent: false
};

const myLayout = await io.layouts.save(options);
```

Available since io.Connect Desktop 9.9

To skip saving any window or Workspace contexts when saving a Layout, use the `ignoreContexts` property of the [`NewLayoutOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/newlayoutoptions/index.md) object:

```javascript
const options = {
    name: "My Layout",
    ignoreContexts: true
};

const savedLayout = await io.layouts.save(options);
```

### Restore

To restore a Layout, use the [`restore()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-restore) method and pass a [`RestoreOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/restoreoptions/index.md) object specifying the name of the Layout (required) and other restore options:

```javascript
const restoreOptions = {
    name: "My Layout",
    // Specify whether to close all running apps before restoring the Layout.
    // The default is `true` for Global Layouts.
    closeRunningInstance: false
};

const result = await io.layouts.restore(restoreOptions);
```

> ⚠️ *Note that saving, and especially restoring, a Global Layout may be a taxing operation depending mainly on how many apps there are in the Layout, how heavy they are, and how much context is attached to the Layout. If you need a quicker way to switch between Global Layouts, see the [Hibernate & Resume](#layout_operations-hibernate__resume) section.*

Available since io.Connect Desktop 9.10.1 & 10.0

To specify whether the Workspaces participating in a Global Layout will be restored in their original (unmodified) state when the Global Layout is restored, or in the exact state in which they were when the Global Layout was saved, use the `restoreWorkspacesByReference` property of the [`RestoreOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/restoreoptions/index.md) object:

```javascript
const restoreOptions = {
    name: "My Layout",
    restoreWorkspacesByReference: true
};

const result = await io.layouts.restore(restoreOptions);
```

The value of this property defaults to the value of the `"restoreWorkspacesByReference"` property in the [Workspaces App definition](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#extending_workspaces-configuration-restoring_workspaces) and will override it.

> ℹ️ *For details on how to specify the mode for restoring Workspaces participating in Global Layouts via configuration, see the [Workspaces > Overview > Extending Workspaces](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#extending_workspaces-configuration-restoring_workspaces) section.*

### Restored Layouts Info

Available since io.Connect Desktop 9.4

To retrieve information about the currently active Global Layout (ID, type, name, participating app instances), as well as about any previously active Global Layouts that may still have running instances of their participating apps, use the [`getRestoredLayoutsInfo()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getRestoredLayoutsInfo) method.

By default, when a Global Layout is [restored](#layout_operations-restore), any remaining app instances of the previously active Global Layout are closed and the `getRestoredLayoutsInfo()` method will return information only about the currently active Global Layout. However, if the `closeRunningInstance` property of the [`RestoreOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/restoreoptions/index.md) object is set to `false` when restoring a Global Layout, all running app instances of the previously active Global Layout will remain intact and in this case the `getRestoredLayoutsInfo()` method will return information about that Global Layout as well.

> ⚠️ *Note that the `getRestoredLayoutsInfo()` method won't return any information about a currently or previously active Global Layout if any of its components is a Workspace, as [Workspace Layouts](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#workspaces_concepts-workspace_layout) aren't supported for this operation. Also keep in mind that the information about the restored Global Layouts is updated dynamically, so if all app instances participating in a Global Layout are closed, the `getRestoredLayoutsInfo()` method won't return any information about it.*

The `getRestoredLayoutsInfo()` method resolves with a [`GetRestoredLayoutsInfoResult`](https://docs.interop.io/desktop/reference/javascript/layouts/getrestoredlayoutsinforesult/index.md) object with a `layoutInfo` property holding a list of [`RestoredLayoutDetails`](https://docs.interop.io/desktop/reference/javascript/layouts/restoredlayoutdetails/index.md) objects. Each `RestoredLayoutDetails` object describes the currently active or any previously active Global Layouts that may still have running instances of their participating apps.

This method may be useful if you want to retrieve the IDs of all Global Layouts that the user has restored (and that still have running instances of their participating apps) in order to use them in operations like [resetting a Global Layout](#layout_operations-reset).

The following example demonstrates retrieving information about all restored Global Layouts and finding the currently active one in order to use its ID:

```javascript
// Retrieve information about all restored Global Layouts.
const allRestoredLayoutsInfo = (await io.layouts.getRestoredLayoutsInfo()).layoutInfo;
// Get the current Global Layout in order to compare the Layout names.
const currentLayout = await io.layouts.getCurrentLayout();

// Find the details about the current Global Layout.
const myLayoutInfo = allRestoredLayoutsInfo.find(layoutInfo => layoutInfo.name === currentLayout.name);

// Use the Layout ID.
console.log(myLayoutInfo.id);
```

### Retrieving Layout Contents

Available since io.Connect Desktop 10.3 & @interopio/desktop 6.21

To retrieve the contents of a Global Layout or a Workspace Layout, use the [`getLayoutContents()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getLayoutContents) method. Pass a [`GetContentsOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/getcontentsoptions/index.md) object as a required argument and specify the `name` and `type` of the Layout whose contents to retrieve:

```javascript
const options = { name: "My Layout", type: "Global" };

const {
    appComponents,
    workspaceComponents,
    workspaceWindows
} = await io.layouts.getLayoutContents(options);

// List all apps in the Layout.
console.log("Apps:", appComponents);

// List all Workspaces App instances in the Layout.
console.log("Workspaces App instances:", workspaceComponents);

// List all windows participating in all Workspaces.
console.log("Workspace windows:", workspaceWindows);
```

The `getLayoutContents()` method resolves with a [`LayoutContents`](https://docs.interop.io/desktop/reference/javascript/layouts/layoutcontents/index.md) object. When used for a Global Layout, the returned object contains all components participating in the Layout: individual app instances (including all Workspaces App instances), all Workspace instances hosted in all Workspaces App instances, and all windows participating in all Workspaces. When used for a Workspace Layout, the returned object contains only the windows participating in the Workspace.

### Hibernate & Resume

Hibernating and resuming provides a quicker way to save and restore Global Layouts. The hibernation operation saves the Layout (therefore the original Global Layout will be overwritten) and enables you to resume (restore) the Layout more quickly by preserving the participating app instances and hiding them from the user. If you have heavy apps in a Layout and they take a lot of time to load, you may choose to hibernate the Layout when the user switches to another Layout. Resuming the Layout later will save the time usually needed for loading the heavy apps, but at the expense of higher memory consumption on the user machine. You should carefully consider the advantages and disadvantages of using hibernation when deciding on a strategy for saving and restoring Global Layouts.

> ⚠️ *Note that in order for the hibernation operation to be most beneficial, you should prevent your app instances from closing when being hibernated. You can specify settings for closing or preserving hibernated app instances globally and per app which provides you with flexibility when designing your hibernation strategy. For more details, see the [Developers > Configuration > System > App Settings > Hibernation](https://docs.interop.io/desktop/developers/configuration/system/index.md#app_settings-hibernation) and [Developers > Configuration > Application > Hibernation](https://docs.interop.io/desktop/developers/configuration/application/index.md#hibernation) sections.*

To hibernate a Layout, use the [`hibernate()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-hibernate) method and provide the name of the Layout to hibernate as a required first argument. As a second optional argument, you can pass a [`HibernationOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/hibernationoptions/index.md) object:

```javascript
const name = "My Layout";
const options = {
    context: { io: 42 },
    metadata: { layout: "MyHibernatedLayout"}
};

const result = await io.layouts.hibernate(name, options);

console.log(`Layout hibernated ${result.status === "Success" ? "successfully" : "unsuccessfully"}.`);
```

To resume a hibernated Layout, use the [`resume()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-resume) method and provide the name of the Layout to resume as a required first argument. As optional second and third arguments you can provide context for the resumed Layout and a [`ResumeOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/resumeoptions/index.md) object:

```javascript
const name = "My Layout";
const context = { io: 42 };
const options = {
    // Will close any already running app instances before resuming the Layout.
    cleanUp: true
};

const result = await io.layouts.resume(name, context, options);

console.log(`Layout resumed ${result.status === "Success" ? "successfully" : "unsuccessfully"}.`);
```

### Rename

To rename a Layout, use the [`rename()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-rename) method. You must pass the [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) object to rename as a first argument and the new name for the Layout as a second argument:

```javascript
await io.layouts.rename(myLayout, "My New Layout");
```

### Remove

To remove a Layout, use the [`remove()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-remove) method. You must pass the Layout type and the name of the Layout as arguments:

```javascript
await io.layouts.remove("Global", "My Layout");
```

### Export & Import

You can export all currently available [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) objects with the [`export()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-export) method. Exported Layouts can be stored to a database and then be used as restore points, or can be sent to another user and imported on their machine:

```javascript
const layouts = await io.layouts.export();
```

*The `export()` method (as opposed to `list()`) is available in all modes if you need to retrieve a collection of all Layouts.*

To import exported Layouts, use the [`import()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-import) method. Pass the collection of [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) objects to import and specify an [`ImportMode`](https://docs.interop.io/desktop/reference/javascript/layouts/importmode/index.md):

```javascript
const mode = "merge";

await io.layouts.import(layouts, mode);
```

The [`ImportMode`](https://docs.interop.io/desktop/reference/javascript/layouts/importmode/index.md) controls the import behavior. If set to `"replace"` (default), all existing Layouts will be removed and will be replaced by the imported ones. If set to `"merge"`, the imported Layouts will be added to the existing ones, replacing any Layouts with conflicting names.

### Update Metadata

To persist any changes made to the metadata of a [`Layout`](https://docs.interop.io/desktop/reference/javascript/layouts/layout/index.md) object, use the [`updateMetadata()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-updateMetadata) method and provide the Layout as an argument:

```javascript
// Changing the metadata of a Layout.
myLayout.metadata = { io: 42 };

// Updating the metadata of a Layout so that it will be persisted.
await io.layouts.updateMetadata(myLayout);
```

### Reset

Available since io.Connect Desktop 9.4

Resetting a Layout programmatically enables you to quickly revert a Global Layout to its default state, without the user having to manually start missing app instances or move and resize windows. Already running instances that are part of the Layout will be reused. You can specify whether the missing app instances should be recreated and whether apps that may have been hidden programmatically should be reset. It's also possible to specify whether to revert the participating app instances to their default state in regard to their [window context](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#context) and selected [Channel](https://docs.interop.io/desktop/capabilities/data-sharing/channels/overview/index.md).

> ⚠️ *Note that [Workspaces Apps](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#workspaces_concepts) aren't included in the reset Layout operation.*

To reset a Layout, use the [`reset()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-reset) method and pass a [`ResetLayoutOptions`](https://docs.interop.io/desktop/reference/javascript/layouts/resetlayoutoptions/index.md) object as a required argument. The only required property in the `ResetLayoutOptions` object is `layoutId` where you must provide the ID of the Layout to reset:

```javascript
// Retrieve details about the currently restored Layout that you want to reset.
const myLayout = (await io.layouts.getRestoredLayoutsInfo()).layoutInfo.find(l => l.name === "My Layout");

const options = {
    // Provide the ID of the Layout to reset.
    layoutId: myLayout.id,
    // Will exclude hidden apps from the reset operation.
    visibleOnly: true,
    // Will create missing app instances.
    createMissing: true,
    // Will preserve the current state of the app instances (window context and selected Channel).
    resetState: false
};

const result = await io.layouts.reset(options);
```

To retrieve the ID of the Layout in which your are interested, you can use the [`getRestoredLayoutsInfo()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getRestoredLayoutsInfo) method, or the [`RestoreResumeResult`](https://docs.interop.io/desktop/reference/javascript/layouts/restoreresumeresult/index.md) object returned both by the [`restore()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-restore) method for restoring a saved Layout and by the [`resume()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-resume) method for resuming a hibernated Layout.

### Refresh

To force a refresh of the Layout list available to the user when using a REST service or [**io.Manager**](https://docs.interop.io/manager/overview/index.md) as a [Layout store](https://docs.interop.io/desktop/capabilities/windows/layouts/overview/index.md#layout_stores), use the [`forceRefresh()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-forceRefresh) method:

```javascript
await io.layouts.forceRefresh();
```

## Save & Update Context

When a Layout is saved, apps can store context data in it. When the Layout is restored, the context data is also restored and returned to the apps. Context data can be saved in all Layout types.

> ⚠️ *Note that saving large volumes of custom data as window context (e.g., thousands of lines of table data) can lead to significant delays when saving a Layout. A Layout usually contains several (in some cases - many) apps and Workspaces (which can also contain many apps) and if one or more of the apps saves large amounts of context data each time a Layout is saved, this will significantly slow down the saving process. The methods for saving custom context work best with smaller amounts of data. If your app needs to save large amounts of data, you have to think about how to design this process better - for instance, you may store IDs, indices, etc., as context data, save the actual data to a database, and when you restore the Layout, fetch the data using the data IDs saved as window context.*

### Saving Context Data

To save context data, apps can subscribe for Layout save requests using the [`onSaveRequested()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onSaveRequested) method. A Layout save request event is fired when the user attempts to save a Layout or close a window, Workspace, etc. The on `onSaveRequested()` method accepts a callback which will be invoked when a Layout save request is triggered. The callback will receive as an argument a [`SaveRequestContext`](https://docs.interop.io/desktop/reference/javascript/layouts/saverequestcontext/index.md) object containing the Layout name, type and context. Use it to determine the type of the Layout and instruct your app to react accordingly:

```javascript
const saveRequestHandler = (requestInfo) => {
    // Get the Layout type.
    const layoutType = requestInfo.layoutType;

    // Return different context data depending on the Layout type.
    if (layoutType === "ApplicationDefault") {
        return { windowContext: { gridWidth: 42 } };
    } else if (layoutType === "Global") {
        return { windowContext: { gridWidth: 420 } };
    } else {
        // Return if not interested in other Layout types.
        return;
    }
};

io.layouts.onSaveRequested(saveRequestHandler);
```

The callback must return a [`SaveRequestResponse`](https://docs.interop.io/desktop/reference/javascript/layouts/saverequestresponse/index.md) object that has a `windowContext` property.

After the Layout has been restored, the saved context data will be available in the window context:

```javascript
// Extracting previously saved data from the window context.
const windowContext = await io.windows.my().getContext();
const gridWidth = windowContext.gridWidth;
```

### Updating App Default Context

To manually update the context of the current window in its App Default Layout, use the `updateDefaultContext()` method:

```javascript
const context = { io: 42 };

await io.layouts.updateDefaultContext(context);
```

### Updating Context of Apps in Global Layouts

To update the context that will be saved for the current app in the currently loaded Global Layout, use the [`updateAppContextInCurrent()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-updateAppContextInCurrent) method. This method allows you to update the saved context for the current app in the Layout without having to save the entire Layout:

```javascript
const context = { io: 42 };

await io.layouts.updateAppContextInCurrent(context);
```

## Default Global Layout

**io.Connect Desktop** allows you to specify a [default Global Layout](https://docs.interop.io/desktop/capabilities/windows/layouts/overview/index.md#default_global_layout) that will be automatically loaded on start. You can get, set and clear the default Global Layout programmatically.

To retrieve the current default Global Layout, use the [`getDefaultGlobal()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-getDefaultGlobal) method:

```javascript
// May return `undefined` if no default Global Layout has been set.
const defaultLayout = await io.layouts.getDefaultGlobal();
```

To set a default Global Layout, use the [`setDefaultGlobal()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-setDefaultGlobal) method:

```javascript
io.layouts.setDefaultGlobal("My Layout");
```

To clear the default Global Layout, use the [`clearDefaultGlobal()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-clearDefaultGlobal) method:

```javascript
io.layouts.clearDefaultGlobal();
```

## Events

The Layouts API provides methods for reacting to various Layout events. Use the returned unsubscribe function to stop receiving notifications about the respective event.

### Added

To get notified when a Layout is added, use the [`onAdded()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onAdded) method:

```javascript
io.layouts.onAdded(console.log);
```

### Removed

To get notified when a Layout is removed, use the [`onRemoved()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onRemoved) method:

```javascript
io.layouts.onRemoved(console.log);
```

### Changed

To get notified when a Layout is changed, use the [`onChanged()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onChanged) method:

```javascript
io.layouts.onChanged(console.log);
```

### Renamed

To get notified when a Layout is renamed, use the [`onRenamed()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onRenamed) method:

```javascript
io.layouts.onRenamed(console.log);
```

### Restored

To get notified when a Layout is restored, use the [`onRestored()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onRestored) method:

```javascript
io.layouts.onRestored(console.log);
```

### Default Global Layout Changed

Available since io.Connect Desktop 9.9

To get notified when the [default Global Layout](https://docs.interop.io/desktop/capabilities/windows/layouts/overview/index.md#default_global_layout) has been changed, use the [`onDefaultGlobalChanged()`](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md#API-onDefaultGlobalChanged) method:

```javascript
io.layouts.onDefaultGlobalChanged(console.log);
```

## API Reference

For a complete list of the available Layouts API methods and properties, see the [Layouts API reference documentation](https://docs.interop.io/desktop/reference/javascript/layouts/api/index.md).
