From 085d0483efa564c49cec8ab11088c87f07fa0df4 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 20 May 2022 11:49:33 +0100 Subject: [PATCH 1/6] Add a recommended set of user channels to the Standard --- CHANGELOG.md | 1 + docs/api/spec.md | 85 +++++++++++++++++- src/api/RecommendedChannels.ts | 90 +++++++++++++++++++ src/index.ts | 1 + .../static/schemas/next/app-directory.yaml | 2 +- 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/api/RecommendedChannels.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 863dc38ac..3c17224db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added details of FDC3's existing versioning and deprecation policies to the FDC3 compliance page ([#539](https://github.com/finos/FDC3/pull/539)) * Added a new experimental features policy, which exempts features designated as experimental from the versioning and deprecation policies, to the FDC3 compliance page ([#549](https://github.com/finos/FDC3/pull/549)) * Add `IntentDeliveryFailed` to the `ResolveError` enumeration to be used when delivery of an intent and context to a targetted app or instance fails. ([#601](https://github.com/finos/FDC3/pull/601)) +* Added a recommended set of user channel definitions to the API docs and typescript sources ([#727](https://github.com/finos/FDC3/pull/726)) ### Changed * Consolidated `Listener` documentation with other types ([#404](https://github.com/finos/FDC3/pull/404)) diff --git a/docs/api/spec.md b/docs/api/spec.md index f1812b2f4..7a1229332 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -332,7 +332,90 @@ Calling `fdc3.broadcast` will now route context to the joined channel. Channel implementations SHOULD ensure that context messages broadcast by an application on a channel are not delivered back to that same application if they are joined to the channel. - > Prior to FDC3 2.0, 'user' channels were known as 'system' channels. They were renamed in FDC 2.0 to reflect their intended usage, rather than the fact that they are created by system (which could also create 'app' channels). The `joinChannel` function was also renamed to `joinUserChannel` to clarify that it is only intended to be used to join 'user', rather than 'app', channels. + > Prior to FDC3 2.0, 'user' channels were known as 'system' channels. They were renamed in FDC3 2.0 to reflect their intended usage, rather than the fact that they are created by system (which could also create 'app' channels). The `joinChannel` function was also renamed to `joinUserChannel` to clarify that it is only intended to be used to join 'user', rather than 'app', channels. + +### Recommended User Channel Set + +Desktop Agent implementations SHOULD use the following set of channels, to enable a consistent user experience across different implementations. Desktop Agent implementation MAY support configuration of the user channels. + +> Note: Future versions of the FDC3 Standard may support connections between desktop agents, where differing user channel sets may cause user experience issues. + +```javascript +const recommendedChannels = [ + { + "id": "A", + "type": "user", + "displayMetadata": { + "name": "Channel A", + "color": "red", + "glyph": "A" + } + }, + { + "id": "B", + "type": "user", + "displayMetadata": { + "name": "Channel B", + "color": "orange", + "glyph": "B" + } + }, + { + "id": "C", + "type": "user", + "displayMetadata": { + "name": "Channel C", + "color": "yellow", + "glyph": "C" + } + }, + { + "id": "D", + "type": "user", + "displayMetadata": { + "name": "Channel D", + "color": "green", + "glyph": "D" + } + }, + { + "id": "E", + "type": "user", + "displayMetadata": { + "name": "Channel E", + "color": "lightblue", + "glyph": "E" + } + }, + { + "id": "F", + "type": "user", + "displayMetadata": { + "name": "Channel F", + "color": "blue", + "glyph": "F" + } + }, + { + "id": "G", + "type": "user", + "displayMetadata": { + "name": "Channel G", + "color": "purple", + "glyph": "G" + } + }, + { + "id": "H", + "type": "user", + "displayMetadata": { + "name": "Channel H", + "color": "brown", + "glyph": "H" + } + } +]; +``` ### Direct Listening and Broadcast on Channels While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic _App Channels_. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. diff --git a/src/api/RecommendedChannels.ts b/src/api/RecommendedChannels.ts new file mode 100644 index 000000000..f3dcbcfd6 --- /dev/null +++ b/src/api/RecommendedChannels.ts @@ -0,0 +1,90 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS FDC3 contributors - see NOTICE file + */ + +import { DisplayMetadata } from './DisplayMetadata'; + +/** Interface representing the data fields of a user channel, without the functions. */ +interface UserChannelTemplate { + readonly id: string; + readonly type: 'user'; + readonly displayMetadata?: DisplayMetadata; +} + +const recommendedChannels: Array = [ + { + id: 'A', + type: 'user', + displayMetadata: { + name: 'Channel A', + color: 'red', + glyph: 'A', + }, + }, + { + id: 'B', + type: 'user', + displayMetadata: { + name: 'Channel B', + color: 'orange', + glyph: 'B', + }, + }, + { + id: 'C', + type: 'user', + displayMetadata: { + name: 'Channel C', + color: 'yellow', + glyph: 'C', + }, + }, + { + id: 'D', + type: 'user', + displayMetadata: { + name: 'Channel D', + color: 'green', + glyph: 'D', + }, + }, + { + id: 'E', + type: 'user', + displayMetadata: { + name: 'Channel E', + color: 'lightblue', + glyph: 'E', + }, + }, + { + id: 'F', + type: 'user', + displayMetadata: { + name: 'Channel F', + color: 'blue', + glyph: 'F', + }, + }, + { + id: 'G', + type: 'user', + displayMetadata: { + name: 'Channel G', + color: 'purple', + glyph: 'G', + }, + }, + { + id: 'H', + type: 'user', + displayMetadata: { + name: 'Channel H', + color: 'brown', + glyph: 'H', + }, + }, +]; + +export default recommendedChannels; diff --git a/src/index.ts b/src/index.ts index 6209bae89..54215c3ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ export * from './api/IntentResolution'; export * from './api/Listener'; export * from './api/ImplementationMetadata'; export * from './api/Methods'; +export * from './api/RecommendedChannels'; export * from './context/ContextType'; export * from './context/ContextTypes'; export * from './intents/Intents'; diff --git a/website/static/schemas/next/app-directory.yaml b/website/static/schemas/next/app-directory.yaml index e7261c4c6..bece799ed 100644 --- a/website/static/schemas/next/app-directory.yaml +++ b/website/static/schemas/next/app-directory.yaml @@ -378,7 +378,7 @@ components: type: string description: >- A comma separated list of the types of contexts the intent offered by the application can process, - where the first part of the context type is the namespace e.g."fdc3.contact", "org.symphony.contact" + where the first part of the context type is the namespace e.g."fdc3.contact, org.symphony.contact" resultType: type: string description: >- From 5c4de541b47e21e2212e861c78cf682441ddada4 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 25 May 2022 12:04:34 +0100 Subject: [PATCH 2/6] Switching to arabic numerals for channel names + losing brown in favour of turquoise --- docs/api/spec.md | 131 +++++++++++++++++---------------- src/api/RecommendedChannels.ts | 56 +++++++------- 2 files changed, 94 insertions(+), 93 deletions(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index 7a1229332..7e42232a5 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -342,82 +342,83 @@ Desktop Agent implementations SHOULD use the following set of channels, to enabl ```javascript const recommendedChannels = [ - { - "id": "A", - "type": "user", - "displayMetadata": { - "name": "Channel A", - "color": "red", - "glyph": "A" - } + { + id: 'Channel 1', + type: 'user', + displayMetadata: { + name: 'Channel 1', + color: 'red', + glyph: '1', }, - { - "id": "B", - "type": "user", - "displayMetadata": { - "name": "Channel B", - "color": "orange", - "glyph": "B" - } + }, + { + id: 'Channel 2', + type: 'user', + displayMetadata: { + name: 'Channel 2', + color: 'orange', + glyph: '2', }, - { - "id": "C", - "type": "user", - "displayMetadata": { - "name": "Channel C", - "color": "yellow", - "glyph": "C" - } + }, + { + id: 'Channel 3', + type: 'user', + displayMetadata: { + name: 'Channel 3', + color: 'yellow', + glyph: '3', }, - { - "id": "D", - "type": "user", - "displayMetadata": { - "name": "Channel D", - "color": "green", - "glyph": "D" - } + }, + { + id: 'Channel 4', + type: 'user', + displayMetadata: { + name: 'Channel 4', + color: 'green', + glyph: '4', }, - { - "id": "E", - "type": "user", - "displayMetadata": { - "name": "Channel E", - "color": "lightblue", - "glyph": "E" - } + }, + { + id: 'Channel 5', + type: 'user', + displayMetadata: { + name: 'Channel 5', + color: 'turquoise', + glyph: '5', }, - { - "id": "F", - "type": "user", - "displayMetadata": { - "name": "Channel F", - "color": "blue", - "glyph": "F" - } + }, + { + id: 'Channel 6', + type: 'user', + displayMetadata: { + name: 'Channel 6', + color: 'lightblue', + glyph: '6', }, - { - "id": "G", - "type": "user", - "displayMetadata": { - "name": "Channel G", - "color": "purple", - "glyph": "G" - } + }, + { + id: 'Channel 7', + type: 'user', + displayMetadata: { + name: 'Channel 7', + color: 'blue', + glyph: '7', }, - { - "id": "H", - "type": "user", - "displayMetadata": { - "name": "Channel H", - "color": "brown", - "glyph": "H" - } - } + }, + { + id: 'Channel 8', + type: 'user', + displayMetadata: { + name: 'Channel 8', + color: 'purple', + glyph: '8', + }, + }, ]; ``` ### Direct Listening and Broadcast on Channels + While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic _App Channels_. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. ### App Channels diff --git a/src/api/RecommendedChannels.ts b/src/api/RecommendedChannels.ts index f3dcbcfd6..e5aab43e9 100644 --- a/src/api/RecommendedChannels.ts +++ b/src/api/RecommendedChannels.ts @@ -14,75 +14,75 @@ interface UserChannelTemplate { const recommendedChannels: Array = [ { - id: 'A', + id: 'Channel 1', type: 'user', displayMetadata: { - name: 'Channel A', + name: 'Channel 1', color: 'red', - glyph: 'A', + glyph: '1', }, }, { - id: 'B', + id: 'Channel 2', type: 'user', displayMetadata: { - name: 'Channel B', + name: 'Channel 2', color: 'orange', - glyph: 'B', + glyph: '2', }, }, { - id: 'C', + id: 'Channel 3', type: 'user', displayMetadata: { - name: 'Channel C', + name: 'Channel 3', color: 'yellow', - glyph: 'C', + glyph: '3', }, }, { - id: 'D', + id: 'Channel 4', type: 'user', displayMetadata: { - name: 'Channel D', + name: 'Channel 4', color: 'green', - glyph: 'D', + glyph: '4', }, }, { - id: 'E', + id: 'Channel 5', type: 'user', displayMetadata: { - name: 'Channel E', - color: 'lightblue', - glyph: 'E', + name: 'Channel 5', + color: 'turquoise', + glyph: '5', }, }, { - id: 'F', + id: 'Channel 6', type: 'user', displayMetadata: { - name: 'Channel F', - color: 'blue', - glyph: 'F', + name: 'Channel 6', + color: 'lightblue', + glyph: '6', }, }, { - id: 'G', + id: 'Channel 7', type: 'user', displayMetadata: { - name: 'Channel G', - color: 'purple', - glyph: 'G', + name: 'Channel 7', + color: 'blue', + glyph: '7', }, }, { - id: 'H', + id: 'Channel 8', type: 'user', displayMetadata: { - name: 'Channel H', - color: 'brown', - glyph: 'H', + name: 'Channel 8', + color: 'purple', + glyph: '8', }, }, ]; From 4666d8cd946801a0dd398f53cfa5017092107114 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 25 May 2022 12:06:40 +0100 Subject: [PATCH 3/6] mark down lint --- docs/api/spec.md | 87 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index 7e42232a5..fd6728f59 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -9,7 +9,9 @@ The role of FDC3 API is to establish a baseline interface for interoperability b The following sections examine the API's use-cases and core concepts. The APIs a fully defined in both subsequent pages of this Part and a full set of TypeScript definitions in the [src](https://github.com/finos/FDC3/tree/master/src/api) directory of the [FDC3 GitHub repository](https://github.com/finos/FDC3/). ## Components + ### Desktop Agent + A Desktop Agent is a desktop component (or aggregate of components) that serves as a launcher and message router (broker) for applications in its domain. A Desktop Agent can be connected to one or more App Directories and will use directories for application identity and discovery. Typically, a Desktop Agent will contain the proprietary logic of a given platform, handling functionality like explicit application interop workflows where security, consistency, and implementation requirements are proprietary. Examples of Desktop Agents include: @@ -23,17 +25,21 @@ Examples of Desktop Agents include: An FDC3-compliant Desktop Agent exposes an FDC3 standard API to applications they have launched. When an App is launched by a Desktop Agent and is given access to the Agent's API to interoperate, it is running in that Desktop Agent's *context*. ### Application + An application is any endpoint on the desktop that is: + - Registered with/known by a Desktop Agent - Launchable by a Desktop Agent - Addressable by a Desktop Agent Examples of End Points include: + - Native Applications - Web Applications - Headless “services” running on the desktop ## Desktop Agent Implementation + The FDC3 API specification consists of interfaces. It is expected that each Desktop Agent will implement these interfaces. A typical implemention would provide instantiable classes for the following interfaces: - [`DesktopAgent`](ref/DesktopAgent) @@ -57,6 +63,7 @@ Other interfaces defined in the spec are not critical to define as concrete type - [`TargetApp`](ref/Types#targetapp) ### API Access + The FDC3 API can be made available to an application through a number of different methods. In the case of web applications, a Desktop Agent MUST provide the FDC3 API via a global accessible as `window.fdc3`. Implementors MAY additionally make the API available through modules, imports, or other means. The global `window.fdc3` must only be available after the API is ready to use. To enable applications to avoid using the API before it is ready, implementors MUST provide a global `fdc3Ready` event that is fired when the API is ready for use. Implementations should first check for the existence of the FDC3 API and add a listener for this event if it is not found: @@ -74,11 +81,13 @@ if (window.fdc3) { ``` ### Standards vs. Implementation + ![Desktop Agent - Standards Schematic](assets/api-1.png) The surface area of FDC3 standardization (shown in *white* above) itself is quite small in comparison to the extent of a typical desktop agent implementation (in *grey*). For example: + - workspace management - user identity and SSO - entitlements @@ -87,6 +96,7 @@ For example: Are all areas of functionality that any feature complete desktop agent would implement, but are not currently areas considered for standardization under FDC3. ### Inter-Agent Communication + A goal of FDC3 standards is that applications running in different Desktop Agent contexts on the same desktop would be able to interoperate. And that one Desktop Agent context would be able to discover and launch an application in another Desktop Application context. ![Desktop Agent - Interop](assets/api-2.png) @@ -98,6 +108,7 @@ An actual connection protocol between Desktop Agents is not currently available ## Functional Use Cases ### Retrieve Metadata about the Desktop Agent implementation + From version 1.2 of the FDC3 specification, Desktop Agent implementations MUST provide a `fdc3.getInfo()` function to allow apps to retrieve information about the version of the FDC3 specification supported by a Desktop Agent implementation and the name of the implementation provider. This metadata can be used to vary the behavior of an application based on the version supported by the Desktop Agent, e.g.: ```js @@ -111,11 +122,12 @@ if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), '1.2')) { ``` ### Open an Application by Name -Linking from one application to another is a critical basic workflow that the web revolutionized via the hyperlink. Supporting semantic addressing of applications across different technologies and platform domains greatly reduces friction in linking different applications into a single workflow. +Linking from one application to another is a critical basic workflow that the web revolutionized via the hyperlink. Supporting semantic addressing of applications across different technologies and platform domains greatly reduces friction in linking different applications into a single workflow. ### Requesting Functionality From Another App -Often, we want to link from one app to another to dynamically create a workflow. Enabling this without requiring prior knowledge between apps is a key goal of FDC3 and is implemented via the raising of [intents](../intents/spec), which represent a desired action, to be performed with a [context](../context/spec) supplied as input. + +Often, we want to link from one app to another to dynamically create a workflow. Enabling this without requiring prior knowledge between apps is a key goal of FDC3 and is implemented via the raising of [intents](../intents/spec), which represent a desired action, to be performed with a [context](../context/spec) supplied as input. Intents provide a way for an app to request functionality from another app and defer the discovery and launching of the destination app to the Desktop Agent. There are multiple models for interop that intents can support. @@ -124,23 +136,27 @@ Intents provide a way for an app to request functionality from another app and d - **Remote API**: An app wants to remote an entire API that it owns to another App. In this case, the API for the App cannot be standardized. However, the FDC3 API can address how an App connects to another App in order to get access to a proprietary API. ### Send/broadcast Context + On the financial desktop, applications often want to broadcast [context](../context/spec) to any number of applications. Context sharing needs to support different groupings of applications, which is supported via the concept of 'channels', over which context is broadcast and received by other applications listening to the channel. In some cases, an application may want to communicate with a single application or service and to prevent other applications from participating in the communication. For single transactions, this can instead be implemented via a raised intent, which will be delivered to a single application that can, optionally, respond with data. Alternatively, it may instead respond with a [`Channel`](ref/Channel) or [`PrivateChannel`](ref/PrivateChannel) over which a stream of responses or a dialog can be supported. ## Raising Intents -Raising an Intent is a method for an application to request functionality from another application and, if desired, defer the discovery and launching of the destination app to the Desktop Agent. + +Raising an Intent is a method for an application to request functionality from another application and, if desired, defer the discovery and launching of the destination app to the Desktop Agent. ### Intents and Context + When raising an intent a specific context is provided as input. The type of the provided context may determine which applications can resolve the intent. -A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents. +A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents. To raise an Intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an Intent listener or in an App Directory). As an alternative to raising a specific intent, you may also raise an unspecified intent with a known context allowing the Desktop Agent or the user (if the intent is ambiguous) to select the appropriate intent and then to raise it with the specified context for resolution. ### Intent Results + An optional [`IntentResult`](ref/Types#intentresult) may also be returned as output by an application handling an intent. Results maybe either a single `Context` object, or a `Channel` that may be used to send a stream of responses. The [`PrivateChannel`](ref/PrivateChannel) type is provided to support synchronisation of data transmitted over returned channels, by allowing both parties to listen for events denoting subscription and unsubscription from the returned channel. `PrivateChannels` are only retrievable via [raising an intent](ref/DesktopAgent#raiseintent). For example, an application handling a `CreateOrder` intent might return a context representing the order and including an ID, allowing the application that raised the intent to make further calls using that ID. @@ -148,6 +164,7 @@ For example, an application handling a `CreateOrder` intent might return a conte An optional result type is also supported when programmatically resolving an intent via [`findIntent`](ref/DesktopAgent#findintent) or [`findIntentByContext`](ref/DesktopAgent#findintentbycontext). ### Resolvers + Successful delivery of an intent depends first upon the Desktop Agent's ability to "resolve the intent" (i.e. map the intent to a specific App instance). Where the target application is ambiguous (because there is more than one application that could resolve the intent and context) Desktop Agents may resolve intents by any suitable methodology. A common method is to display a UI that allows the user to pick the desired App from a list of those that will accept the intent and context. Alternatively, the app issuing the intent may proactively handle resolution by calling [`findIntent`](ref/DesktopAgent#findintent) or [`findIntentByContext`](ref/DesktopAgent#findintentbycontext) and then raise the intent with a specific target application, e.g.: ```js @@ -189,22 +206,26 @@ const appIntents = await fdc3.findIntentByContext(context); await fdc3.raiseIntent(appIntent[0].intent, context, appIntent[0].apps[0]); ``` -Result context types requested are represented by their type name. A channel may be requested by passing the string `"channel"` or a channel that returns a specific type via the syntax `"channel"`, e.g. `"channel"`. Requesting intent resolution to an app returning a channel MUST include apps that are registered as returning a channel with a specific type. +Result context types requested are represented by their type name. A channel may be requested by passing the string `"channel"` or a channel that returns a specific type via the syntax `"channel"`, e.g. `"channel"`. Requesting intent resolution to an app returning a channel MUST include apps that are registered as returning a channel with a specific type. ### Intent Resolution + Raising an intent will return a Promise-type object that will resolve/reject based on a number of factors. #### Resolve + - Intent was resolved unambiguously and the receiving app was launched successfully (if necessary). - Intent was ambiguous, a resolution was chosen by the end user, and the chosen application was launched successfully. #### Reject + - No app matching the intent and context (if specified) was found. - A match was found, but the receiving app failed to launch. - The intent was ambiguous and the resolver experienced an error. #### Resolution Object -If the raising of the intent resolves (or rejects), a standard [`IntentResolution`](ref/Metadata#intentresolution) object will be passed into the resolver function with details of the application that resolved the intent and the means to access any results subsequently returned. + +If the raising of the intent resolves (or rejects), a standard [`IntentResolution`](ref/Metadata#intentresolution) object will be passed into the resolver function with details of the application that resolved the intent and the means to access any results subsequently returned. For example, to raise a specific intent: @@ -228,6 +249,7 @@ catch (err){ ... } ``` Use metadata about the resolving app instance to target a further intent + ```js try { const resolution = await fdc3.raiseIntent('StageOrder', context); @@ -240,6 +262,7 @@ catch (err) { ... } ``` Raise an intent and retrieve either data or a channel from the IntentResolution: + ```js let resolution = await agent.raiseIntent("intentName", context); try { @@ -258,50 +281,53 @@ try { ``` ### Register an Intent Handler + Applications need to let the system know the intents they can support. Typically, this is done via registration with an [App Directory](../app-directory/spec). It is also possible for intents to be registered at the application level as well to support ad-hoc registration which may be helpful at development time. Although dynamic registration is not part of this specification, a Desktop Agent agent may choose to support any number of registration paths. When an instance of an application is launched, it is expected to add an [`IntentHandler`](ref/Types#intenthandler) function to the desktop agent for each intent it has registered by calling the [`fdc3.addIntentListener`](ref/DesktopAgent#addintentlistener) function of the Desktop Agent. Doing so allows the Desktop Agent to pass incoming intents and contexts to that instance of the application. Hence, if the application instance was spawned in response to the raised intent, then the Desktop Agent must wait for the relevant intent listener to be added by that instance, before it can deliver the intent and context to it. In order to facilitate accurate error responses, calls to `fdc3.raiseIntent` should not return an `IntentResolution` until the intent handler has been added and the intent delivered to the target app. #### Compliance with Intent Standards + Intents represent a contract with expected behaviour if an app asserts that it supports the intent. Where this contract is enforceable by schema (for example, return object types), the FDC3 API implementation SHOULD enforce compliance and return an error if the interface is not met. It is expected that App Directories SHOULD also curate listed apps and ensure that they are complying with declared intents. - ## Context Channels Context channels allows a set of apps to share a stateful piece of data between them, and be alerted when it changes. Use cases for channels include color linking between applications to automate the sharing of context and topic based pub/sub such as theme. ### Types of Channel + There are three types of channels, which have different visibility and discoverability semantics: -1. **_User channels_**, which: - * facilitate the creation of user-controlled context links between applications (often via the selection of a color channel), - * are created and named by the desktop agent, - * are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call), - * can be 'joined' (via the [`joinUserChannel()`](ref/DesktopAgent#joinuserchannel) API call). +1. ***User channels***, which: + - facilitate the creation of user-controlled context links between applications (often via the selection of a color channel), + - are created and named by the desktop agent, + - are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call), + - can be 'joined' (via the [`joinUserChannel()`](ref/DesktopAgent#joinuserchannel) API call). > **Note:** Prior to FDC3 2.0, 'user' channels were known as 'system' channels. They were renamed in FDC3 2.0 to reflect their intended usage, rather than the fact that they are created by system (which could also create 'app' channels). > **Note:** Earlier versions of FDC3 included the concept of a 'global' system channel which was deprecated in FDC3 1.2 and removed in FDC3 2.0. -2. **_App channels_**, which: - * facilitate developer controlled messaging between applications, - * are created and named by applications (via the [`getOrCreateChannel()`](ref/DesktopAgent#getorcreatechannel) API call), - * are not discoverable, - * are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) +2. ***App channels***, which: + - facilitate developer controlled messaging between applications, + - are created and named by applications (via the [`getOrCreateChannel()`](ref/DesktopAgent#getorcreatechannel) API call), + - are not discoverable, + - are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) -3. **_Private_** channels, which: - * facilitate private communication between two parties, - * have an auto-generated identity and can only be retrieved via a raised intent. +3. ***Private*** channels, which: + - facilitate private communication between two parties, + - have an auto-generated identity and can only be retrieved via a raised intent. Channels are interacted with via `broadcast` and `addContextListener` functions, allowing an application to send and receive Context objects via the channel. For User channels, these functions are provided on the Desktop Agent, e.g. [`fdc3.broadcast(context)`](ref/DesktopAgent#broadcast), and apply to channels joined via [`fdc3.joinUserChannel`](ref/DesktopAgent#joinuserchannel). For App channels, a channel object must be retrieved, via [`fdc3.getOrCreateChannel(channelName)`](ref/DesktopAgent#getorcreatechannel), which provides the functions, i.e. [`myChannel.broadcast(context)`](ref/Channel#broadcast) and [`myChannel.addContextListener(context)`](ref/Channel#addcontextlistener). For `PrivateChannels`, a channel object must also be retrieved, but via an intent raised with [`fdc3.raiseIntent(intent, context)`](ref/DesktopAgent#raiseintent) and returned as an [`IntentResult`](ref/Types#intentresult). Channel implementations SHOULD ensure that context messages broadcast by an application on a channel are not delivered back to that same application if they are also listening on the channel. ### Joining User Channels -Apps can join _User channels_. An app can only be joined to one User channel at a time. + +Apps can join *User channels*. An app can only be joined to one User channel at a time. When an app is joined to a User channel, calls to [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be routed to that channel and listeners added through [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will receive context broadcasts from other apps also joined to that channel. If an app is not joined to a User channel [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be a no-op and handler functions added with [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will not receive any broadcasts. However, apps can still choose to listen and broadcast to specific channels (both User and App channels) via the methods on the [`Channel`](ref/Channel) class. @@ -309,11 +335,12 @@ When an app joins a User channel, or adds a context listener when already joined It is possible that a call to join a User channel could be rejected. If for example, the desktop agent wanted to implement controls around what data apps can access. -Joining channels in FDC3 is intended to be a behavior initiated by the end user. For example: by color linking or apps being grouped in the same workspace. Most of the time, it is expected that apps will be joined to a channel by mechanisms outside of the app. To support programmatic management of joined channels and the implementation of channel selector UIs other than those provided outside of the app, Desktop Agent implementations MAY provide [`fdc3.joinChannel()`](ref/DesktopAgent#joinchannel), [`fdc3.getCurrentChannel()](ref/DesktopAgent#getcurrentchannel) and [`fdc3.leaveCurrentChannel()`](ref/DesktopAgent#leavecurrentchannel) functions and if they do, MUST do so as defined in the [Desktop Agent API reference](ref/DesktopAgent). +Joining channels in FDC3 is intended to be a behavior initiated by the end user. For example: by color linking or apps being grouped in the same workspace. Most of the time, it is expected that apps will be joined to a channel by mechanisms outside of the app. To support programmatic management of joined channels and the implementation of channel selector UIs other than those provided outside of the app, Desktop Agent implementations MAY provide [`fdc3.joinChannel()`](ref/DesktopAgent#joinchannel), [`fdc3.getCurrentChannel()](ref/DesktopAgent#getcurrentchannel) and [`fdc3.leaveCurrentChannel()`](ref/DesktopAgent#leavecurrentchannel) functions and if they do, MUST do so as defined in the [Desktop Agent API reference](ref/DesktopAgent). There SHOULD always be a clear UX indicator of what channel an app is joined to. #### Examples + To find a User channel, one calls: ```js @@ -419,9 +446,10 @@ const recommendedChannels = [ ### Direct Listening and Broadcast on Channels -While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic _App Channels_. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. +While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic *App Channels*. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. ### App Channels + App Channels are topics dynamically created by applications connected via FDC3. For example, an app may` create a channel to broadcast to others data or status specific to that app. To get (or create) a channel reference, then interact with it: @@ -459,17 +487,18 @@ if another application broadcasts to "my_custom_channel" (by retrieving it and b ### Private Channels -`PrivateChannels` are created to support the return of a stream of responses from a raised intent, or private dialog between two applications. +`PrivateChannels` are created to support the return of a stream of responses from a raised intent, or private dialog between two applications. It is intended that Desktop Agent implementations: - * - SHOULD restrict external apps from listening or publishing on this channel. - * - MUST prevent `PrivateChannels` from being retrieved via `fdc3.getOrCreateChannel`. - * - MUST provide the `id` value for the channel as required by the `Channel` interface. + +- SHOULD restrict external apps from listening or publishing on this channel. +- MUST prevent `PrivateChannels` from being retrieved via `fdc3.getOrCreateChannel`. +- MUST provide the `id` value for the channel as required by the `Channel` interface. The `PrivateChannel` type also supports synchronisation of data transmitted over returned channels. They do so by extending the `Channel` interface with event handlers which provide information on the connection state of both parties, ensuring that desktop agents do not need to queue or retain messages that are broadcast before a context listener is added and that applications are able to stop broadcasting messages when the other party has disconnected. ### Broadcasting and listening for multiple context types -The [Context specification](../../context/spec#assumptions) recommends that complex context objects are defined using simpler context types for particular fields. For example, a `Position` is composed of an `Instrument` and a holding amount. This leads to situations where an application may be able to receive or respond to context objects that are embedded in a more complex type, but not the more complex type itself. For example, a pricing chart might respond to an `Instrument` but doesn't know how to handle a `Position`. -To facilitate context linking in such situations it is recommended that applications `broadcast` each context type that other apps (listening on a User Channel or App Channel) may wish to process, starting with the simpler types, followed by the complex type. Doing so allows applications to filter the context types they receive by adding listeners for specific context types - but requires that the application broadcasting context make multiple broadcast calls in quick succession when sharing its context. +The [Context specification](../../context/spec#assumptions) recommends that complex context objects are defined using simpler context types for particular fields. For example, a `Position` is composed of an `Instrument` and a holding amount. This leads to situations where an application may be able to receive or respond to context objects that are embedded in a more complex type, but not the more complex type itself. For example, a pricing chart might respond to an `Instrument` but doesn't know how to handle a `Position`. +To facilitate context linking in such situations it is recommended that applications `broadcast` each context type that other apps (listening on a User Channel or App Channel) may wish to process, starting with the simpler types, followed by the complex type. Doing so allows applications to filter the context types they receive by adding listeners for specific context types - but requires that the application broadcasting context make multiple broadcast calls in quick succession when sharing its context. From 413208b54cfcea193980e5209de6f7faba57717d Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 25 May 2022 12:32:22 +0100 Subject: [PATCH 4/6] tweakj recommended channel color schema again --- docs/api/spec.md | 6 +++--- src/api/RecommendedChannels.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index fd6728f59..b7bc56f17 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -410,7 +410,7 @@ const recommendedChannels = [ type: 'user', displayMetadata: { name: 'Channel 5', - color: 'turquoise', + color: 'cyan', glyph: '5', }, }, @@ -419,7 +419,7 @@ const recommendedChannels = [ type: 'user', displayMetadata: { name: 'Channel 6', - color: 'lightblue', + color: 'blue', glyph: '6', }, }, @@ -428,7 +428,7 @@ const recommendedChannels = [ type: 'user', displayMetadata: { name: 'Channel 7', - color: 'blue', + color: 'magenta', glyph: '7', }, }, diff --git a/src/api/RecommendedChannels.ts b/src/api/RecommendedChannels.ts index e5aab43e9..795bc9335 100644 --- a/src/api/RecommendedChannels.ts +++ b/src/api/RecommendedChannels.ts @@ -54,7 +54,7 @@ const recommendedChannels: Array = [ type: 'user', displayMetadata: { name: 'Channel 5', - color: 'turquoise', + color: 'cyan', glyph: '5', }, }, @@ -63,7 +63,7 @@ const recommendedChannels: Array = [ type: 'user', displayMetadata: { name: 'Channel 6', - color: 'lightblue', + color: 'blue', glyph: '6', }, }, @@ -72,7 +72,7 @@ const recommendedChannels: Array = [ type: 'user', displayMetadata: { name: 'Channel 7', - color: 'blue', + color: 'magenta', glyph: '7', }, }, From 9298f36f0b6f09f4efa728b81fcc2b203ce46e95 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 26 May 2022 12:51:17 +0100 Subject: [PATCH 5/6] namespacing recommended channel names --- docs/api/spec.md | 16 ++++++++-------- src/api/RecommendedChannels.ts | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index b7bc56f17..f5c5ed39c 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -370,7 +370,7 @@ Desktop Agent implementations SHOULD use the following set of channels, to enabl ```javascript const recommendedChannels = [ { - id: 'Channel 1', + id: 'fdc3.channel.1', type: 'user', displayMetadata: { name: 'Channel 1', @@ -379,7 +379,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 2', + id: 'fdc3.channel.2', type: 'user', displayMetadata: { name: 'Channel 2', @@ -388,7 +388,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 3', + id: 'fdc3.channel.3', type: 'user', displayMetadata: { name: 'Channel 3', @@ -397,7 +397,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 4', + id: 'fdc3.channel.4', type: 'user', displayMetadata: { name: 'Channel 4', @@ -406,7 +406,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 5', + id: 'fdc3.channel.5', type: 'user', displayMetadata: { name: 'Channel 5', @@ -415,7 +415,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 6', + id: 'fdc3.channel.6', type: 'user', displayMetadata: { name: 'Channel 6', @@ -424,7 +424,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 7', + id: 'fdc3.channel.7', type: 'user', displayMetadata: { name: 'Channel 7', @@ -433,7 +433,7 @@ const recommendedChannels = [ }, }, { - id: 'Channel 8', + id: 'fdc3.channel.8', type: 'user', displayMetadata: { name: 'Channel 8', diff --git a/src/api/RecommendedChannels.ts b/src/api/RecommendedChannels.ts index 795bc9335..502181a85 100644 --- a/src/api/RecommendedChannels.ts +++ b/src/api/RecommendedChannels.ts @@ -14,7 +14,7 @@ interface UserChannelTemplate { const recommendedChannels: Array = [ { - id: 'Channel 1', + id: 'fdc3.channel.1', type: 'user', displayMetadata: { name: 'Channel 1', @@ -23,7 +23,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 2', + id: 'fdc3.channel.2', type: 'user', displayMetadata: { name: 'Channel 2', @@ -32,7 +32,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 3', + id: 'fdc3.channel.3', type: 'user', displayMetadata: { name: 'Channel 3', @@ -41,7 +41,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 4', + id: 'fdc3.channel.4', type: 'user', displayMetadata: { name: 'Channel 4', @@ -50,7 +50,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 5', + id: 'fdc3.channel.5', type: 'user', displayMetadata: { name: 'Channel 5', @@ -59,7 +59,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 6', + id: 'fdc3.channel.6', type: 'user', displayMetadata: { name: 'Channel 6', @@ -68,7 +68,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 7', + id: 'fdc3.channel.7', type: 'user', displayMetadata: { name: 'Channel 7', @@ -77,7 +77,7 @@ const recommendedChannels: Array = [ }, }, { - id: 'Channel 8', + id: 'fdc3.channel.8', type: 'user', displayMetadata: { name: 'Channel 8', From 7299630d9c121eb074ffb55bf7e8bb6f9c778e09 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 26 May 2022 12:57:45 +0100 Subject: [PATCH 6/6] whitespace change to trigger deploy --- website/blog/2017-09-25-testing-rss.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/blog/2017-09-25-testing-rss.md b/website/blog/2017-09-25-testing-rss.md index b7ff8129c..401995913 100644 --- a/website/blog/2017-09-25-testing-rss.md +++ b/website/blog/2017-09-25-testing-rss.md @@ -9,3 +9,4 @@ authorFBID: 661277173 This should be truncated. This line should never render in XML. + \ No newline at end of file