Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

498 Allow intents to be resolved on output type (where they return data) #499

Closed
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
167a7d4
Merge branch '432-return-data-from-an-intent' into 498-resolve-intent…
kriswest Nov 12, 2021
85619ec
Add suport for metadata on output types for intent to appD and the fi…
kriswest Nov 12, 2021
0adfd83
changelog
kriswest Nov 12, 2021
bd97624
WIP
kriswest Nov 18, 2021
ea69042
WIP
kriswest Nov 18, 2021
22cd3be
Merge branch '432-return-data-from-an-intent' into 498-resolve-intent…
kriswest Nov 18, 2021
6d68022
Changing IntentResolution.getData() to IntentResolution.getResult()
kriswest Nov 18, 2021
bb1e120
Changing IntentResolution.getData() to IntentResolution.getResult()
kriswest Nov 18, 2021
e3a962e
WIP
kriswest Nov 18, 2021
240b424
WIP
kriswest Nov 19, 2021
9b0b3b4
completed draft of feeds
kriswest Nov 19, 2021
075067a
changelog
kriswest Nov 19, 2021
ea3e2eb
outputContext -> resultContext and other comments from review
kriswest Nov 22, 2021
157a46f
Mergeing updates from review of upstream PR
kriswest Nov 22, 2021
4c274a4
Apply suggestions from code review
kriswest Dec 13, 2021
461bf95
Merge branch 'master' into 498-resolve-intents-on-output-type
kriswest Jan 25, 2022
3fa81cb
Merge branch '498-resolve-intents-on-output-type' into 433-private-ch…
kriswest Jan 25, 2022
dbd3e81
Merge branch 'master' into 433-private-channels-returned-by-intents
kriswest Feb 4, 2022
ef1d315
Merge branch 'master' into 433-private-channels-returned-by-intents
kriswest Feb 21, 2022
6412fba
Removing defunct paragraph from docs/api/spec.md (bad merge)
kriswest Feb 21, 2022
1da923a
prettier
kriswest Feb 21, 2022
b88b4af
Update docs/api/ref/DesktopAgent.md
kriswest Feb 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added the ability to return data from an intent, via the addition of an IntentHandler type and a `getResult()` to IntentResolution, both of which return a Promise of a Context object. ([#495](https://github.com/finos/FDC3/pull/495))
* Added a field to specify the Context type that intent can return to the AppD Application schema and extended the findIntent API calls to be able to use it for resolution. ([#499](https://github.com/finos/FDC3/pull/499))
* Added the ability to return a Channel from an intent (via the `IntentResult` type), resolver support for intents that return Channels and the concept of PrivateChannels. ([#508](https://github.com/finos/FDC3/pull/508))
* Added a References and Bibliography section to the Standard's documentation to hold links to 'normative references' and other documentation that is useful for understanding the standard ([#530](https://github.com/finos/FDC3/pull/530))
* `IntentResolution` now requires the name of the intent raised to included, allowing it to be used to determine the intent raised via `fdc3.raiseIntentForContext()`. ([#507](https://github.com/finos/FDC3/pull/507))
* A Trademarks page was added to acknowledge trademarks used within the Standard not owned by FINOS or the Linux Foundation ([#534](https://github.com/finos/FDC3/pull/534))
* Added details of FDC3's existing versioning and deprecation policies to the FDC3 compliance page ([#539](https://github.com/finos/FDC3/pull/539))

### Changed
* Consolidated `Listener` documentation with other types ([#404](https://github.com/finos/FDC3/pull/404))
* Updated definition of the `Position` context type to support negative (short) positions ([#419](https://github.com/finos/FDC3/pull/419))
Expand Down
4 changes: 2 additions & 2 deletions docs/api/ref/DesktopAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface DesktopAgent {
findIntentsByContext(context: Context, resultType?: string): Promise<Array<AppIntent>>;
raiseIntent(intent: string, context: Context, app?: TargetApp): Promise<IntentResolution>;
raiseIntentForContext(context: Context, app?: TargetApp): Promise<IntentResolution>;
addIntentListener(intent: string, handler: IntentHandler): Listener;
addIntentListener(intent: string, handler: IntentHandler): Promise<Listener>;

// channels
getOrCreateChannel(channelId: string): Promise<Channel>;
Expand Down Expand Up @@ -81,7 +81,7 @@ const contactListener = await fdc3.addContextListener('fdc3.contact', contact =>
### `addIntentListener`

```ts
addIntentListener(intent: string, handler: IntentHandler): Listener;
addIntentListener(intent: string, handler: IntentHandler): Promise<Listener>;
```
Adds a listener for incoming Intents from the Desktop Agent. The handler function may return void or a promise that resolves to a [`IntentResult`](Types#intentresult), which is either a [`Context`](Types#context) object, representing any data that should be returned, or a [`Channel`](Channel) or [`PrivateChannel`](PrivateChannel) over which data responses will be sent. The `IntentResult` will be returned to app that raised the intent via the [`IntentResolution`](Metadata#intentresolution) and retrieved from it using the `getResult()` function.

Expand Down
6 changes: 6 additions & 0 deletions docs/api/ref/Metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,16 @@ The Interface used to describe an Intent within the platform.

```ts
interface IntentResolution {

/**
* The application that resolved the intent.
*/
readonly source: TargetApp;
/**
* The intent that was raised. May be used to determine which intent the user
* chose in response to `fdc3.raiseIntentForContext()`.
*/
readonly intent: string;
/**
* The version number of the Intents schema being used.
*/
Expand Down
65 changes: 19 additions & 46 deletions docs/api/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ If the raising of the intent resolves (or rejects), a standard [`IntentResolutio

```ts
interface IntentResolution {
/**
/**
* The application that resolved the intent.
*/
readonly source: TargetApp;
/**
* The intent that was raised. May be used to determine which intent the user
* chose in response to `fdc3.raiseIntentForContext()`.
*/
readonly intent: string;
/**
* The version number of the Intents schema being used.
*/
Expand Down Expand Up @@ -284,6 +289,7 @@ if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), '1.2')) {

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.


There are three types of channels, which have different visibility and discoverability semantics:

1. **System channels**, which:
Expand All @@ -301,11 +307,16 @@ There are three types of channels, which have different visibility and discovera
* 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 support private communication between two parties, have an auto-generated identity and can only be retrieved via a raised intent.

3. 'private' channels, which support 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 System channels, these functions are provided on the Desktop Agent, e.g. [`fdc3.broadcast(context)`](ref/DesktopAgent#broadcast), and apply to channels joined via [`fdc3.joinChannel`](ref/DesktopAgent#joinchannel). For App channels, a channel object must be retrieved, via [`fdc3.getOrCreateChannel(channelName)`](ref/DesktopAgent#getorcreatechannel), which provides the functions, e.g. [`myChannel.broadcast(context)`](ref/Channel#broadcast).

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 System Channels
Apps can join _System 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`](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 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 via the methods on the [`Channel`](ref/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.
Expand Down Expand Up @@ -407,50 +418,7 @@ 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.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`.

To facilitate context linking in such situations it is recommended that applications [`broadcast`](ref/DesktopAgent#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.

### Examples
To find a system channel, one calls

```js
// returns an array of channels
const allChannels = await fdc3.getSystemChannels();
const redChannel = allChannels.find(c => c.id === 'red');
```
### Joining channels

To join a system channel. one calls

```js
fdc3.joinChannel(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.

### 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

```js
const appChannel = await fdc3.getOrCreateChannel('my_custom_channel');
// get the current context of the channel
const current = await appChannel.getCurrentContext();
// add a listener
appChannel.addContextListener(null, context => {...});
// broadcast to the channel
appChannel.broadcast(context);

```
if another application broadcasts to "my_custom_channel" (by retrieving it and broadcasting to it via `myChannel.broadcast()`) then the broadcast will be received by the specific listener (`myChannelListener`) but NOT by the listener for joined channels (`listener`).

### Private Channels

Expand All @@ -463,6 +431,11 @@ It is intended that Desktop Agent implementations:

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`](ref/DesktopAgent#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.

## APIs
The APIs are defined in TypeScript in [src], with documentation generated in the [docs] folder.

Expand Down
2 changes: 1 addition & 1 deletion src/api/DesktopAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ export interface DesktopAgent {
* });
* ```
*/
addIntentListener(intent: string, handler: IntentHandler): Listener;
addIntentListener(intent: string, handler: IntentHandler): Promise<Listener>;

/**
* Adds a listener for incoming context broadcast from the Desktop Agent.
Expand Down
5 changes: 5 additions & 0 deletions src/api/IntentResolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export interface IntentResolution {
* The application that resolved the intent.
*/
readonly source: TargetApp;
/**
* The intent that was raised. May be used to determine which intent the user
* chose in response to `fdc3.raiseIntentForContext()`.
*/
readonly intent: string;
/**
* The version number of the Intents schema being used.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/api/Methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ export function raiseIntentForContext(context: Context, app?: TargetApp): Promis
return rejectIfNoGlobal(() => window.fdc3.raiseIntentForContext(context, app));
}

export function addIntentListener(intent: string, handler: IntentHandler): Listener {
return throwIfNoGlobal(() => window.fdc3.addIntentListener(intent, handler));
export function addIntentListener(intent: string, handler: IntentHandler): Promise<Listener> {
return rejectIfNoGlobal(() => window.fdc3.addIntentListener(intent, handler));
}

export function addContextListener(
Expand Down
2 changes: 1 addition & 1 deletion src/app-directory/specification/appd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ components:
items:
type: string
description: >-
A comma separated list of the types of contexts the intent offered by the application can process.
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"
resultType:
type: string
Expand Down
4 changes: 2 additions & 2 deletions website/static/schemas/next/app-directory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,9 @@ components:
items:
type: string
description: >-
A comma separated list of the types of contexts the intent offered by the application can process.
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"
outputContext:
resultContext:
type: string
description: >-
The type of context return by the application when resolving this intent. E.g. "fdc3.instrument"
Expand Down