From 643df332770af95574cd6ec30e035527494bf1b9 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 15 Oct 2021 18:16:07 +0100 Subject: [PATCH 01/11] Rename deprecate getSystemChannels and replaces with getUserChannels (API, methods.ts, docs, spec) --- docs/api/ref/Channel.md | 10 +++--- docs/api/ref/DesktopAgent.md | 38 ++++++++++++-------- docs/api/ref/Metadata.md | 2 +- docs/api/spec.md | 70 +++++++++++++++++++----------------- src/api/Channel.ts | 4 +-- src/api/DesktopAgent.ts | 27 ++++++++------ src/api/Methods.ts | 13 ++++++- test/Methods.test.ts | 18 +++++++--- 8 files changed, 109 insertions(+), 73 deletions(-) diff --git a/docs/api/ref/Channel.md b/docs/api/ref/Channel.md index 71717405f..0ad3ad323 100644 --- a/docs/api/ref/Channel.md +++ b/docs/api/ref/Channel.md @@ -8,7 +8,7 @@ hide_title: true Represents a context channel that applications can join to share context data. -A channel can be either a well-known "system" channel (retrieved with [`getSystemChannels`](DesktopAgent#getsystemchannels)) or a custom "app" channel (obtained through [`getOrCreateChannel`](DesktopAgent#getorcreatechannel)). +A channel can be either a "User" channel (retrieved with [`getUserChannels`](DesktopAgent#getuserchannels)) or a custom "App" channel (obtained through [`getOrCreateChannel`](DesktopAgent#getorcreatechannel)). Channels each have a unique identifier, some display metadata and operations for broadcasting context to other applications, or receiving context from other applications. @@ -34,7 +34,7 @@ interface Channel { * [`Context`](Types#context) * [`Listener`](Types#listener) -* [`DesktopAgent.getSystemChannels`](DesktopAgent#getsystemchannels) +* [`DesktopAgent.getUserChannels`](DesktopAgent#getuserchannels) * [`DesktopAgent.getOrCreateChannel`](DesktopAgent#getorcreatechannel) * [`DesktopAgent.joinChannel`](DesktopAgent#joinchannel) @@ -46,7 +46,7 @@ interface Channel { public readonly id: string; ``` -Uniquely identifies the channel. It is either assigned by the desktop agent (system channel) or defined by an application (app channel). +Uniquely identifies the channel. It is either assigned by the desktop agent (User Channel) or defined by an application (App Channel). ### `type` @@ -62,7 +62,7 @@ Can be _system_ or _app_. public readonly displayMetadata?: DisplayMetadata; ``` -DisplayMetadata can be used to provide display hints for channels intended to be visualized and selectable by end users. +DisplayMetadata can be used to provide display hints for User Channels intended to be visualized and selectable by end users. #### See also * [`DisplayMetadata`](Metadata#displaymetadata) @@ -130,7 +130,7 @@ instrumentListener.unsubscribe(); public broadcast(context: Context): void; ``` -Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on channels that they aren't a member of. +Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on both App Channels and User Channels that they aren't a member of. If the broadcast is denied by the channel or the channel is not available, the method will return an `Error` with a string from the [`ChannelError`](ChannelError) enumeration. diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index f7b52efdd..2237b9aaa 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -21,7 +21,7 @@ interface DesktopAgent { broadcast(context: Context): void; addContextListener(contextType: string | null, handler: ContextHandler): Listener; /** - * @deprecated 'Use `addContextListener(null, handler)` instead of `addContextListener(handler)` + * @deprecated Use `addContextListener(null, handler)` instead of `addContextListener(handler)` */ addContextListener(handler: ContextHandler): Listener; @@ -34,6 +34,10 @@ interface DesktopAgent { // channels getOrCreateChannel(channelId: string): Promise; + getUserChannels(): Promise>; + /** + * @deprecated Use `getUserChannels()` instead of `getSystemChannels()` + */ getSystemChannels(): Promise>; joinChannel(channelId: string) : Promise; getCurrentChannel() : Promise; @@ -57,7 +61,7 @@ addContextListener(handler: ContextHandler): Listener; ``` Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. -Context broadcasts are only received from apps that are joined to the same channel as the listening application, hence, if the application is not currently joined to a channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. +Context broadcasts are only received from apps that are joined to the same User Channel as the listening application, hence, if the application is not currently joined to a User Channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. #### Examples ```js @@ -101,7 +105,7 @@ const listener = fdc3.addIntentListener('StartChat', context => { broadcast(context: Context): void; ``` -Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever `Channel` the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. +Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever _User Channel_ the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. DesktopAgent implementations should ensure that context messages broadcast to a channel by an application joined to it should not be delivered back to that same application. @@ -201,7 +205,7 @@ A promise resolving to all the intents, their metadata and metadata about the ap getCurrentChannel() : Promise; ``` -Returns the `Channel` object for the current channel membership. Returns `null` if the app is not joined to a channel. +Returns the `Channel` object for the current User Channel membership. Returns `null` if the app is not joined to a channel. #### Examples @@ -247,7 +251,7 @@ if (fdc3.getInfo && versionIsAtLeast(fdc3.getInfo(), "1.2")) { getOrCreateChannel(channelId: string): Promise; ``` -Returns a Channel object for the specified channel, creating it (as an _App_ channel) - if it does not exist. +Returns a Channel object for the specified channel, creating it (as an _App Channel_) - if it does not exist. `Error` with a string from the [`ChannelError`](ChannelError) enumeration if channel could not be created or access was denied. #### Example @@ -255,7 +259,7 @@ Returns a Channel object for the specified channel, creating it (as an _App_ cha ```js try { const myChannel = await fdc3.getOrCreateChannel("myChannel"); - const myChannel.addContextListener(null, context => {}); + myChannel.addContextListener(null, context => { /* do something with context */}); } catch (err){ //app could not register the channel @@ -266,17 +270,21 @@ catch (err){ #### See also * [`Channel`](Channel) -### `getSystemChannels` +### `getUserChannels` ```ts +getUserChannels() : Promise>; +/** + * @deprecated Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. + */ getSystemChannels() : Promise>; ``` -Retrieves a list of the System channels available for the app to join. This should include the 'global' channel. +Retrieves a list of the User Channels available for the app to join. This MAY include the deprecated 'global' channel. #### Example ```js -const systemChannels = await fdc3.getSystemChannels(); -const redChannel = systemChannels.find(c => c.id === 'red'); +const userChannels = await fdc3.getUserChannels(); +const redChannel = userChannels.find(c => c.id === 'red'); ``` #### See also @@ -301,17 +309,17 @@ Rejects with an error if the channel is unavailable or the join request is denie #### Examples ```js -// get all system channels -const channels = await fdc3.getSystemChannels(); +// get all user channels +const channels = await fdc3.getUserChannels(); -// create UI to pick from the system channels +// create UI to pick from the User channels // join the channel on selection fdc3.joinChannel(selectedChannel.id); ``` #### See also -* [`getSystemChannels`](#getSystemChannels) +* [`getUserChannels`](#getuserchannels) @@ -321,7 +329,7 @@ fdc3.joinChannel(selectedChannel.id); leaveCurrentChannel() : Promise; ``` -Removes the app from any channel membership. Context broadcast and listening through the top-level `fdc3.broadcast` and `fdc3.addContextListener` will be a no-op when the app is not joined to a channel. +Removes the app from any channel membership. Context broadcast and listening through the top-level `fdc3.broadcast` and `fdc3.addContextListener` will be a no-op when the app is not joined to a User Channel. #### Examples diff --git a/docs/api/ref/Metadata.md b/docs/api/ref/Metadata.md index 10f310ad9..d5aa8d780 100644 --- a/docs/api/ref/Metadata.md +++ b/docs/api/ref/Metadata.md @@ -64,7 +64,7 @@ A desktop agent (typically for _system_ channels) may want to provide additional #### See also * [`Channel`](Channel) -* [`DesktopAgent.getSystemChannels`](DesktopAgent#getsystemchannels) +* [`DesktopAgent.getUserChannels`](DesktopAgent#getuserchannels) ### Properties diff --git a/docs/api/spec.md b/docs/api/spec.md index 5c0a9b309..6a856726b 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -218,40 +218,44 @@ Context channels allows a set of apps to share a stateful piece of data between There are two types of channels, which are functionally identical, but have different visibility and discoverability semantics. -1. The 'system' channels, which have a well understood identity. +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 destkop agent, + * are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call). - > **Deprecation notice:** Earlier versions of FDC3 include the concept of a 'global' system 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). + + > **Deprecation notice:** Earlier versions of FDC3 include the concept of a 'global' user channel for backwards compatibility with FDC3 1.0. In future, there won't be a 'global' channel (see [below](#the-global-channel) for more detail). -2. The 'app' channels, which have a transient identity and need to be revealed - +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. ### Joining Channels -Apps can join channels. An app can only be joined to one channel at a time. +Apps can join _User Channels_. An app can only be joined to one channel at a time. -When an app is joined to a channel, calls to `fdc3.broadcast` will be routed to that channel and listeners added through `fdc3.addContextListener` will receive context broadcasts from other apps also joined to that channel. If an app is not joined to a channel `fdc3.broadcast` will be a no-op and handler functions added with `fdc3.addContextListener` will not receive any broadcasts. However, apps can still choose to listen and broadcast to specific channels via the methods on the `Channel` class. +When an app is joined to a User Channel, calls to `fdc3.broadcast` will be routed to that channel and listeners added through `fdc3.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` will be a no-op and handler functions added with `fdc3.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` class. -When an app joins a channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel. +When an app joins a User Channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel. -It is possible that a call to join a channel could be rejected. If for example, the desktop agent wanted to implement controls around what data apps can access. +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. Always, there SHOULD be a clear UX indicator of what channel an app is joined to. +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. Always, there SHOULD be a clear UX indicator of what User Channel an app is joined to. ### The 'global' Channel > **Deprecation notice** > -> The global channel, which exists only for backward compatibility with FDC3 1.0, -will be removed in a future version of the FDC3 API Specification. +> The global channel, which exists only for backward compatibility with FDC3 1.0, will be removed in a future version of the FDC3 API Specification. > -> Instead of relying on being joined to a 'default' channel by the desktop agent on startup, -an app or system channel should be joined explicitly through the relevant APIs, -or through a channel selection UI. +> Instead of relying on being joined to a 'default' channel by the desktop agent on startup, a user channel should be joined explicitly through the relevant APIs, or through a channel selection UI. -The 'system' channels include a 'global' channel which serves as the backwards compatible layer with the 'send/broadcast context' behavior in FDC3 1.0. A desktop agent MAY choose to make membership in the 'global' channel the default state for apps on start up. +The User channels MAY include a 'global' channel which serves as the backwards compatible layer with the 'send/broadcast context' behavior in FDC3 1.0. A desktop agent MAY choose to make membership in the 'global' channel the default state for apps on start up. -The 'global' channel should be returned as part of the response from the `fdc3.getSystemChannels` call. Desktop Agents may want to filter out the 'global' option in their UI for system channel pickers. +If supported, the 'global' channel should be returned as part of the response from the `fdc3.getUserChannels` call. Desktop Agents may want to filter out the 'global' option in their UI for User channel pickers. ### Examples @@ -267,40 +271,40 @@ An app can still explicitly receive context events on any channel, regardless of ```js // check for current fdc3 channel -let joinedChannel = await fdc3.getCurrentChannel() -//current channel is null, as the app is not currently joined to a channel +let joinedChannel = await fdc3.getCurrentChannel(); +// current channel is null, as the app is not currently joined to a channel -const redChannel = await fdc3.getSystemChannels.filter(c => c.id === 'red') -const context = await redChannel.getCurrentContext('fdc3.instrument') +const redChannel = await fdc3.getUserChannels.filter(c => c.id === 'red'); +const context = await redChannel.getCurrentContext('fdc3.instrument'); // context is instrument AAPL on the global channel -fdc3.joinChannel('blue') -joinedChannel = await fdc3.getCurrentChannel() -//current channel is now the 'blue' channel - +fdc3.addContextListener(null, (context) => { /* do something with context */ }); +// listen for any context broadcasts for channels that we join +fdc3.joinChannel('blue'); +// join the 'blue' channel, the current context of the channel will be received immeadiately +joinedChannel = await fdc3.getCurrentChannel(); +// current channel is now the 'blue' channel ``` ### Direct Listening and Broadcast on Channels -While joining channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the _Channel.addBroadcastListener_ and the _Channel.broadcast_ APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. +While joining User Channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the _Channel.addBroadcastListener_ and the _Channel.broadcast_ APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. ### 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 System 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. - - +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. ### Examples -To find a system channel, one calls +To find a User Channel, one calls: ```js // returns an array of channels -const allChannels = await fdc3.getSystemChannels(); +const allChannels = await fdc3.getUserChannels(); const redChannel = allChannels.find(c => c.id === 'red'); ``` #### Joining channels -To join a system channel. one calls +To join a User Channel, one calls: ```js fdc3.joinChannel(redChannel.id); @@ -312,9 +316,9 @@ Channel implementations should ensure that context messages broadcast by an appl #### 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. +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 +To get (or create) a channel reference, then interact with it: ```js const appChannel = await fdc3.getOrCreateChannel('my_custom_channel'); diff --git a/src/api/Channel.ts b/src/api/Channel.ts index 86a96d14a..990bad867 100644 --- a/src/api/Channel.ts +++ b/src/api/Channel.ts @@ -24,7 +24,7 @@ export interface Channel { /** * Channels may be visualized and selectable by users. DisplayMetadata may be used to provide hints on how to see them. - * For app channels, displayMetadata would typically not be present + * For App channels, displayMetadata would typically not be present. */ readonly displayMetadata?: DisplayMetadata; @@ -33,7 +33,7 @@ export interface Channel { * top-level FDC3 `broadcast` function. * * Note that this function can be used without first joining the channel, allowing applications to broadcast on - * channels that they aren't a member of. + * User channels that they aren't a member of. * * Channel implementations should ensure that context messages broadcast by an application on a channel should * not be delivered back to that same application if they are joined to the channel. diff --git a/src/api/DesktopAgent.ts b/src/api/DesktopAgent.ts index 6b449a6f6..9e5bd6e4d 100644 --- a/src/api/DesktopAgent.ts +++ b/src/api/DesktopAgent.ts @@ -102,7 +102,7 @@ export interface DesktopAgent { findIntentsByContext(context: Context): Promise>; /** - * Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever `Channel` the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. + * Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever _User Channel_ the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. * * DesktopAgent implementations should ensure that context messages broadcast to a channel by an application joined to it should not be delivered back to that same application. * @@ -172,14 +172,14 @@ export interface DesktopAgent { addIntentListener(intent: string, handler: ContextHandler): Listener; /** - * Adds a listener for incoming context broadcast from the Desktop Agent. + * Adds a listener for incoming context broadcasts from the Desktop Agent. * @deprecated use `addContextListener(null, handler)` instead of `addContextListener(handler)`. */ addContextListener(handler: ContextHandler): Listener; /** - * Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. - * Context broadcasts are only received from apps that are joined to the same channel as the listening application, hence, if the application is not currently joined to a channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. + * Adds a listener for incoming context broadcasts from the Desktop Agent via User channels. If the consumer is only interested in a context of a particular type, they can they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. + * Context broadcasts are only received from apps that are joined to the same User channel as the listening application, hence, if the application is not currently joined to a channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. * ```javascript * // any context * const listener = fdc3.addContextListener(null, context => { ... }); @@ -190,20 +190,25 @@ export interface DesktopAgent { addContextListener(contextType: string | null, handler: ContextHandler): Listener; /** - * Retrieves a list of the System channels available for the app to join + * Retrieves a list of the User channels available for the app to join. + */ + getUserChannels(): Promise>; + + /** + * @deprecated Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. */ getSystemChannels(): Promise>; /** - * Joins the app to the specified channel. + * Joins the app to the specified User channel. * If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. * If the channel already contains context that would be passed to context listeners assed via `fdc3.addContextListener` then those listeners will be called immediately with that context. * An app can only be joined to one channel at a time. * Rejects with an error if the channel is unavailable or the join request is denied. The error string will be drawn from the `ChannelError` enumeration. * ```javascript * // get all system channels - * const channels = await fdc3.getSystemChannels(); - * // create UI to pick from the system channels + * const channels = await fdc3.getUserChannels(); + * // create UI to pick from the User channels * // join the channel on selection * fdc3.joinChannel(selectedChannel.id); * ``` @@ -211,7 +216,7 @@ export interface DesktopAgent { joinChannel(channelId: string): Promise; /** - * Returns a channel with the given identity. Either stands up a new channel or returns an existing channel. + * Returns an App channel with the given identity. Either stands up a new channel or returns an existing channel. * It is up to applications to manage how to share knowledge of these custom channels across windows and to manage * channel ownership and lifecycle. * `Error` with a string from the `ChannelError` enumeration. @@ -219,13 +224,13 @@ export interface DesktopAgent { getOrCreateChannel(channelId: string): Promise; /** - * Returns the `Channel` object for the current channel membership. + * Returns the `Channel` object for the current User channel membership. * Returns `null` if the app is not joined to a channel. */ getCurrentChannel(): Promise; /** - * Removes the app from any channel membership. + * Removes the app from any User channel membership. * Context broadcast and listening through the top-level `fdc3.broadcast` and `fdc3.addContextListener` will be a no-op when the app is not on a channel. * ```javascript * //desktop-agent scope context listener diff --git a/src/api/Methods.ts b/src/api/Methods.ts index 631769eac..508a7d9ab 100644 --- a/src/api/Methods.ts +++ b/src/api/Methods.ts @@ -79,8 +79,19 @@ export function addContextListener( } } +export function getUserChannels(): Promise { + return rejectIfNoGlobal(() => { + //fallback to getSystemChannels for FDC3 <2.0 implementations + if (window.fdc3.getUserChannels) { + return window.fdc3.getUserChannels(); + } else { + return window.fdc3.getSystemChannels(); + } + }); +} + export function getSystemChannels(): Promise { - return rejectIfNoGlobal(() => window.fdc3.getSystemChannels()); + return getUserChannels(); } export function joinChannel(channelId: string): Promise { diff --git a/test/Methods.test.ts b/test/Methods.test.ts index 6d525f73d..f83e69a03 100644 --- a/test/Methods.test.ts +++ b/test/Methods.test.ts @@ -13,6 +13,7 @@ import { getCurrentChannel, getInfo, getOrCreateChannel, + getUserChannels, getSystemChannels, ImplementationMetadata, joinChannel, @@ -79,8 +80,8 @@ describe('test ES6 module', () => { expect(() => addContextListener(expect.any(String), expect.any(Object))).toThrowError(UnavailableError); }); - test('getSystemChannels should reject', async () => { - await expect(getSystemChannels()).rejects.toEqual(UnavailableError); + test('getUserChannels should reject', async () => { + await expect(getUserChannels()).rejects.toEqual(UnavailableError); }); test('joinChannel should reject', async () => { @@ -187,11 +188,18 @@ describe('test ES6 module', () => { expect(window.fdc3.addContextListener).toHaveBeenNthCalledWith(2, null, handler2); }); - test('getSystemChannels should delegate to window.fdc3.getSystemChannels', async () => { + test('getUserChannels should delegate to window.fdc3.getUserChannels', async () => { + await getUserChannels(); + + expect(window.fdc3.getUserChannels).toHaveBeenCalledTimes(1); + expect(window.fdc3.getUserChannels).toHaveBeenCalledWith(); + }); + + test('getSystemChannels should delegate to window.fdc3.getUserChannels', async () => { await getSystemChannels(); - expect(window.fdc3.getSystemChannels).toHaveBeenCalledTimes(1); - expect(window.fdc3.getSystemChannels).toHaveBeenCalledWith(); + expect(window.fdc3.getUserChannels).toHaveBeenCalledTimes(2); //was already called in previous test, hence this should be the second call to getUserChannels + expect(window.fdc3.getUserChannels).toHaveBeenCalledWith(); }); test('joinChannel should delegate to window.fdc3.joinChannel', async () => { From 558283ea964a97ece9320f3b9b9b1bd3915f5890 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 15 Oct 2021 18:39:50 +0100 Subject: [PATCH 02/11] Ensure getSystemChannels is still in docs and standardize capitalisation of "User channels" --- docs/api/ref/DesktopAgent.md | 18 +++++++++++++----- docs/api/spec.md | 18 +++++++++--------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index 2237b9aaa..36a6af649 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -273,11 +273,8 @@ catch (err){ ### `getUserChannels` ```ts getUserChannels() : Promise>; -/** - * @deprecated Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. - */ -getSystemChannels() : Promise>; ``` + Retrieves a list of the User Channels available for the app to join. This MAY include the deprecated 'global' channel. #### Example @@ -290,6 +287,17 @@ const redChannel = userChannels.find(c => c.id === 'red'); #### See also * [`Channel`](Channel) +### `getSystemChannels` +```ts +/** + * @deprecated Use `getUserChannels` instead. + */ +getSystemChannels() : Promise>; +``` + +Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. +#### See also +* [`getUserChannels`](#getuserchannels) ### `joinChannel` @@ -297,7 +305,7 @@ const redChannel = userChannels.find(c => c.id === 'red'); joinChannel(channelId: string) : Promise; ``` -Joins the app to the specified channel. +Joins the app to the specified User channel. If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. If the channel already contains context that would be passed to context listeners added via `fdc3.addContextListener` then those listeners will be called immediately with that context. diff --git a/docs/api/spec.md b/docs/api/spec.md index 6a856726b..49a4e0930 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -237,13 +237,13 @@ There are two types of channels, which are functionally identical, but have diff ### Joining Channels Apps can join _User Channels_. An app can only be joined to one channel at a time. -When an app is joined to a User Channel, calls to `fdc3.broadcast` will be routed to that channel and listeners added through `fdc3.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` will be a no-op and handler functions added with `fdc3.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` class. +When an app is joined to a User channel, calls to `fdc3.broadcast` will be routed to that channel and listeners added through `fdc3.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` will be a no-op and handler functions added with `fdc3.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` class. -When an app joins a User Channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel. +When an app joins a User channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel. -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. +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. Always, there SHOULD be a clear UX indicator of what User Channel an app is joined to. +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. Always, there SHOULD be a clear UX indicator of what User channel an app is joined to. ### The 'global' Channel @@ -251,7 +251,7 @@ Joining channels in FDC3 is intended to be a behavior initiated by the end user. > > The global channel, which exists only for backward compatibility with FDC3 1.0, will be removed in a future version of the FDC3 API Specification. > -> Instead of relying on being joined to a 'default' channel by the desktop agent on startup, a user channel should be joined explicitly through the relevant APIs, or through a channel selection UI. +> Instead of relying on being joined to a 'default' channel by the desktop agent on startup, a User channel should be joined explicitly through the relevant APIs, or through a channel selection UI. The User channels MAY include a 'global' channel which serves as the backwards compatible layer with the 'send/broadcast context' behavior in FDC3 1.0. A desktop agent MAY choose to make membership in the 'global' channel the default state for apps on start up. @@ -287,7 +287,7 @@ joinedChannel = await fdc3.getCurrentChannel(); ``` ### Direct Listening and Broadcast on Channels -While joining User Channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the _Channel.addBroadcastListener_ and the _Channel.broadcast_ APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. +While joining User Channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the `Channel.addBroadcastListener` and the `Channel.broadcast` APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. ### 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`. @@ -295,7 +295,7 @@ The [Context specification](../../context/spec#assumptions) recommends that comp 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. ### Examples -To find a User Channel, one calls: +To find a User channel, one calls: ```js // returns an array of channels @@ -304,13 +304,13 @@ const redChannel = allChannels.find(c => c.id === 'red'); ``` #### Joining channels -To join a User Channel, one calls: +To join a User channel, one calls: ```js fdc3.joinChannel(redChannel.id); ``` -Calling _fdc3.broadcast_ will now route context to the joined channel. +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 should not be delivered back to that same application if they are joined to the channel. From 03e98a084dfdbf12b4db6bf575310598f2cf208c Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 22 Oct 2021 14:46:42 +0100 Subject: [PATCH 03/11] Renaming joinChannel to joinUserChannel --- docs/api/ref/Channel.md | 2 +- docs/api/ref/DesktopAgent.md | 37 ++++++++++++++++++++++-------- docs/api/ref/Errors.md | 4 ++-- docs/api/spec.md | 24 +++++++++++-------- docs/context/ref/Instrument.md | 2 +- docs/context/ref/InstrumentList.md | 2 +- docs/context/ref/Nothing.md | 2 +- docs/supported-platforms.md | 2 +- src/api/DesktopAgent.ts | 9 ++++++-- src/api/Methods.ts | 15 +++++++++++- 10 files changed, 70 insertions(+), 29 deletions(-) diff --git a/docs/api/ref/Channel.md b/docs/api/ref/Channel.md index 0ad3ad323..b42915396 100644 --- a/docs/api/ref/Channel.md +++ b/docs/api/ref/Channel.md @@ -36,7 +36,7 @@ interface Channel { * [`Listener`](Types#listener) * [`DesktopAgent.getUserChannels`](DesktopAgent#getuserchannels) * [`DesktopAgent.getOrCreateChannel`](DesktopAgent#getorcreatechannel) -* [`DesktopAgent.joinChannel`](DesktopAgent#joinchannel) +* [`DesktopAgent.joinUserChannel`](DesktopAgent#joinuserchannel) ## Properties diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index 36a6af649..d0e6f21e5 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -35,16 +35,22 @@ interface DesktopAgent { // channels getOrCreateChannel(channelId: string): Promise; getUserChannels(): Promise>; - /** - * @deprecated Use `getUserChannels()` instead of `getSystemChannels()` - */ - getSystemChannels(): Promise>; - joinChannel(channelId: string) : Promise; + joinUserChannel(channelId: string) : Promise; getCurrentChannel() : Promise; leaveCurrentChannel() : Promise; //implementation info getInfo(): ImplementationMetadata; + + /** + * @deprecated Use `getUserChannels()` instead of `getSystemChannels()` + */ + getSystemChannels(): Promise>; + /** + * @deprecated Use `joinUserChannel()` instead of `joinChannel()` + */ + joinChannel(channelId: string) : Promise; + } ``` @@ -295,14 +301,14 @@ const redChannel = userChannels.find(c => c.id === 'red'); getSystemChannels() : Promise>; ``` -Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. +Alias to the [`getUserChannels`](#getuserchannels) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. #### See also * [`getUserChannels`](#getuserchannels) -### `joinChannel` +### `joinUserChannel` ```ts -joinChannel(channelId: string) : Promise; +joinUserChannel(channelId: string) : Promise; ``` Joins the app to the specified User channel. @@ -323,13 +329,26 @@ const channels = await fdc3.getUserChannels(); // create UI to pick from the User channels // join the channel on selection -fdc3.joinChannel(selectedChannel.id); +fdc3.joinUserChannel(selectedChannel.id); ``` #### See also * [`getUserChannels`](#getuserchannels) +### `joinChannel` + +```ts +/** + * @deprecated Use `joinUserChannel()` instead of `joinChannel()` + */ +joinChannel(channelId: string) : Promise; +``` +Alias to the [`joinUserChannel`](#joinUserChannel) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. + +#### See also +* [`joinUserChannel`](#joinuserchannel) + ### `leaveCurrentChannel` diff --git a/docs/api/ref/Errors.md b/docs/api/ref/Errors.md index c2ca879d9..5d4ec05a8 100644 --- a/docs/api/ref/Errors.md +++ b/docs/api/ref/Errors.md @@ -46,10 +46,10 @@ enum ChannelError { } ``` -Contains constants representing the errors that can be encountered when calling channels using the [`joinChannel`](DesktopAgent#joinchannel) or [`getOrCreateChannel`](DesktopAgent#getorcreatechannel) methods, or the [`getCurrentContext`](Channel#getcurrentcontext), [`broadcast`](Channel#broadcast) or [`addContextListener`](Channel#addcontextlistener) methods on the `Channel` object. +Contains constants representing the errors that can be encountered when calling channels using the [`joinUserChannel`](DesktopAgent#joinuserchannel) or [`getOrCreateChannel`](DesktopAgent#getorcreatechannel) methods, or the [`getCurrentContext`](Channel#getcurrentcontext), [`broadcast`](Channel#broadcast) or [`addContextListener`](Channel#addcontextlistener) methods on the `Channel` object. #### See also -* [`DesktopAgent.joinChannel`](DesktopAgent#joincannel) +* [`DesktopAgent.joinUserChannel`](DesktopAgent#joinusercannel) * [`DesktopAgent.getOrCreateChannel`](DesktopAgent#getorcreatechannel) * [`Channel.broadcast`](Channel#broadcast) * [`Channel.addContextListener`](Channel#addcontextlistener) diff --git a/docs/api/spec.md b/docs/api/spec.md index 49a4e0930..28b9fb28b 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -220,8 +220,9 @@ There are two types of channels, which are functionally identical, but have diff 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 destkop agent, - * are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call). + * 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). > 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). @@ -232,10 +233,11 @@ There are two types of channels, which are functionally identical, but have diff 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 not discoverable, + * are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) ### Joining Channels -Apps can join _User Channels_. An app can only be joined to one channel at a time. +Apps can join _User channels_. An app can only be joined to one channel at a time. When an app is joined to a User channel, calls to `fdc3.broadcast` will be routed to that channel and listeners added through `fdc3.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` will be a no-op and handler functions added with `fdc3.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` class. @@ -270,9 +272,9 @@ const context = await redChannel.getCurrentContext('fdc3.instrument'); An app can still explicitly receive context events on any channel, regardless of the channel it is currently joined to. ```js -// check for current fdc3 channel +// check for current User channel let joinedChannel = await fdc3.getCurrentChannel(); -// current channel is null, as the app is not currently joined to a channel +// current channel is null, as the app is not currently joined to a user channel const redChannel = await fdc3.getUserChannels.filter(c => c.id === 'red'); const context = await redChannel.getCurrentContext('fdc3.instrument'); @@ -280,14 +282,14 @@ const context = await redChannel.getCurrentContext('fdc3.instrument'); fdc3.addContextListener(null, (context) => { /* do something with context */ }); // listen for any context broadcasts for channels that we join -fdc3.joinChannel('blue'); +fdc3.joinUserChannel('blue'); // join the 'blue' channel, the current context of the channel will be received immeadiately joinedChannel = await fdc3.getCurrentChannel(); // current channel is now the 'blue' channel ``` ### Direct Listening and Broadcast on Channels -While joining User Channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the `Channel.addBroadcastListener` and the `Channel.broadcast` APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. +While joining User channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. ### 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`. @@ -302,18 +304,20 @@ To find a User channel, one calls: const allChannels = await fdc3.getUserChannels(); const redChannel = allChannels.find(c => c.id === 'red'); ``` -#### Joining channels +#### Joining User channels To join a User channel, one calls: ```js -fdc3.joinChannel(redChannel.id); +fdc3.joinUserChannel(redChannel.id); ``` 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 should not be 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. + #### 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. diff --git a/docs/context/ref/Instrument.md b/docs/context/ref/Instrument.md index fd5bff8ad..484a7de08 100644 --- a/docs/context/ref/Instrument.md +++ b/docs/context/ref/Instrument.md @@ -59,7 +59,7 @@ const instrument = { } } -fdc3.joinChannel('global') +fdc3.joinUserChannel('Channel 1') fdc3.broadcast(instrument) ``` diff --git a/docs/context/ref/InstrumentList.md b/docs/context/ref/InstrumentList.md index 6119fbc94..8dbc5c9cf 100644 --- a/docs/context/ref/InstrumentList.md +++ b/docs/context/ref/InstrumentList.md @@ -54,7 +54,7 @@ const instruments = { ] } -fdc3.joinChannel('global') +fdc3.joinUserChannel('global') fdc3.broadcast(instruments) ``` diff --git a/docs/context/ref/Nothing.md b/docs/context/ref/Nothing.md index e017bb6a9..a0a802605 100644 --- a/docs/context/ref/Nothing.md +++ b/docs/context/ref/Nothing.md @@ -34,6 +34,6 @@ const nullContext = { type: 'fdc3.nothing' } -fdc3.joinChannel('groupA') +fdc3.joinUserChannel('groupA') fdc3.broadcast(nullContext) ``` \ No newline at end of file diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md index c838173d1..f10aa70d8 100644 --- a/docs/supported-platforms.md +++ b/docs/supported-platforms.md @@ -53,7 +53,7 @@ const instrument = { const result = await fdc3.raiseIntent('ViewAnalysis', instrument) // join the red channel and broadcast data to subscribers -await fdc3.joinChannel('red') +await fdc3.joinUserChannel('red') fdc3.broadcast(instrument) // set up a listener for incoming data diff --git a/src/api/DesktopAgent.ts b/src/api/DesktopAgent.ts index 9e5bd6e4d..087fed51f 100644 --- a/src/api/DesktopAgent.ts +++ b/src/api/DesktopAgent.ts @@ -195,7 +195,7 @@ export interface DesktopAgent { getUserChannels(): Promise>; /** - * @deprecated Alias to the [`getUserChannels`](#getUserChannels) function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. + * @deprecated Alias to the `getUserChannels function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. */ getSystemChannels(): Promise>; @@ -210,9 +210,14 @@ export interface DesktopAgent { * const channels = await fdc3.getUserChannels(); * // create UI to pick from the User channels * // join the channel on selection - * fdc3.joinChannel(selectedChannel.id); + * fdc3.joinUserChannel(selectedChannel.id); * ``` */ + joinUserChannel(channelId: string): Promise; + + /** + * @deprecated Alias to the `joinUserChannel` function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. + */ joinChannel(channelId: string): Promise; /** diff --git a/src/api/Methods.ts b/src/api/Methods.ts index 508a7d9ab..1356e5826 100644 --- a/src/api/Methods.ts +++ b/src/api/Methods.ts @@ -91,11 +91,24 @@ export function getUserChannels(): Promise { } export function getSystemChannels(): Promise { + //fallforward to getUserChannels for FDC3 2.0+ implementations return getUserChannels(); } +export function joinUserChannel(channelId: string): Promise { + return rejectIfNoGlobal(() => { + //fallback to joinChannel for FDC3 <2.0 implementations + if (window.fdc3.joinUserChannel) { + return window.fdc3.joinUserChannel(channelId); + } else { + return window.fdc3.joinChannel(channelId); + } + }); +} + export function joinChannel(channelId: string): Promise { - return rejectIfNoGlobal(() => window.fdc3.joinChannel(channelId)); + //fallforward to joinUserChannel for FDC3 2.0+ implementations + return joinUserChannel(channelId); } export function getOrCreateChannel(channelId: string): Promise { From c9371e461ad4637ee29312e465cd759949452967 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 22 Oct 2021 14:51:25 +0100 Subject: [PATCH 04/11] Renaming joinChannel to joinUserChannel --- src/api/DesktopAgent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/DesktopAgent.ts b/src/api/DesktopAgent.ts index 087fed51f..2d16b44a6 100644 --- a/src/api/DesktopAgent.ts +++ b/src/api/DesktopAgent.ts @@ -213,7 +213,7 @@ export interface DesktopAgent { * fdc3.joinUserChannel(selectedChannel.id); * ``` */ - joinUserChannel(channelId: string): Promise; + joinUserChannel(channelId: string): Promise; /** * @deprecated Alias to the `joinUserChannel` function provided for backwards compatibility with version 1.1 and 1.2 of the FDC3 standard. From a5871d3a0b1531b9a9601255f9c83483e45f8bf7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 27 Oct 2021 16:18:07 +0100 Subject: [PATCH 05/11] Fixing tests post joinChannel rename to joinUserChannel --- test/Methods.test.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/Methods.test.ts b/test/Methods.test.ts index f83e69a03..99e721d2b 100644 --- a/test/Methods.test.ts +++ b/test/Methods.test.ts @@ -17,6 +17,7 @@ import { getSystemChannels, ImplementationMetadata, joinChannel, + joinUserChannel, leaveCurrentChannel, open, raiseIntent, @@ -88,6 +89,10 @@ describe('test ES6 module', () => { await expect(joinChannel(expect.any(String))).rejects.toEqual(UnavailableError); }); + test('joinUserChannel should reject', async () => { + await expect(joinUserChannel(expect.any(String))).rejects.toEqual(UnavailableError); + }); + test('getOrCreateChannel should reject', async () => { await expect(getOrCreateChannel(expect.any(String))).rejects.toEqual(UnavailableError); }); @@ -202,13 +207,22 @@ describe('test ES6 module', () => { expect(window.fdc3.getUserChannels).toHaveBeenCalledWith(); }); - test('joinChannel should delegate to window.fdc3.joinChannel', async () => { + test('joinChannel should delegate to window.fdc3.joinUserChannel', async () => { const channelId = 'channel'; await joinChannel(channelId); - expect(window.fdc3.joinChannel).toHaveBeenCalledTimes(1); - expect(window.fdc3.joinChannel).toHaveBeenCalledWith(channelId); + expect(window.fdc3.joinUserChannel).toHaveBeenCalledTimes(1); + expect(window.fdc3.joinUserChannel).toHaveBeenCalledWith(channelId); + }); + + test('joinUserChannel should delegate to window.fdc3.joinUserChannel', async () => { + const channelId = 'channel'; + + await joinUserChannel(channelId); + + expect(window.fdc3.joinUserChannel).toHaveBeenCalledTimes(2); + expect(window.fdc3.joinUserChannel).toHaveBeenCalledWith(channelId); }); test('getOrCreateChannel should delegate to window.fdc3.getOrCreateChannel', async () => { From 9e38f59d598b90e97bac6abcb095956734bd73e3 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 9 Nov 2021 18:17:54 +0000 Subject: [PATCH 06/11] Changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 695cd9225..d1d4c668d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Changed +* Replaced 'System channels' with 'User channels' throughout the spec, documentation, API and methods.ts. Clarified spec and documentation where it is referring to User channels vs. App channels. Added support to methods.ts for automatic fallback to `getSystemChannels` if `getUserChannels` doesn't exist. ([#470](https://github.com/finos/FDC3/pull/479)) + ## [npm v1.2.0] - 2021-04-19 ### Added From c8a66a3319b70d59d4f2b424b716653a671723cb Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 21 Dec 2021 10:41:40 +0000 Subject: [PATCH 07/11] Apply suggestions from code review Co-authored-by: Matt Jamieson <10372+mattjamieson@users.noreply.github.com> --- docs/api/spec.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index 28b9fb28b..9f5c3779e 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -237,7 +237,7 @@ There are two types of channels, which are functionally identical, but have diff * are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) ### Joining Channels -Apps can join _User channels_. An app can only be joined to one 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` will be routed to that channel and listeners added through `fdc3.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` will be a no-op and handler functions added with `fdc3.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` class. @@ -245,7 +245,7 @@ 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. Always, there SHOULD be a clear UX indicator of what User channel an app is joined to. +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. There SHOULD always be a clear UX indicator of what User channel an app is joined to. ### The 'global' Channel @@ -276,7 +276,7 @@ An app can still explicitly receive context events on any channel, regardless of let joinedChannel = await fdc3.getCurrentChannel(); // current channel is null, as the app is not currently joined to a user channel -const redChannel = await fdc3.getUserChannels.filter(c => c.id === 'red'); +const redChannel = (await fdc3.getUserChannels).find(c => c.id === 'red'); const context = await redChannel.getCurrentContext('fdc3.instrument'); // context is instrument AAPL on the global channel @@ -289,7 +289,7 @@ joinedChannel = await fdc3.getCurrentChannel(); ``` ### Direct Listening and Broadcast on Channels -While joining User channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. +While joining User channels automates a lot of the channel behavior for an app, it has the limitation that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. ### 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`. From 2319b5e255150f0d504093be3c5a2994e825cf38 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 24 Jan 2022 12:48:57 +0000 Subject: [PATCH 08/11] Applying suggestion from code review --- docs/context/ref/InstrumentList.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/context/ref/InstrumentList.md b/docs/context/ref/InstrumentList.md index ea2bbdfe7..9ac458350 100644 --- a/docs/context/ref/InstrumentList.md +++ b/docs/context/ref/InstrumentList.md @@ -54,7 +54,7 @@ const instruments = { ] } -fdc3.joinUserChannel('global') +fdc3.joinUserChannel('Channel 1') fdc3.broadcast(instruments) ``` From 3f0b8765e2fc968484c93e28b9c276bdaee27d41 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 4 Feb 2022 14:18:25 +0000 Subject: [PATCH 09/11] prettier --- src/api/DesktopAgent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/DesktopAgent.ts b/src/api/DesktopAgent.ts index 6512a9efa..e9099531b 100644 --- a/src/api/DesktopAgent.ts +++ b/src/api/DesktopAgent.ts @@ -151,7 +151,7 @@ export interface DesktopAgent { /** * Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever _User Channel_ the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. - * + * * DesktopAgent implementations should ensure that context messages broadcast to a channel by an application joined to it should not be delivered back to that same application. * * ```javascript From 6b8bf41880c42cd503a53ac241516fb16953ecca Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 21 Feb 2022 21:31:08 +0000 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Hugh Troeger --- docs/api/ref/Errors.md | 2 +- docs/api/spec.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/ref/Errors.md b/docs/api/ref/Errors.md index 5ebbbdc74..53dd365c3 100644 --- a/docs/api/ref/Errors.md +++ b/docs/api/ref/Errors.md @@ -54,7 +54,7 @@ enum ChannelError { Contains constants representing the errors that can be encountered when calling channels using the [`joinUserChannel`](DesktopAgent#joinuserchannel) or [`getOrCreateChannel`](DesktopAgent#getorcreatechannel) methods, or the [`getCurrentContext`](Channel#getcurrentcontext), [`broadcast`](Channel#broadcast) or [`addContextListener`](Channel#addcontextlistener) methods on the `Channel` object. #### See also -* [`DesktopAgent.joinUserChannel`](DesktopAgent#joinusercannel) +* [`DesktopAgent.joinUserChannel`](DesktopAgent#joinuserchannel) * [`DesktopAgent.getOrCreateChannel`](DesktopAgent#getorcreatechannel) * [`Channel.broadcast`](Channel#broadcast) * [`Channel.addContextListener`](Channel#addcontextlistener) diff --git a/docs/api/spec.md b/docs/api/spec.md index e3e0e6098..b85a476e3 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -299,7 +299,7 @@ fdc3.joinUserChannel(redChannel.id); 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 should not be delivered back to that same application if they are joined to the 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. From 7a10fdd474c6ea76fdc75ded6cdf7add0e39d4a2 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 21 Feb 2022 21:45:19 +0000 Subject: [PATCH 11/11] Apply comment from code review to simplify test, thanks @greyseer256 --- test/Methods.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/Methods.test.ts b/test/Methods.test.ts index 3e536b7ed..0df97c90d 100644 --- a/test/Methods.test.ts +++ b/test/Methods.test.ts @@ -45,6 +45,10 @@ expect.extend({ }, }); +beforeEach(() => { + jest.resetAllMocks(); +}); + describe('test ES6 module', () => { describe('without `window.fdc3` global', () => { test('open should reject', async () => { @@ -203,7 +207,7 @@ describe('test ES6 module', () => { test('getSystemChannels should delegate to window.fdc3.getUserChannels', async () => { await getSystemChannels(); - expect(window.fdc3.getUserChannels).toHaveBeenCalledTimes(2); //was already called in previous test, hence this should be the second call to getUserChannels + expect(window.fdc3.getUserChannels).toHaveBeenCalledTimes(1); expect(window.fdc3.getUserChannels).toHaveBeenCalledWith(); }); @@ -221,7 +225,7 @@ describe('test ES6 module', () => { await joinUserChannel(channelId); - expect(window.fdc3.joinUserChannel).toHaveBeenCalledTimes(2); + expect(window.fdc3.joinUserChannel).toHaveBeenCalledTimes(1); expect(window.fdc3.joinUserChannel).toHaveBeenCalledWith(channelId); });