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

Support raise Intent without a context #375

Merged
merged 5 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 7 additions & 3 deletions docs/api/ref/DesktopAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ raiseIntent(intent: string, context: Context, app?: TargetApp): Promise<IntentRe
```
Raises a specific intent against a target app.

The desktop agent will resolve the correct app to target based on the provided intent name and context data.
The desktop agent will resolve the correct app to target based on the provided intent name and context data type. If you wish to raise an Intent without a context, use the `fdc3.nothing` context type. This type exists so that apps can explicitly declare support for raising an intent without context.

If multiple matching apps are found, the user may be presented with an app picker.
Alternatively, the specific app to target can also be provided (if known).
Expand All @@ -398,6 +398,9 @@ await fdc3.raiseIntent("StartChat", context, appIntent.apps[0].name);

// or use the metadata of the app to fully describe the target app for the intent
await fdc3.raiseIntent("StartChat", context, appIntent.apps[0]);

//Raise an intent without a context by using the null context type
await fdc3.raiseIntent("StartChat", {type: "fdc3.nothing"});
```
#### See also
* [`Context`](Types#context)
Expand All @@ -415,8 +418,9 @@ Finds and raises an intent against a target app based purely on context data.

The desktop agent will resolve the correct app to target based on the provided context.

This is similar to calling `findIntentsByContext`, and then raising an intent against one of the returned apps, except in this case
the desktop agent has the opportunity to provide the user with a richer selection interface where they can choose the intent and target app.
This is similar to calling `findIntentsByContext`, and then raising an intent against one of
the returned apps, except in this case the desktop agent has the opportunity to provide the
user with a richer selection interface where they can choose the intent and target app.

Returns an `IntentResolution` object with a handle to the app that responded to the selected intent.

Expand Down
10 changes: 6 additions & 4 deletions docs/api/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ When raising an Intent a specific context may be provided. The type of the provi

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. In addition to raising a specific intent, you can raise an Intent for a specific Context allowing the Desktop Agent or the user (if the Intent is ambiguous) to select the appropriate Intent for the selected Context and then to raise that Intent for resolution.

To raise an Intent without a context, use the `fdc3.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).

#### Intent Resolution
Raising an Intent will return a Promise-type object that will resolve/reject based on a number of factors.

Expand Down Expand Up @@ -143,14 +145,14 @@ For example, to raise a specific Intent:

```js
try {
const result = await fdc3.raiseIntent('StageOrder');
const result = await fdc3.raiseIntent('StageOrder', context);
}
catch (er){
console.log(er.message);
}
```

or to raise an Intent for a specific context:
or to raise an unspecified Intent for a specific context, where the user will select an intent from a resolver dialog:
```js
try {
const result = await fdc3.raiseIntentForContext(context);
Expand Down Expand Up @@ -182,7 +184,7 @@ Intents represent a contract with expected behavior if an app asserts that it su

It is expected that App Directories will also curate listed apps and ensure that they are complying with declared intents.

Like FDC3 Context Data, the Intent schemas need to be versioned. Desktop Agents will be responsible to declare which version of the Intent schema they are using. Applications may also assert a specific version requirement when raising an Intent. Version negotation may be supported by a given Desktop Agent.
Like FDC3 Context Data, the Intent schemas need to be versioned. Desktop Agents will be responsible to declare which version of the Intent schema they are using. Applications may also assert a specific version requirement when raising an Intent. Version negotation may be supported by a given Desktop Agent.

### Send/broadcast Context
On the financial desktop, applications often want to broadcast context to any number of applications. Context sharing needs to support concepts of different groupings of applications as well as data privacy concerns. Each Desktop Agent will have its own rules for supporting these features. However, a Desktop Agent should ensure that context messages broadcast to a channel by an application joined to it should not be delivered back to that same application.
Expand All @@ -201,7 +203,7 @@ if (fdc3.getInfo && versionIsAtLeast(fdc3.getInfo(), '1.2')) {
```

## Resolvers
Intents functionality is dependent on resolver functionality to map the intent to a specific App. This will often require end-user input. Resolution can either be performed by the Desktop Agent (raising UI to pick the desired App for the intent) or by the app launching the intent - in which case the calling App will handle the resolution itself (using the findIntents API below) and then invoke an explicit Intent object.
Intents functionality is dependent on resolver functionality to map the intent to a specific App. This will often require end-user input. Resolution can either be performed by the Desktop Agent (raising UI to pick the desired App for the Intent, or both an Intent and App for a context) or by the app launching the intent - in which case the calling App will handle the resolution itself (using the findIntents API below) and then invoke an explicit Intent object.

## Context Channels

Expand Down
39 changes: 39 additions & 0 deletions docs/context/ref/Nothing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
id: Nothing
sidebar_label: Nothing
title: Nothing
hide_title: true
---
# `Nothing`

A type that explicitly represents a lack of context.

Notes:

- Intended to be used in situations where no context is desired.
- For example:
- Raising an Intent without context (e.g. opening a blank order form, or chat
interface without a contact selected).
- Resetting context on a channel (e.g. when context is used to set a filter in
other applications a null context might release the filter).
- An explicit representation of a Null or empty context allows apps to declare support for
a lack of context, for example in their Intent metadata in an app directory.

## Type

`fdc3.nothing`

## Schema

https://fdc3.finos.org/schemas/next/nothing.schema.json

## Example

```js
const nullContext = {
type: 'fdc3.nothing'
}

fdc3.joinChannel('groupA')
fdc3.broadcast(nullContext)
```
10 changes: 10 additions & 0 deletions docs/context/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ The following are standard FDC3 context types.
- __fdc3.position__
- [Financial Objects Specification](https://fo.finos.org/docs/objects/position)
- [schema](/schemas/next/position.schema.json)
- __fdc3.nothing
- Explicit representation of a lack of context
- [schema](/schemas/next/nothing.schema.json)

__Note:__ The below examples show how the base context data interface can be used to define specific context data objects. It is not the purpose of the specification at this stage to define standard representations for objects. It establishes the framework in which such definitions could be created.

Expand Down Expand Up @@ -265,4 +268,11 @@ __Note:__ The below examples show how the base context data interface can be use
}
```

#### Nothing
```json
{
"type": "fdc3.nothing",
}
```


18 changes: 18 additions & 0 deletions docs/intents/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,21 @@ const intentsAndApps = await fdc3.findIntentsByContext({
}
});
```

## Using Intents without a context
As the [Desktop Agent API](api/ref/DesktopAgent) and [App Directory](app-directory/overview) both
require a context to specified whereever Intents are used, using an Intent without a context is
achieved through the use of an explcit `null` context type `fdc3.nothing`. By using an explicit type
to represent a lack of context we allow applicaitons to declare their support for a lack of
context.

```javascript
const intentsAndApps = await fdc3.findIntentsByContext({
type: "fdc3.nothing",
});

const result = await fdc3.raiseIntent("StartChat", {
type: "fdc3.nothing"
});
```

2 changes: 2 additions & 0 deletions src/api/DesktopAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export interface DesktopAgent {
* await fdc3.raiseIntent("StartChat", context, appIntent.apps[0].name);
* //or use one of the AppMetadata objects returned in the AppIntent object's 'apps' array
* await fdc3.raiseIntent("StartChat", context, appMetadata);
* //Raise an intent without a context by using the null context type
* await fdc3.raiseIntent("StartChat", {type: "fdc3.nothing"});
* ```
*/
raiseIntent(intent: string, context: Context, app?: TargetApp): Promise<IntentResolution>;
Expand Down
1 change: 1 addition & 0 deletions src/context/ContextType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum ContextTypes {
Organization = 'fdc3.organization',
Portfolio = 'fdc3.portfolio',
Position = 'fdc3.position',
Nothing = 'fdc3.nothing',
}

export type ContextType = ContextTypes | string;
16 changes: 15 additions & 1 deletion src/context/ContextTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// To parse this data:
//
// import { Convert, Context, Contact, ContactList, Instrument, InstrumentList, Country, Organization, Portfolio, Position } from "./file";
// import { Convert, Context, Contact, ContactList, Instrument, InstrumentList, Country, Organization, Portfolio, Position, Nothing } from "./file";
//
// const context = Convert.toContext(json);
// const contact = Convert.toContact(json);
Expand All @@ -11,6 +11,7 @@
// const organization = Convert.toOrganization(json);
// const portfolio = Convert.toPortfolio(json);
// const position = Convert.toPosition(json);
// const nothing = Convert.toNothing(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
Expand Down Expand Up @@ -102,6 +103,10 @@ export interface Position {
name?: string;
}

export interface Nothing {
type: string;
}

// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
Expand Down Expand Up @@ -176,6 +181,14 @@ export class Convert {
public static positionToJson(value: Position): string {
return JSON.stringify(uncast(value, r('Position')), null, 2);
}

public static toNothing(json: string): Nothing {
return cast(JSON.parse(json), r('Nothing'));
}

public static nothingToJson(value: Nothing): string {
return JSON.stringify(uncast(value, r('Nothing')), null, 2);
}
}

function invalidValue(typ: any, val: any, key: any = ''): never {
Expand Down Expand Up @@ -427,4 +440,5 @@ const typeMap: any = {
],
'any'
),
Nothing: o([{ json: 'type', js: 'type', typ: '' }], 'any'),
};
3 changes: 2 additions & 1 deletion src/context/schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"Country": ["https://fdc3.finos.org/schemas/next/country.schema.json"],
"Organization": ["https://fdc3.finos.org/schemas/next/organization.schema.json"],
"Portfolio": ["https://fdc3.finos.org/schemas/next/portfolio.schema.json"],
"Position": ["https://fdc3.finos.org/schemas/next/position.schema.json"]
"Position": ["https://fdc3.finos.org/schemas/next/position.schema.json"],
"Nothing": ["https://fdc3.finos.org/schemas/next/nothing.schema.json"]
}
10 changes: 10 additions & 0 deletions src/context/schemas/nothing.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://fdc3.finos.org/schemas/next/nothing.schema.json",
"type": "object",
"title": "Nothing",
"allOf": [{ "$ref": "context.schema.json#" }],
"properties": {
"type": { "const": "fdc3.nothing" }
}
}
3 changes: 2 additions & 1 deletion website/sidebars.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"context/ref/Organization",
"context/ref/Country",
"context/ref/Position",
"context/ref/Portfolio"
"context/ref/Portfolio",
"context/ref/Nothing"
]
}
],
Expand Down
10 changes: 10 additions & 0 deletions website/static/schemas/next/nothing.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://fdc3.finos.org/schemas/next/nothing.schema.json",
"type": "object",
"title": "Nothing",
"allOf": [{ "$ref": "context.schema.json#" }],
"properties": {
"type": { "const": "fdc3.nothing" }
}
}