Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
johnman committed May 1, 2024
1 parent 9053a39 commit 35d6256
Show file tree
Hide file tree
Showing 16 changed files with 1,016 additions and 161 deletions.
81 changes: 62 additions & 19 deletions how-to/web-interop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

> **_:information_source: OpenFin:_** [OpenFin](https://www.openfin.co/) libraries are a commercial product and this repo is for evaluation purposes. Use of the OpenFin npm packages is only granted pursuant to a license from OpenFin. Please [**contact us**](https://www.openfin.co/contact/) if you would like to request a developer evaluation key or to discuss a production license.
# OpenFin Web Interop Basic
# OpenFin Web Interop

This is a very basic example that has a simple provider web page that acts as the main/index page. This page wires up the interop broker using the [@openfin/core-web](https://www.npmjs.com/package/@openfin/core-web) library.
This is a simple example that has a simple provider web page that acts as the main/index page. This page wires up the interop broker and a layout using the [@openfin/core-web](https://www.npmjs.com/package/@openfin/core-web) library.

This page has a very simple layout which is made up of two iframes:
This page has a very simple layout which is made up of four iframes:

- An FDC3 View - This uses the FDC3 API to add a context listener and to broadcast a hardcoded context object.
- An Interop View - This uses the OpenFin Interop API to add a context listener and to set context using a hardcoded context object.

![OpenFin Web Interop Basic Example](./docs/web-interop-basic.png)
- Local - An FDC3 View - This uses the FDC3 API to add a context listener and to broadcast a hardcoded context object.
- Local - An Interop View - This uses the OpenFin Interop API to add a context listener and to set context using a hardcoded context object.
- External - An FDC3 Tool used in our workspace platform starters that lets you experiment with context sharing using the FDC3 APIs.
- External - An Interop Tool used in our workspace platform starters that lets you experiment with context sharing using the OpenFin Interop API.

## Getting Started

Expand Down Expand Up @@ -55,7 +55,7 @@ The host is the entry point and it is the page that gets loaded into the Chrome/

It has a responsibility to create a connection providing a broker url and then initializing the broker providing an id (**this id will be needed by your content when it wishes to connect**).

In the sample we use a [settings](./client/src/platform/settings.ts) file but this has been removed from the snippet to simplify the code snippet.
In the sample we use a [settings](./client/src/platform/settings.ts) file that reads settings from the [web manifest file](./public/manifest.json) but this has been removed from the snippet to simplify the code snippet.

```javascript
import { connect } from "@openfin/core-web";
Expand All @@ -65,24 +65,38 @@ import "./util/buffer";
* Initializes the OpenFin Web Broker connection.
*/
async function init(): Promise<void> {
// Connect to the OpenFin Web Broker.
const fin = await connect({ options: { brokerUrl: "http://localhost:6060/platform/iframe-broker.html" } });
// Get the dom element that should host the layout
const layoutContainer = document.querySelector<HTMLElement>(`#${settings.platform.layout.layoutContainerId}`);

// Get the default layout
const layoutSnapshot = {...};

// Connect to the OpenFin Web Broker and pass the default layout.
const fin = await connect({ options: { brokerUrl: "http://localhost:6060/platform/iframe-broker.html" },
platform: { layoutSnapshot } });

// You may now use the `fin` object. This step is important as it initializes the interop broker.
// You may now use the `fin` object to initialize the broker and the layout.
await fin.Interop.init("web-interop-basic");
// initialize the layout and pass it the dom element to bind to
await fin.Platform.Layout.init({
container: layoutContainer
});
}
```

The host html page [provider.html](./public/platform/provider.html) then:

- imports this code and initializes it.
- brings in required content through an iframe.
- brings in the required css for the @openfin/core-web layout system.

The host page initializes the OpenFin layout system and brings in a required css file that styles the layout system. This styles.css is brought in from the [@openfin/core-web](https://www.npmjs.com/package/@openfin/core-web) npm package. This style is copied to the public/style folder as core-web-styles.css using our [scripts/copy-core-web.js](./scripts/copy-core-web.js) script. It runs as part of the build process.

### IFrame Broker

This is the iframe that is referenced by the Host and Content Providers and it is how they communicate with each other. The iframe broker html page and the shared-webworker.js file have to reside on the same domain as the **host**.

The [iframe broker html page](./public/platform/iframe-broker.html) uses the shared-webworker.js file that comes as part of the [@openfin/core-web](https://www.npmjs.com/package/@openfin/core-web) npm package.
The [iframe broker html page](./public/platform/iframe-broker.html) uses the shared-webworker.js file that comes as part of the [@openfin/core-web](https://www.npmjs.com/package/@openfin/core-web) npm package. This script is copied to the public/js folder as shared-worker.bundle.js using our [scripts/copy-core-web.js](./scripts/copy-core-web.js) script. It runs as part of the build process.

The iframe broker needs some initialization logic as well.

Expand Down Expand Up @@ -150,10 +164,39 @@ export async function init(): Promise<void> {
}
```
## A visual representation
We've covered the key pieces. We have a host, one or more pieces of content and a common iframe broker html page that is used to tie them altogether.
This diagram is here to provide a rough visual guide to support the content above and the example:
![OpenFin Web Interop Basic Rough Visual Guide](./docs/web-interop-basic-visualization.png)
## Settings
To make it easier to update settings we store them in the web [manifest.json](./public/manifest.json) inside of _custom_settings_.
```json
{
"name": "OpenFin Web Interop",
"short_name": "OpenFinWebInterop",
"start_url": "./platform/provider.html",
"display": "standalone",
"background_color": "#fff",
"description": "An example showing a implementation of the OpenFin Web Interop Library.",
"icons": [
{
"src": "common/images/icon-blue.png",
"sizes": "72x72",
"type": "image/png"
}
],
"related_applications": [],
"custom_settings": {
"platform": {
"interop": {
"sharedWorkerUrl": "http://localhost:6060/js/shared-worker.bundle.js",
"brokerUrl": "http://localhost:6060/platform/iframe-broker.html",
"providerId": "web-interop-basic",
"defaultContextGroup": "green"
},
"layout": {
"layoutContainerId": "layout_container",
"defaultLayout": "http://localhost:6060/layouts/default.layout.fin.json"
}
}
}
}
```
10 changes: 7 additions & 3 deletions how-to/web-interop/client/src/platform/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ export async function init(): Promise<void> {
// Set window.fin to the `fin` object.
if (window.fin === undefined) {
const settings = await getSettings();
if(settings === undefined) {
console.error("Unable to run the sample as we have been unable to load the web manifest and it's settings from the currently running html page. Please ensure that the web manifest is being served and that it contains the custom_settings section.");
return;
}
// Specify an interopConfig with a specific provider ID and a context group to initialize the `fin.me.interop` client on connection.
window.fin = await connect({
options: {
brokerUrl: settings.platform.brokerUrl,
brokerUrl: settings.platform.interop.brokerUrl,
interopConfig: {
providerId: settings.platform.providerId,
currentContextGroup: settings.platform.defaultContextGroup
providerId: settings.platform.interop.providerId,
currentContextGroup: settings.platform.interop.defaultContextGroup
}
}
});
Expand Down
6 changes: 5 additions & 1 deletion how-to/web-interop/client/src/platform/iframe-broker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import { getSettings } from "./settings";
*/
async function init(): Promise<void> {
const settings = await getSettings();
if(settings === undefined) {
console.error("Unable to run the sample as we have been unable to load the web manifest and it's settings from the currently running html page. Please ensure that the web manifest is being served and that it contains the custom_settings section.");
return;
}
return initBrokerConnection({
sharedWorkerUrl: settings.platform.sharedWorkerUrl
sharedWorkerUrl: settings.platform.interop.sharedWorkerUrl
});
}

Expand Down
80 changes: 39 additions & 41 deletions how-to/web-interop/client/src/platform/settings.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,46 @@
import type { WebLayoutSnapshot } from "@openfin/core-web";
import type { Settings } from "../shapes/setting-shapes";

/**
* Fetches the settings for the application.
* @returns The settings for the application.
*/
export async function getSettings(): Promise<Settings> {
return {
platform: {
sharedWorkerUrl: "http://localhost:6060/js/shared-worker.bundle.js",
brokerUrl: "http://localhost:6060/platform/iframe-broker.html",
providerId: "web-interop-basic",
defaultContextGroup: "green"
},
layout: {
layoutContainerId: "layout-container",
defaultLayout: {
layouts: {
tab1: {
content: [
{
type: "row",
content: [
{
title: "Bloomberg",
type: "component",
componentName: "view",
componentState: {
url: "http://bloomberg.com/"
}
},
{
title: "OpenFin",
type: "component",
componentName: "view",
componentState: {
url: "http://www.openfin.co/"
}
}
]
}
]
}
}
}
}
};
export async function getSettings(): Promise<Settings|undefined> {
const settings = await getManifestSettings();
if(settings === undefined) {
console.error("Unable to run the example as settings are required and we fetch them from the link web manifest from the html page that is being served. It should exist in the customSettings section of the web manifest.");
}
return settings;
}

/**
* Returns a default layout from the settings if provided.
* @returns The default layout from the settings.
*/
export async function getDefaultLayout(): Promise<WebLayoutSnapshot|undefined> {
const settings = await getSettings();
if(settings?.platform?.layout?.defaultLayout === undefined) {
console.error("Unable to run the example as without a layout being defined. Please ensure that settings have been provided in the web manifest.");
return;
}
if(typeof settings.platform.layout.defaultLayout === "string") {
const layoutResponse = await fetch(settings.platform.layout.defaultLayout);
const layoutJson = await layoutResponse.json() as WebLayoutSnapshot;
return layoutJson;
}
return settings.platform.layout.defaultLayout;
}

/**
* Returns the settings from the manifest file.
* @returns customSettings for this example
*/
async function getManifestSettings(): Promise<Settings|undefined> {
// Get the manifest link
const link = document.querySelector<HTMLLinkElement>('link[rel="manifest"]');
if(link !== null) {
const manifestResponse = await fetch(link.href);
const manifestJson = await manifestResponse.json() as { custom_settings: Settings };
return manifestJson.custom_settings;
}
}
62 changes: 20 additions & 42 deletions how-to/web-interop/client/src/provider.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,32 @@
/* eslint-disable func-style */
import type OpenFin from "@openfin/core";
import { connect, type WebLayoutSnapshot } from "@openfin/core-web";
import { connect } from "@openfin/core-web";
import "./util/buffer";
import { getSettings } from "./platform/settings";
import { getDefaultLayout, getSettings } from "./platform/settings";

/**
* Initializes the OpenFin Web Broker connection.
*/
async function init(): Promise<void> {
const settings = await getSettings();
const layoutSnapshot: WebLayoutSnapshot = settings.layout.defaultLayout;
const layoutContainer = document.querySelector<HTMLElement>(`#${settings.layout.layoutContainerId}`);
const layoutSnapshot = await getDefaultLayout();
if(settings === undefined || layoutSnapshot === undefined) {
console.error("Unable to run the sample as we have been unable to load the web manifest and it's settings from the currently running html page. Please ensure that the web manifest is being served and that it contains the custom_settings section.");
return;
}
const layoutContainer = document.querySelector<HTMLElement>(`#${settings.platform.layout.layoutContainerId}`);
if(layoutContainer === null) {
// error
} else {
// Connect to the OpenFin Web Broker.
const fin = await connect({ options: { brokerUrl: settings.platform.brokerUrl },
platform: { layoutSnapshot } });

// You may now use the `fin` object.
await fin.Interop.init(settings.platform.providerId);

function createLayout({ layoutName, layout }, i) {
const layoutIdentity = { layoutName };
const layoutDiv = document.createElement('div');
layoutDiv.id = `layout-${i}`;
layoutDiv.innerText = layoutName;
layoutContainer.appendChild(layoutDiv);
return layoutIdentity;
};

const layoutManagerOverride = (Base) =>
class E2ELayoutManager extends Base {
async applyLayoutSnapshot({ layouts }) {
await Promise.all(
Object.entries(layouts).map(async ([layoutName, layout], i) =>
createLayout({ layoutName, layout }, i)
)
);
}
async removeLayout(layoutIdentity) {
console.log(`[platform-window] manager: removeLayout called for ${layoutIdentity.layoutName}`);
}
};

// You may now use the `fin` object. In this case, we want to initialize and create layouts
await fin.Platform.Layout.init({
container: layoutContainer
});
console.error(`Please ensure the document has an element with the following id #${settings.platform.layout.layoutContainerId} so that the web-layout can be applied.`);
return;
}
// Connect to the OpenFin Web Broker.
const fin = await connect({ options: { brokerUrl: settings.platform.interop.brokerUrl },
platform: { layoutSnapshot } });

// You may now use the `fin` object.
await fin.Interop.init(settings.platform.interop.providerId);
// initialize the layout and pass it the dom element to bind to
await fin.Platform.Layout.init({
container: layoutContainer
});
}

init()
Expand Down
22 changes: 10 additions & 12 deletions how-to/web-interop/client/src/shapes/setting-shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ export interface Settings {
* Platform settings
*/
platform: {
sharedWorkerUrl: string;
brokerUrl: string;
providerId: string;
defaultContextGroup?: string;
};

/**
* Layout settings
*/
layout: {
layoutContainerId: string;
defaultLayout: WebLayoutSnapshot;
interop: {
sharedWorkerUrl: string;
brokerUrl: string;
providerId: string;
defaultContextGroup?: string;
};
layout: {
layoutContainerId: string;
defaultLayout: WebLayoutSnapshot | string;
};
};
}
4 changes: 2 additions & 2 deletions how-to/web-interop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "public/platform/provider.bundle.js",
"scripts": {
"client": "node ./scripts/launch.mjs",
"copy-shared-worker": "node ./scripts/copy-shared-worker.js",
"build-client": "npm run copy-shared-worker && webpack build --config ./client/webpack.config.js --mode=development",
"copy-core-web": "node ./scripts/copy-core-web.js",
"build-client": "npm run copy-core-web && webpack build --config ./client/webpack.config.js --mode=development",
"build": "npm run build-client",
"start": "npx --yes http-server ./public -p 6060 -c-1",
"setup": "npm install && npm run build",
Expand Down
Loading

0 comments on commit 35d6256

Please sign in to comment.