Skip to content

Commit

Permalink
Merge pull request #751 from finos/734-retrieve-AppMetadata
Browse files Browse the repository at this point in the history
734 return app identifier and add function to retrieve app metadata
  • Loading branch information
kriswest authored Jun 20, 2022
2 parents 7a2de4e + 3c2c52c commit b11cbff
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 130 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added `categories` field and recommended categories list to AppD application records to enable category based browsing of AppDs ([#673](https://github.com/finos/FDC3/pull/673))
* Added an `interop` field to AppD application records, replacing the `intents` field, to more fully describe an app's use of FDC3 and enable search for apps that 'interoperate' with a selected app ([#697](https://github.com/finos/FDC3/pull/697))
* Added `AppIdentifier` type, which is a new parent of `AppMetadata` and clarifies required fields for API call parameters which now prefer `appId` and `instanceId` over `name` ([#722](https://github.com/finos/FDC3/pull/722))
* Added a `getAppMetdata()` function to the desktop agent that can be used to retrieve the full `AppMetadata` for an `AppIdentifier` and reduced types such as `IntentResolution.source` and `ContextMetadata.source` from `AppMetadata` to `AppIdentifier` to clarify what fields a developer can rely on and that they should manually retrieve the full `AppMetadata` when they need it for display purposes. ([#751](https://github.com/finos/FDC3/pull/751))

### Changed

Expand Down
107 changes: 63 additions & 44 deletions docs/api/ref/DesktopAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ It is expected that the `DesktopAgent` interface is made availabe via the [`wind
```ts
interface DesktopAgent {
// apps
open(app: AppIdentifier, context?: Context): Promise<AppMetadata>;
findInstances(app: AppIdentifier): Promise<Array<AppMetadata>>;
open(app: AppIdentifier, context?: Context): Promise<AppIdentifier>;
findInstances(app: AppIdentifier): Promise<Array<AppIdentifier>>;
getAppMetadata(app: AppIdentifier): Promise<AppMetadata>;

// context
broadcast(context: Context): Promise<void>;
Expand Down Expand Up @@ -46,7 +47,7 @@ interface DesktopAgent {
addContextListener(handler: ContextHandler): Promise<Listener>;
getSystemChannels(): Promise<Array<Channel>>;
joinChannel(channelId: string) : Promise<void>;
open(name: String, context?: Context): Promise<AppMetadata>;
open(name: String, context?: Context): Promise<AppIdentifier>;
raiseIntent(intent: string, context: Context, name: String): Promise<IntentResolution>;
raiseIntentForContext(context: Context, name: String): Promise<IntentResolution>;
}
Expand All @@ -60,7 +61,7 @@ interface DesktopAgent {
addContextListener(contextType: string | null, handler: ContextHandler): Promise<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.
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 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.

Expand All @@ -77,7 +78,7 @@ const contactListener = await fdc3.addContextListener('fdc3.contact', contact =>

// listener that logs metadata for the message a specific type
const contactListener = await fdc3.addContextListener('fdc3.contact', (contact, metadata) => {
console.log(`Received context message\nContext: ${contact}\nOriginating app: ${metadata?.sourceAppMetadata}`);
console.log(`Received context message\nContext: ${contact}\nOriginating app: ${metadata?.source}`);
//do something else with the context
});
```
Expand Down Expand Up @@ -113,7 +114,7 @@ const listener = fdc3.addIntentListener('StartChat', context => {
//Handle a raised intent and log the originating app metadata
const listener = fdc3.addIntentListener('StartChat', (contact, metadata) => {
console.log(`Received intent StartChat\nContext: ${contact}\nOriginating app: ${metadata?.sourceAppMetadata}`);
console.log(`Received intent StartChat\nContext: ${contact}\nOriginating app: ${metadata?.source}`);
return;
});
Expand Down Expand Up @@ -186,14 +187,14 @@ fdc3.broadcast(instrument);
### `findInstances`
```ts
findInstances(app: AppIdentifier): Promise<Array<AppMetadata>>;
findInstances(app: AppIdentifier): Promise<Array<AppIdentifier>>;
```
Find all the available instances for a particular application.
If there are no instances of the specified application the returned promise should resolve to an empty array.
If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration.
If the request fails for another reason, the promise will return an `Error` with a string from the `ResolveError` enumeration.
#### Example
Expand Down Expand Up @@ -231,14 +232,14 @@ const appIntent = await fdc3.findIntent("StartChat");
// {
// intent: { name: "StartChat", displayName: "Chat" },
// apps: [
// { name: "Skype" },
// { name: "Symphony" },
// { name: "Slack" }
// { appId: "Skype" },
// { appId: "Symphony" },
// { appId: "Slack" }
// ]
// }
// raise the intent against a particular app
await fdc3.raiseIntent(appIntent.intent.name, context, appIntent.apps[0].name);
await fdc3.raiseIntent(appIntent.intent.name, context, appIntent.apps[0]);
//later, we want to raise 'StartChat' intent again
const appIntent = await fdc3.findIntent("StartChat");
Expand All @@ -247,10 +248,10 @@ const appIntent = await fdc3.findIntent("StartChat");
// {
// intent: { name: "StartChat", displayName: "Chat" },
// apps: [
// { name: "Skype" },
// { name: "Symphony" },
// { name: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" },
// { name: "Slack" }
// { appId: "Skype" },
// { appId: "Symphony" },
// { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" },
// { appId: "Slack" }
// ]
```
Expand All @@ -269,14 +270,14 @@ const appIntent = await fdc3.findIntent("ViewContact", "fdc3.ContactList");
// returns only apps that return the specified result type:
// {
// intent: { name: "ViewContact", displayName: "View Contact Details" },
// apps: { name: "MyCRM", resultType: "fdc3.ContactList"}]
// apps: { appId: "MyCRM", resultType: "fdc3.ContactList"}]
// }
const appIntent = await fdc3.findIntent("QuoteStream", instrument, "channel<fdc3.Quote>");
// returns only apps that return a channel which will receive the specified input and result types:
// {
// intent: { name: "QuoteStream", displayName: "Quotes stream" },
// apps: { name: "MyOMS", resultType: "channel<fdc3.Quote>"}]
// apps: { appId: "MyOMS", resultType: "channel<fdc3.Quote>"}]
// }
```
Expand All @@ -297,7 +298,7 @@ A promise resolving to all the intents, their metadata and metadata about the ap
If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration.
The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel<fdc3,instrument>"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response.
The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel<fdc3,instrument>"`. If intent resolution to an app returning a channel is requested without a specified context type, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response.
#### Example
Expand All @@ -310,20 +311,20 @@ const appIntents = await fdc3.findIntentsByContext(context);
// [
// {
// intent: { name: "StartCall", displayName: "Call" },
// apps: [{ name: "Skype" }]
// apps: [{ appId: "Skype" }]
// },
// {
// intent: { name: "StartChat", displayName: "Chat" },
// apps: [
// { name: "Skype" },
// { name: "Symphony" },
// { name: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" },
// { name: "Slack" }
// { appId: "Skype" },
// { appId: "Symphony" },
// { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" },
// { appId: "Slack" }
// ]
// },
// {
// intent: { name: "ViewContact", displayName: "View Contact" },
// apps: [{ name: "Symphony" }, { name: "MyCRM", resultType: "fdc3.ContactList"}]
// apps: [{ appId: "Symphony" }, { appId: "MyCRM", resultType: "fdc3.ContactList"}]
// }
// ];
```
Expand All @@ -335,7 +336,7 @@ const appIntentsForType = await fdc3.findIntentsByContext(context, "fdc3.Contact
// returns for example:
// [{
// intent: { name: "ViewContact", displayName: "View Contact" },
// apps: [{ name: "Symphony" }, { name: "MyCRM", resultType: "fdc3.ContactList"}]
// apps: [{ appId: "Symphony" }, { appId: "MyCRM", resultType: "fdc3.ContactList"}]
// }];
// select a particular intent to raise
Expand All @@ -353,6 +354,26 @@ await fdc3.raiseIntent(startChat.intent.name, context, selectedApp);
* [`findIntent()`](#findintent)
* [`ResolveError`](Errors#resolveerror)
### `getAppMetadata`
```ts
getAppMetadata(app: AppIdentifier): Promise<AppMetadata>;
```
Retrieves the [`AppMetadata`](Metadata#appmetadata) for an [`AppIdentifier`](Types#appidentifier), which provides additional metadata (such as icons, a title and description) from the App Directory record for the application, that may be used for display purposes.
#### Examples
```js
let appIdentifier = { appId: "MyAppId@my.appd.com" }
let appMetadata = await fdc3.getAppMetadata(appIdentifier);
```
#### See also
* [`AppMetadata`](Metadata#appmetadata)
* [`AppIdentifier`](Types#appidentifier)
### `getCurrentChannel`
```ts
Expand Down Expand Up @@ -401,7 +422,6 @@ The `ImplementationMetadata` object returned also includes the metadata for the
```js
let implementationMetadata = await fdc3.getInfo();
let {appId, instanceId} = implementationMetadata.appMetadata;
```
#### See also
Expand All @@ -415,8 +435,9 @@ let {appId, instanceId} = implementationMetadata.appMetadata;
getOrCreateChannel(channelId: string): Promise<Channel>;
```
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`](Errors#channelerror) enumeration if the channel could not be created or access was denied.
Returns a `Channel` object for the specified channel, creating it (as an _App_ channel) if it does not exist.
If the Channel cannot be created or access was denied, the returned promise MUST be rejected with an error string from the `ChannelError` enumeration.
#### Example
Expand Down Expand Up @@ -566,33 +587,30 @@ redChannel.addContextListener(null, channelListener);
### `open`
```ts
open(app: AppIdentifier, context?: Context): Promise<AppMetadata>;
open(app: AppIdentifier, context?: Context): Promise<AppIdentifier>;
```
Launches an app with target information, which can be either be a string like a name, or an [`AppMetadata`](Metadata#appmetadata) object.
Launches an app, specified via an [`AppIdentifier`](Metadata#appidentifier) object.
The `open` method differs in use from [`raiseIntent`](#raiseintent). Generally, it should be used when the target application is known but there is no specific intent. For example, if an application is querying the App Directory, `open` would be used to open an app returned in the search results.
The `open` method differs in use from [`raiseIntent`](#raiseintent). Generally, it should be used when the target application is known but there is no specific intent. For example, if an application is querying an App Directory, `open` would be used to open an app returned in the search results.
**Note**, if the intent, context and target app name are all known, it is recommended to instead use [`raiseIntent`](#raiseintent) with the `target` argument.
If a [`Context`](Types#context) object is passed in, this object will be provided to the opened application via a contextListener. The Context argument is functionally equivalent to opening the target app with no context and broadcasting the context directly to it.
Returns an [`AppMetadata`](Metadata#appmetadata) object with the `instanceId` field set identifying the instance of the application opened by this call.
Returns an [`AppIdentifier`](Metadata#appidentifier) object with the `instanceId` field set to identify the instance of the application opened by this call.
If opening errors, it returns an `Error` with a string from the [`OpenError`](Errors#openerror) enumeration.
#### Example
```js
// Open an app without context, using the app name
let instanceMetadata = await fdc3.open('myApp');
// Open an app without context, using an AppMetadata object to specify the target
let appMetadata = {name: 'myApp', appId: 'myApp-v1.0.1', version: '1.0.1'};
let instanceMetadata = await fdc3.open(appMetadata);
// Open an app without context, using an AppIdentifier object to specify the target
let appIdentifier = { appId: 'myApp-v1.0.1' };
let instanceIdentifier = await fdc3.open(appIdentifier);
// Open an app with context
let instanceMetadata = await fdc3.open(appMetadata, context);
let instanceIdentifier = await fdc3.open(appIdentifier, context);
```
#### See also
Expand All @@ -608,7 +626,7 @@ let instanceMetadata = await fdc3.open(appMetadata, context);
raiseIntent(intent: string, context: Context, app?: AppIdentifier): Promise<IntentResolution>;
```
Raises a specific intent for resolution against apps registered with the desktop agent.
Raises a specific intent for resolution against apps registered with the desktop agent.
The desktop agent MUST resolve the correct app to target based on the provided intent name and context data. If multiple matching apps are found, a method for resolving the intent to a target app, such as presenting the user with a resolver UI allowing them to pick an app, SHOULD be provided.
Alternatively, the specific app or app instance to target can also be provided. A list of valid target applications and instances can be retrieved via [`findIntent`](DesktopAgent#findintent).
Expand Down Expand Up @@ -687,7 +705,7 @@ If a target app for the intent cannot be found with the criteria provided or the
const intentResolution = await fdc3.raiseIntentForContext(context);
// Resolve against all intents registered by a specific target app for the specified context
await fdc3.raiseIntentForContext(context, targetAppMetadata);
await fdc3.raiseIntentForContext(context, targetAppIdentifier);
```
#### See also
Expand All @@ -709,8 +727,8 @@ addContextListener(handler: ContextHandler): Promise<Listener>;
Adds a listener for incoming context broadcasts from the Desktop Agent. Provided for backwards compatibility with versions FDC3 standard <2.0.
#### See also
* [`addContextListener`](#addcontextlistener)
* [`addContextListener`](#addcontextlistener)
### `getSystemChannels` (deprecated)
Expand All @@ -720,6 +738,7 @@ getSystemChannels() : Promise<Array<Channel>>;
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` (deprecated)
Expand All @@ -736,7 +755,7 @@ Alias to the [`joinUserChannel`](#joinuserchannel) function provided for backwar
### `open` (deprecated)
```ts
open(name: String, context?: Context): Promise<AppMetadata>;
open(name: String, context?: Context): Promise<AppIdentifier>;
```
Version of `open` that launches an app by name rather than `AppIdentifier`. Provided for backwards compatibility with versions of the FDC3 Standard <2.0.
Expand Down
13 changes: 6 additions & 7 deletions docs/api/ref/Metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ For each intent, it reference the applications that support that intent.

```ts
interface AppMetadata extends AppIdentifier {
/**
/**
* The 'friendly' app name. This field was used with the `open` and
* `raiseIntent` calls in FDC3 <2.0, which now require an `AppIdentifier`
Expand Down Expand Up @@ -102,10 +101,10 @@ Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passe

```ts
interface ContextMetadata {
/** Metadata identifying the app that sent the context and/or intent.
* @experimental
/** Identifier for the app instance that sent the context and/or intent.
* @experimental
*/
readonly sourceAppMetadata: AppMetadata;
readonly source: AppIdentifier;
}
```

Expand Down Expand Up @@ -308,11 +307,11 @@ The interface used to describe an intent within the platform.
```ts
interface IntentResolution {

/** Metadata about the app instance that was selected (or started) to resolve
/** Identifier for the app instance that was selected (or started) to resolve
* the intent. `source.instanceId` MUST be set, indicating the specific app
* instance that received the intent.
*/
readonly source: AppMetadata;
readonly source: AppIdentifier;

/** The intent that was raised. May be used to determine which intent the user
* chose in response to `fdc3.raiseIntentForContext()`.
Expand Down Expand Up @@ -379,4 +378,4 @@ try {

* [`DesktopAgent.raiseIntent`](DesktopAgent#raiseintent)
* [`DesktopAgent.raiseIntentForContext`](DesktopAgent#raiseintentforcontext)
* [`TargetApp`](Types#targetapp)
* [`AppIdentifier`](Types#appidentifier)
2 changes: 1 addition & 1 deletion docs/api/ref/Types.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ FDC3 API operations make use of several type declarations.

Identifies an application, or instance of an application, and is used to target FDC3 API calls at specific applications.
Will always include at least an `appId` property, which can be used with `fdc3.open`, `fdc3.raiseIntent` etc..
If the `instanceId` field is set then the `AppMetadata` object represents a specific instance of the application that may be addressed using that Id.
If the `instanceId` field is set then the `AppIdentifier` object represents a specific instance of the application that may be addressed using that Id.

```ts
interface AppIdentifier {
Expand Down
Loading

0 comments on commit b11cbff

Please sign in to comment.