Recipes - Platform
Standard recipes for Platform API Use Cases. These examples assume a basic understanding of OpenFin Platforms, so please see the Platforms Getting Started page first. Many of these recipes can be seen in action in the Platform seed.
Requirements
- OpenFin CLI installed
- OpenFin Runtime 16.83.53.26+
- Windows Operating System | Mac not fully supported and may result in unexpected behavior
Fixed or "Locked" Layouts
Use Case
Within a Layout, lock a View in place so an end user cannot rearrange the Views.
Description
Locking Views in place can be achieved by setting the reorderEnabled
property in the LayoutSettings object to false
. Additionally, the tabs or "header" section of the Layout can be removed by setting the hasHeaders
parameter to false
.
You can toggle between these states by using the code below. Please note that the headerHeight
is set to 0
when hasHeaders
is false.
createLockedWindow.js
tab is an example using the Platform API to create a window with a "locked" Layout without headers.
toggleLockedLayout.js
tab is an example javascript code to toggle between a locked and unlocked layout. This should be run in the window context.
lockedEventing.js
tab is an example of eventing based on "locked" Layout state. This should be run in the window context.
For more information about manifest files, see Manifest settings.
Example
let platform = await fin.Platform.getCurrent();
let myWinIdentity = await platform.createWindow({
contextMenu: true,
layout: {
settings: {
hasHeaders: false,
reorderEnabled: false
},
content: [{
type: 'stack',
content:[{
type: 'component',
componentName: 'view',
componentState: {
name: 'my-new-test-view',
url: 'http://www.example.com' // The URL of the View
}
}]
}]
}
});
async toggleLockedLayout () {
const oldLayout = await fin.Platform.Layout.getCurrentSync().getConfig();
const { settings, dimensions } = oldLayout;
if(settings.hasHeaders && settings.reorderEnabled) {
fin.Platform.Layout.getCurrentSync().replace({
...oldLayout,
settings: {
...settings,
hasHeaders: false,
reorderEnabled: false
}
});
} else {
fin.Platform.Layout.getCurrentSync().replace({
...oldLayout,
settings: {
...settings,
hasHeaders: true,
reorderEnabled: true
},
dimensions: {
...dimensions,
headerHeight: 25 // please insert your default headerHeight here
}
});
}
};
fin.me.on('layout-ready', async () => {
// Whenever a new layout is ready on this window (on init, replace, or applyPreset)
const { settings } = await fin.Platform.Layout.getCurrentSync().getConfig();
// determine whether it is locked and update an icon
const lockIcon = document.getElementById('lock-button');
if(settings.hasHeaders && settings.reorderEnabled) {
lockIcon.classList.remove('layout-locked');
} else {
lockIcon.classList.add('layout-locked');
}
});
Layout Stack Buttons
Use Case
Provide Layout Stack buttons to your Platform Windows.
Description
Adding Layout Stack Buttons can be achieved by setting the corresponding properties in your LayoutSettings.
Note that the red rectangles show the Layout Stack buttons.
createWindowWithStackButtons.js
tab is an example that uses the Platform API to create a Window with the various stack buttons enabled.
You'll see the popoutWholeStack
option listed as well.
Example
let platform = await fin.Platform.getCurrent();
let myWinIdentity = await platform.createWindow({
contextMenu: true,
layout: { // The `layout` object has two fields: `settings` and `content`
settings: { // Here are the options you can toggle
showPopoutIcon: true,
showCloseIcon: true,
showMaximiseIcon: true,
popoutWholeStack: false
},
content: [{
type: 'stack',
content:[{
type: 'component',
componentName: 'view',
componentState: {
name: 'my-new-test-view',
url: 'http://www.example.com' // The URL of the View
}
}]
}]
}
});
Context Sharing
Use Case
Share context data between all Views in a Window.
Description
setWindowContext
can be used to set a Window's customContext
. This context will be accessible from the Window itself and from any child Views via getWindowContext
. It will be saved in any Platform snapShots and available upon application of those snapShots. The context data must be serializable. This can only be called from a window or view that has been launched into a Platform. This method can be called from the Window itself, or from any child View.
setWindowContext.js
is an example using the Platform Context API to set the context of a Window or View.
listenToHostContextChanges.js
is an example using the Platform Context API to listen for changes in a window's context from a view via the host-context-changed
event. This event fires when a host window's context is updated or when the view is reparented to a new Window.
Example
const platform = fin.Platform.getCurrentSync();
const contextData = {
security: 'STOCK',
currentView: 'detailed'
}
const windowOrViewIdentity = { uuid: fin.me.uuid, name: 'nameOfWindowOrView' };
await platform.setWindowContext(contextData, windowOrViewIdentity);
// Context of the target window or view is now set to `contextData`
// From a view
const contextChangeHandler = ({ context }) => {
console.log('Host window\'s context has changed. New context data:', context);
// react to new context data here
}
await fin.me.on('host-context-changed', contextChangeHandler);
const platform = await fin.Platform.getCurrentSync();
const contextData = {
security: 'STOCK',
currentView: 'detailed'
}
platform.setWindowContext(contextData) // contextChangeHandler will log
// From a window
const contextChangeHandler = ({ context }) => {
console.log('This window\'s context has changed. New context data:', context);
// react to new context data here
// e.g. to make other windows aware of the context change
// one could fin.InterApplicationBus.publish
// or ChannelClient.dispatch here
}
await fin.me.on('context-changed', contextChangeHandler);
const platform = await fin.Platform.getCurrentSync();
const contextData = {
security: 'STOCK',
currentView: 'detailed'
}
platform.setWindowContext(contextData) // contextChangeHandler will log
Provider Customization
Use Case
Functionality that needs to be persisted / applied across the entire Platform via the Platform Provider, this includes but is not limited to Provider overrides
Description
Because the Platform Provider is effectively the "main" application window (that's generally hidden in the background) it can be leveraged to add listeners that need to apply to the entire platform.
lastVisibleWindowClosed.js
is an example using the Platform API that each time a window is closed checks if the window was the last visible Window and shuts down the Platform if it is.
Example
// from the Platform Provider
async function lastVisibleWindowClosed(e) {
const platform = await fin.Platform.getCurrent();
const childWindows = await platform.Application.getChildWindows();
async function isShowing(win) {
return await win.isShowing();
}
const asyncFilter = async (arr, predicate) => {
const results = await Promise.all(arr.map(predicate));
return arr.filter((_v, index) => results[index]);
};
const visibleWindows = await asyncFilter(childWindows, isShowing);
if (visibleWindows.length === 1) return await platform.quit();
return await fin.me.close(true);
}
await fin.me.addListener("close-requested", lastVisibleWindowClosed);
Provider overrides & snapshot logic
Use Case
Override OpenFin methods with your own to save and apply snapshots
.
Description
Saving a snapshot on quit and restoring a snapshot from a stored location on initialization. Assumes this code has been loaded into the html file defined in the providerUrl
of the platform attribute in your application’s manifest.
The Override class as presented below should be returned to Platform.init
setLastSnapshot
gets a snapshot of the running platform instance upon invocation, and saves snapshot object as a serialized JSON string in localStorage.
getLastSnapshot
retrieves the JSON string representation item from localStorage.
quit
override method called anytime a platform entity with the given provider url invokes the quit method. In this recipe we call setLastSnapshot
.
applySnapshot
override method called anytime a platform entity with the given provider url invokes the applySnapshot method. In this recipe we call getLastSnapshot
.
Example
class Override extends Provider {
async setLastSnapShot = () => {
const snapshot = await fin.Platform.getCurrentSync().getSnapshot();
localStorage.setItem("last-saved-snapshot", JSON.stringify(snapshot))
}
getLastSnapShot = () => {
const snapshot = localStorage.getItem("last-saved-snapshot");
return JSON.parse(snapshot);
}
async quit(...args) {
await this.setLastSnapshot();
return super.quit(...args);
}
async applySnapshot({ snapshot, options }, callerIdentity) {
const lastSnapshot = this.getLastSnapshot();
if(lastSnapshot) {
return super.applySnapshot({snapshot: lastSnapshot, options}, callerIdentity)
} else {
return super.applySnapshot({ snapshot, options }, callerIdentity)
}
}
};
Launching a Headless Platform
Use Case
Headless Platform for Launching Platform Windows and applying snapshots
Description
An alternative approach to Provider overrides and snapshot logic, for handling additional edges cases while reducing code complexity.
app.json
Main application manifest
default-snapshot.json
Snapshot to load if there’s not one in localStorage
platform-provider.js
Js file to load the logic in the provider window
platform-window.js
Executed in the context of the defaultWindowUrl
content
platform-window.html
Include the platform-window.js
to be executed in the context of the defaultWindowUrl
platform-provider.html
Include the platform-provider.js
to be executed in the context of the providerUrl
.
Example
{
"runtime": {
...
},
"shortcut": {
...
},
"platform": {
"uuid": "platform_customization_local",
"applicationIcon": "https://openfin.github.io/golden-prototype/favicon.ico",
"autoShow": false,
"providerUrl": "http://localhost:5555/provider.html",
"defaultWindowOptions": {
"url": "http://localhost:5555/platform-window.html",
"contextMenu": true,
"defaultLeft": 0,
"defaultTop": 0,
"minHeight": 445
},
"defaultViewOptions": {
...
},
}
}
//NOTE: the manifest does not contain a default snapshot to apply on startup
{
"snapshot": {
"windows": [
{
"url": "http://localhost:5555/main-window.html",
"layout": {
"content": [
{
"type": "stack",
"id": "no-drop-target",
"content": [
{
"type": "component",
"componentName": "view",
"componentState": {
"name": "component_A1",
"processAffinity": "ps_1",
"url": "https://cdn.openfin.co/embed-web/chart.html"
}
}
]
}
]
}
}
]
}
}
//NOTE: A default snapshot to provide the applySnapshot call if the requested snapshot does not exist
(async function() {
await fin.Platform.init();
const snapshotItem = 'snapShot';
const defaultSnapshotUrl = 'http://localhost:5555/default-snapshot.json';
const platform = fin.Platform.getCurrentSync();
const storedSnapshotValue = window.localStorage.getItem(snapshotItem);
const storedSnapshot = storedSnapshotValue && JSON.parse(storedSnapshotValue);
if(storedSnapshot) {
return platform.applySnapshot(storedSnapshot);
} else {
const defaultSnapshotReq = await window.fetch(defaultSnapshotUrl);
const defaultSnapshot = await defaultSnapshotReq.json();
return platform.applySnapshot(defaultSnapshot.snapshot);
}
}
)();
//Executed in the context of the defaultWindowUrl content
async function restoreWindowLayout() {
const storedWinLayout = localStorage.getItem(fin.me.identity.name);
if (storedWinLayout) {
return fin.Platform.Layout.getCurrentSync()
.replace(JSON.parse(storedWinLayout));
} else {
throw new Error("No snapshot found in localstorage");
}
}
//Include the platform-window.js to be executed in the context of the defaultWindowUrl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>OpenFin Template</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="module" src="platform-window.js"></script>
</head>
<!-- default window content -->
.
.
.
</html>
//Include the platform-provider.js to be executed in the context of the providerUrl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>OpenFin Template</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="module" src="platform-provider.js"></script>
</head>
<!-- default window content -->
.
.
.
</html>
Updated 7 months ago