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

Allow intents to be targeted at specific instances of apps #450

Closed
kriswest opened this issue Sep 6, 2021 · 5 comments · Fixed by #509
Closed

Allow intents to be targeted at specific instances of apps #450

kriswest opened this issue Sep 6, 2021 · 5 comments · Fixed by #509
Labels
api FDC3 API Working Group channels feeds & transactions Channels, Feeds & Transactions Discussion Group enhancement New feature or request intents

Comments

@kriswest
Copy link
Contributor

kriswest commented Sep 6, 2021

Enhancement Request

Use Case:

fdc3.raiseIntent and fdc3.raiseIntentForContext support an optional app? argument that allow you to bypass an intent resolver UI when raising an intent and instead select a specific app type, which is further enabled via the fdc3.findIntent and fdc3.findIntentForContext functions which allow programmatic access to the resolver data.

However, in a typical FDC3-enabled desktop there may be one or more instances of an application already open, which the user will often wish to deliver their intent and context to. This might be to any open instance or it might be to a specific instance of the application that has already interacted with the request in some way. There is, at present, no programmatic way to achieve this (although some desktop agents have implemented this behaviour via their resolver UIs) and no way to retrieve details of open application instances through the FDC3 APIs.

For example:

A user viewing details of a trade may wish to raise an intent to ViewOrder and target an open instance of a particular order management application.
A user viewing details of an order in an OMS may wish to open the customer's details in a CRM application (e.g. by raising the intent ViewContact). The CRM application receiving the intent may wish to use details of the application and instance that raised the intent to allow the user to ViewOrders in the instance of the OMS that contacted it.
A user may wish to plot a pricing chart by raising a ViewChart intent, then plot comparisons with other stocks by repeatedly raising ViewChart (or another suitable intent, e.g. ViewComparison) and targeting the same app instance as resolved the initial intent.

Additional information

There are a number of approaches that could be used to support AppInstances, however they will have to be made carefully in order to preserve backwards compatibility. Consideration should also be given to whether support for targeting specific instances of apps is required for FDC3 spec compliance or not.

@kriswest kriswest added enhancement New feature or request api FDC3 API Working Group intents channels feeds & transactions Channels, Feeds & Transactions Discussion Group labels Sep 6, 2021
@kriswest
Copy link
Contributor Author

kriswest commented Sep 6, 2021

Proposal A

Define an AppInstance type, which simply enhances AppMetadata i.e.

interface AppInstance extends AppMetadata {
  instanceId: string;
}

simply extends the AppMetadata object so that it can also carry an instance id. Hence, the signatures of functions like fdc3.findIntent do not change, rather we can simply update the definition of AppIntent to:

interface AppIntent {
  intent: IntentMetadata;
  apps: Array<AppMetadata | AppInstance>;
}

and can use narrowing to determine the type of each response:

let appIntent = await fdc3.findIntent("ViewChart", context);
appIntent.forEach((option) => {
  if("instanceId" in option) {
    //its an instance of an app
  } else {
    //just metadata for an app
  }
});

Desktop agents would be expected to return both AppInstances and AppMetadata for apps that can be started (n.b. this allows for cases where an app can't be started for some reasons, which we have occasionally encountered, e.g. because they are singletons or integrated into the desktop in such a way that new instances can't be started).

Similarly, the signatures of the fdc3.raiseIntent functions do not change, rather we can simply update the definition of TargetApp to:

type TargetApp = string | AppMetadata | AppInstance;

which handles both the ability to specify an AppInstance as a target and the IntentResolution to return details of the instance (as it also leverages TargetApp).

@kriswest
Copy link
Contributor Author

kriswest commented Sep 6, 2021

Proposal B

Create a new AppInstance type and extend the AppMetadata type to allow an array of AppInstance objects to be carried by it. I.e.:

interface AppInstance {
  instanceId: string;
  //may be extended with other fields specific to Desktop Agent implementations...
}

interface AppMetadata {
  name: string;
  appId?: string;
  version?: string;
  title?: string;
  tooltip?: string;
  description?: string;
  icons?: Array<string>;
  images?: Array<string>;
  instances?: Array<AppInstance>;
}

Again the signature of fdc3.findIntent does not change, neither does AppIntent as the AppInstance objects are nested under the existing return type of AppMetadata.

However, this proposal becomes inelegant as soon as we start working with the TargetApp type:
e.g. to target an instance with fdc3.raiseIntent we must:

  • require that the AppMetadata.instances array contains only a single value (and ignore any additional values) OR
  • allow targeting of multiple instances (unintended) OR
  • use a union type (as we did in proposal a):
    type TargetApp = string | AppMetadata | AppInstance;
    • however, we lose the AppMetadata info in TargetApp this time.
      • For fdc3.raiseIntent this may not be a problem (other than when debugging) as the DesktopAgent should be able to figure out what the type of the instance is (although this may be lost if it has closed).
      • But for the use as the argument to fdc3.open it will not have the necessary metadata
      • and in the return type IntentResolution the app receiving the resolution won't know the application type (as we lost AppMetadata again).
      • Hence we would need to update the IntentResolution definition to not rely on TargetApp:
        interface IntentResolution {
          source: AppMetadata;
          instanceId?: string
          data?: object;
          version: string;
        }
    • Note, we also had to nest the instanceId field inside an object so that it had a field name, to enable us to differentiate it from a string (used to allow TargetApp to be a name for backwards compatibility).

@kriswest
Copy link
Contributor Author

kriswest commented Sep 6, 2021

Supplementary proposal

If either proposal A or B are chosen, we may also wish to:

  1. Provide support for fdc3.open to return instance details, by updating its return type:
open(app: TargetApp, context?: Context): Promise<AppInstance>;
  1. Allow discovery of open instances of an application with a new desktop agent function:
findInstances(app: TargetApp): Promise<Array<AppInstance>>;

@bertrand-s
Copy link
Contributor

Hi @kriswest
Following yesterday's discussion, here is a way to have instanceId optional in AppMetaData but mandatory in AppInstance (TS allows to override a field in a subclass)

interface AppMetadata {
    name: string;
    appId?: string;
    /**
     * Unique id cross-agent / cross-workstations
     * e.g. UUID or object containing a unique identifier - implementation specific to each desktop agent
     */
    instanceId?: any;
    version?: string;
    title?: string;
    tooltip?: string;
    description?: string;
    icons?: Array<string>;
    images?: Array<string>;
    instances?: Array<AppInstance>;
}

interface AppInstance extends AppMetadata {
    instanceId: any;
    //may be extended with other fields specific to Desktop Agent implementations...
}

So you can use AppInstance when instanceId is mandatory and AppMetadata when it is optional...

Note: I also put instanceId as any - as per yesterday discussions - but Desktop Agents using an object will have to ensure to always send back the same object reference when a given instanceId is 'reused', which will lead to extra implementation complexity (this problem doesn't exist with strings)

@kriswest
Copy link
Contributor Author

kriswest commented Nov 17, 2021

Thanks @bertrand-s - I think some of the objections were to the introduction of the AppInstance type at all, as it leads to the need for union types in other function signatures and types, e.g.:

interface AppIntent {
  intent: IntentMetadata;
  apps: Array<AppMetadata | AppInstance>;
} 
type TargetApp = string | AppMetadata | AppInstance;

vs.

interface AppIntent {
  intent: IntentMetadata;
  apps: Array<AppMetadata>;
} 
type TargetApp = string | AppMetadata;

Does AppMetadata need the instance field at all when its not representing an instance? Alternatively, do we need AppInstance at all if AppMetadata has the optional field?
Personally, that doesn't worry me - on reflection it's a fairly minor detail so I'm happy to go either way.

I'm actually more concerned with whether we should standardize any metadata about the instance. The idea of making the instance data any I think arose more out of wanting to encourage developers to use AppMetadata objects returned by other functions, rather than any real concern about whether the data would vary significantly. I'll make some additions to the docs and spec in that regard to deal with that concern when a PR for this issue is raised.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api FDC3 API Working Group channels feeds & transactions Channels, Feeds & Transactions Discussion Group enhancement New feature or request intents
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants