Skip to content

Commit

Permalink
Broke out default interop broker into a module
Browse files Browse the repository at this point in the history
Evaluating the previous approach where modules could be specified in an array and the default could be applied before or after highlighted there may be cases where you need to have an interop override load before and after the default implementation so the old approach was too restrictive and added complexity for understanding.

The default implementation has been broken out into an interop override module and the helper methods have been updated to make this possible (in a backwards compatible way). The default implementation does now need to be listed in the array but it gives a lot more options and makes it easier to understand that not including it means you are not loading that logic needlessly.
  • Loading branch information
johnman committed Mar 17, 2024
1 parent 77a344e commit 7aa6ddd
Show file tree
Hide file tree
Showing 23 changed files with 406 additions and 171 deletions.
5 changes: 1 addition & 4 deletions how-to/workspace-platform-starter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@

- Improved performance of switching schemes
- Improved performance of computing dock configuration, especially on theme changes.
- Added modules as an option for platformProvider.interop settings and added interopOverride as a module generation option when calling npm run generate-module e.g. npm run generate-module interopOverride 'my override'. Also added the option of changing when/if the Workspace Platform Starter default interop override runs:
- after (default) - run the Workspace Platform Starter default broker implementation after your interop override modules (so the default implementation is the base class)
- before - run the Workspace Platform Starter default broker implementation before your interop override modules (so your interop overrides are the base class for our default implementation)
- never - never use the Workspace Platform Starter default implementation (So you will be responsible for adding full interop broker support through your modules)
- Breaking Change (if you do not update your manifest): Added modules as an option for platformProvider.interop settings and made the workspace platform starter interop override a module (so you can decide to load it, chain it with other overrides or exclude it). Please see the new document [how to customize your interop broker](./docs/how-to-customize-your-interop-broker.md). If you want the default interop broker to check endpoints to see if a context type should be enriched through an endpoint then you need to add the wps-interop-override module id to the endpoint clients array in the endpointProvider (see the manifest.fin.json as an example).

## v17.2.0

Expand Down
1 change: 1 addition & 0 deletions how-to/workspace-platform-starter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The information below provides information related to configuring and using the
| [Add Intent Support To Your App](./docs/how-to-add-intent-support-to-your-app.md) | If you have added one or more apps to your platform you may want one to trigger a workflow in another using FDC3. |
| [Configure Your Platform's Intent Support](./docs/how-to-configure-fdc3-intents.md) | How to configure your platform's Intent support. What UI to present to the user if they have to make an application selection after an intent is raised. |
| [Add FDC3 Open Support To Your App](./docs/how-to-add-open-support-to-your-app.md) | If you have added one or more apps to your platform you may wish to have them easily opened using fdc3.open with the option of passing context. |
| [Customize Your Interop Broker](./docs/how-to-customize-your-interop-broker.md) | You now have control over the interop broker beyond settings. You can use the default implementation, replace it or extend it without having to touch the main codebase. |
| [Use Notifications](./docs/how-to-use-notifications.md) | Your platform or you app(s) may want to get the end user's attention and capture a response. |
| [Customize The Bootstrapping Process](./docs/how-to-customize-the-bootstrapping-process.md) | This section covers how you can manage what gets registered and what background behavior do you want to run (e.g. do you want to register all of the Workspace Components or just some of them?). |
| [Theme Your Platform](./docs/how-to-theme-your-platform.md) | The workspace components support a dark theme out of the box. This section covers how to define the theme and logo for your platform and some tools that make that process easier. |
Expand Down
22 changes: 18 additions & 4 deletions how-to/workspace-platform-starter/client/src/framework/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import {
} from "@openfin/workspace-platform";
import { getApp, getApps } from "./apps";
import { checkCondition, conditionChanged } from "./conditions";
import * as connectionProvider from "./connections";
import * as Dialog from "./dialog";
import { getEndpointClient } from "./endpoint";
import type { EndpointClient } from "./endpoint-client";
import * as favoriteProvider from "./favorite";
import { launch } from "./launch";
import { bringToFront, launch } from "./launch";
import { subscribeLifecycleEvent, unsubscribeLifecycleEvent } from "./lifecycle";
import { createLogger } from "./logger-provider";
import { MANIFEST_TYPES } from "./manifest-types";
import * as Menu from "./menu";
import { launchPage, launchView } from "./platform/browser";
import type { PlatformApp, UpdatableLaunchPreference } from "./shapes/app-shapes";
import type { PlatformApp, PlatformAppIdentifier, UpdatableLaunchPreference } from "./shapes/app-shapes";
import type { ConditionContextTypes, ConditionsClient } from "./shapes/conditions-shapes";
import type { ConnectionValidationOptions, ConnectionValidationResponse } from "./shapes/connection-shapes";
import type { DialogClient } from "./shapes/dialog-shapes";
import type { FavoriteClient } from "./shapes/favorite-shapes";
import type { Logger } from "./shapes/logger-shapes";
Expand Down Expand Up @@ -279,6 +281,7 @@ export async function closedownModule<
export function getDefaultHelpers(): ModuleHelpers {
return {
sessionId: passedSessionId,
bringAppToFront: bringToFront,
getPlatform: getCurrentSync,
getApps: async (): Promise<PlatformApp[]> => {
logger.info("getApps: getting public apps for module.");
Expand All @@ -293,16 +296,27 @@ export function getDefaultHelpers(): ModuleHelpers {
getConditionsClient,
getShareClient,
getDialogClient,
launchApp: async (appId: string, launchPreference?: UpdatableLaunchPreference): Promise<void> => {
isConnectionValid: async <T>(
identity: OpenFin.Identity,
payload?: unknown,
options?: ConnectionValidationOptions<T>
): Promise<ConnectionValidationResponse> =>
connectionProvider.isConnectionValid<T>(identity, payload, options),
launchApp: async (
appId: string,
launchPreference?: UpdatableLaunchPreference
): Promise<PlatformAppIdentifier[] | undefined> => {
logger.info(`launchApp: Looking up appId: ${appId}`);
const app = await getApp(appId);
let result: PlatformAppIdentifier[] | undefined;
if (isEmpty(app)) {
logger.warn(`launchApp: The specified appId: ${appId} is not listed in this platform.`);
} else {
logger.info(`launchApp: Launching app with appId: ${appId}`);
await launch(app, launchPreference);
result = await launch(app, launchPreference);
logger.info(`launchApp: App with appId: ${appId} launched.`);
}
return result;
},
launchPage: async (
pageId: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import type { WindowPositioningOptions } from "../shapes/browser-shapes";
import type { PlatformInteropOverride, PlatformInteropOverrideOptions } from "../shapes/interopbroker-shapes";
import type { ModuleDefinition, ModuleEntry, ModuleHelpers } from "../shapes/module-shapes";
import type { PlatformProviderOptions } from "../shapes/platform-shapes";
import { isEmpty } from "../utils";
import { getConstructorOverride } from "./broker/interop-override";

const logger = createLogger("InteropProvider");
const allOverrides: OpenFin.ConstructorOverride<OpenFin.InteropBroker>[] = [];
Expand All @@ -24,7 +22,7 @@ export async function init(
windowPositioningOptions: WindowPositioningOptions,
helpers: ModuleHelpers
): Promise<void> {
if (options) {
if (options && !isInitialized) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { modules: moduleOptions, ...settings } = options?.interop ?? {};
const interopOverrideSettings: PlatformInteropOverrideOptions | undefined = settings;
Expand Down Expand Up @@ -52,28 +50,12 @@ export async function init(

logger.info("Getting interop overrides...");

if (
interopOverrideSettings?.defaultBrokerStrategy === "after" ||
isEmpty(interopOverrideSettings?.defaultBrokerStrategy)
) {
logger.info(
"Adding default interop override so it executes after the list of custom interop overrides"
);
allOverrides.push(await getConstructorOverride(interopOverrideSettings));
}
for (const interopModule of modules) {
const interopConstructor =
await interopModule.implementation.getConstructorOverride(interopOverrideSettings);
allOverrides.push(interopConstructor);
logger.info(`Added interopOverride module: ${interopModule.definition.id}`);
}
if (interopOverrideSettings?.defaultBrokerStrategy === "before") {
logger.info("Adding default interop override so it runs before the list of custom interop overrides");
allOverrides.push(await getConstructorOverride(interopOverrideSettings));
}
if (interopOverrideSettings?.defaultBrokerStrategy === "never") {
logger.info("The default interop override will not be added and will not be executed.");
}
logger.info("Finished setting up interop overrides.");
isInitialized = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ export type PlatformInteropOverrideOptions = Omit<PlatformInteropBrokerOptions,
* Options for the platform interop broker.
*/
export interface PlatformInteropBrokerOptions extends ModuleList {
/**
* The platform includes a default broker override and this setting allows you to control when it is called.
* If you wish to have the default interop override execute after your logic (it is the base) then set this to "after" (the default if not set).
* If you wish to have the default interop override execute before your logic (your modules are the base) then set this to "before".
* If you wish to just use your modules then you can specify "never" and the default interop override will not execute anywhere (Please note this
* will mean you will be responsible for implementing all interop broker logic beyond the base runtime implementation).
*/
defaultBrokerStrategy?: "before" | "after" | "never";
/**
* Intent Resolver configuration if you wish to support intents. It needs to support the functions required by the
* platform
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type OpenFin from "@openfin/core";
import type { BrowserWindowModule, WorkspacePlatformModule } from "@openfin/workspace-platform";
import type { PlatformApp, UpdatableLaunchPreference } from "./app-shapes";
import type { PlatformApp, PlatformAppIdentifier, UpdatableLaunchPreference } from "./app-shapes";
import type { ConditionsClient } from "./conditions-shapes";
import type { ConnectionValidationOptions, ConnectionValidationResponse } from "./connection-shapes";
import type { DialogClient } from "./dialog-shapes";
import type { EndpointClient } from "./endpoint-shapes";
import type { FavoriteClient } from "./favorite-shapes";
Expand Down Expand Up @@ -78,6 +79,14 @@ export interface ModuleHelpers {
*/
sessionId: string;

/**
* Given an application definition and some platform identifiers bring the application to the front.
* @param platformApp The app to determine how to bring the application to the front
* @param platformAppIdentifiers The platform identifiers to bring to the front.
* @returns Nothing.
*/
bringAppToFront?(platformApp: PlatformApp, platformAppIdentifiers: PlatformAppIdentifier[]): Promise<void>;

/**
* Get the current platform.
* @returns The current platform.
Expand Down Expand Up @@ -166,14 +175,30 @@ export interface ModuleHelpers {
*/
getDialogClient?(): Promise<DialogClient | undefined>;

/**
* If the platform has been configured to list supported connections then this API can provide a way of validating the connection.
* @param identity The identity of the connection.
* @param payload The payload to validate if provided.
* @param options The options for the validation (provides additional information such as the type of connection that is trying to be made).
* @returns The response from the validation.
*/
isConnectionValid?<T>(
identity: OpenFin.Identity,
payload?: unknown,
options?: ConnectionValidationOptions<T>
): Promise<ConnectionValidationResponse>;

/**
* If available, this function lets you request the launch of an application that is available to this platform and
* the current user.
* @param appId The id of the application that is registered against the currently running platform
* @param launchPreference If the app supports launch preferences then these can be passed.
* @returns Nothing.
* @returns An array of the platform identities that related from the launch or nothing if nothing was launched.
*/
launchApp?(appId: string, launchPreference?: UpdatableLaunchPreference): Promise<void>;
launchApp?(
appId: string,
launchPreference?: UpdatableLaunchPreference
): Promise<PlatformAppIdentifier[] | undefined>;

/**
* Launch a page in the workspace.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AppsForIntent, PlatformApp } from "../../shapes/app-shapes";
import type { AppIntents } from "../../shapes/fdc3-2-0-shapes";
import type { Logger } from "../../shapes/logger-shapes";
import { isEmpty } from "../../utils";
import type { AppsForIntent, PlatformApp } from "workspace-platform-starter/shapes/app-shapes";
import type { AppIntents } from "workspace-platform-starter/shapes/fdc3-2-0-shapes";
import type { Logger } from "workspace-platform-starter/shapes/logger-shapes";
import { isEmpty } from "workspace-platform-starter/utils";

/**
* The App Intent Helper inspects app catalogs to discover supported intents and contexts.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import type {
IntentRegistrationPayload,
CaptureApiPayload,
ApiMetadata
} from "../../shapes/interopbroker-shapes";
import type { Logger } from "../../shapes/logger-shapes";
import { isEmpty, isStringValue } from "../../utils";
} from "workspace-platform-starter/shapes/interopbroker-shapes";
import type { Logger } from "workspace-platform-starter/shapes/logger-shapes";
import { isEmpty, isStringValue } from "workspace-platform-starter/utils";

/**
* Used to track client interactions with a broker.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { ResolveError } from "@finos/fdc3";
import type OpenFin from "@openfin/core";
import type { AppIntent } from "@openfin/workspace-platform";
import type { PlatformApp } from "../../shapes/app-shapes";
import type { IntentResolverResponse, IntentResolverOptions } from "../../shapes/interopbroker-shapes";
import type { Logger } from "../../shapes/logger-shapes";
import { formatError, isEmpty } from "../../utils";
import { centerContentInIdentity } from "../../utils-position";
import type { PlatformApp } from "workspace-platform-starter/shapes/app-shapes";
import type {
IntentResolverResponse,
IntentResolverOptions
} from "workspace-platform-starter/shapes/interopbroker-shapes";
import type { Logger } from "workspace-platform-starter/shapes/logger-shapes";
import { formatError, isEmpty } from "workspace-platform-starter/utils";
import { centerContentInIdentity } from "workspace-platform-starter/utils-position";

/**
* An Intent Resolver Used for resolving intent selection.
Expand Down
Loading

0 comments on commit 7aa6ddd

Please sign in to comment.