@openfin/search-api
Version:
A search API framework for OpenFin.
583 lines (582 loc) • 18.9 kB
TypeScript
import type OpenFin from '@openfin/core';
import { RegistrationMetaInfo } from '@client/index';
export type { RegistrationMetaInfo };
/**
* Create a topic.
* If the OpenFin identity creating the topic is running in a platform, the search topic will be sandboxed to the platform.
* In order to subscribe to a sandboxed search topic, the UUID of the platform must be specified explicitly or the subscribing OpenFin identity must be running in the platform.
* @param req the topic create request.
*/
export declare const create: () => Promise<SearchTopic>;
/**
* Subscribe to an existing search topic.
* @param req the subscribe request.
*/
export declare const subscribe: () => Promise<SearchTopicClient>;
/**
* Search API object that is injected in the window.
*/
export type SearchAPI = {
create: typeof create;
subscribe: typeof subscribe;
};
/**
* A response to a search from a search provider.
*/
export interface SearchProviderResponse {
/**
* The search provider that responded with the search results.
*/
provider: SearchProviderInfo;
/**
* If the search result succeeds for this provider, results of the search will be set.
*/
results?: SearchResult[];
/**
* A context with custom data to pass through search
*/
context?: any;
/**
* If the search failed for this provider, error will be set.
*/
error?: Error;
}
/**
* The search request.
*/
export interface SearchRequest {
/**
* The search query.
*/
query: string;
/**
* Additional custom context that can be used for searching.
*/
context?: any;
/**
* A list of search provider names to execute the search request against.
*/
targets?: string[];
}
/**
* A generator that returns search responses from all providers that have currently responded.
*
* More documentation on Javascript Generators can be found [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator).
*/
export type SearchProviderResponseGenerator = AsyncGenerator<SearchProviderResponse[], SearchProviderResponse[], SearchProviderResponse[]>;
/**
* Describes the state of the search response generator.
*/
export declare enum SearchProviderResponseGeneratorState {
/**
* The generator is in the process of fetching the initial set of results from search providers.
*/
Fetching = "fetching",
/**
* The generator has fetched all initial results, and is now waiting for search providers with
* open {@link SearchListenerResponse} streams to push new or updated search results.
*/
Fetched = "fetched",
/**
* All open {@link SearchListenerResponse} streams have closed, completing the request.
* In this state, the set of responses returned by `generator.next()` are final.
*/
Complete = "complete"
}
/**
* Extended search provider response generator with additional properties about the search request.
*/
export interface SearchProviderResponseGeneratorExtended extends SearchProviderResponseGenerator {
/**
* The id of the search request.
*/
id: string;
/**
* The state of the search provider response generator.
*/
state: SearchProviderResponseGeneratorState;
/**
* Notifies all search providers related to this search request
* that the search requester is no longer listening for new or updated search results.
* @experimental
*/
close: () => void;
}
/**
* Called when a remote OpenFin identity, such as a view, attempts to connect
* to the search topic.
*
* Returning false will reject said request.
*
* ```js
* const allowedHosts = ["www.company.com"];
* searchTopic.onSubscription(identity => {
* const info = await fin.View.wrapSync(identity).getInfo();
* const url = new URL(info.url);
*
* return allowedHosts.includes(url.host);
* });
* ```
*/
export type SubscriptionListener = (identity: OpenFin.Identity) => Promise<boolean>;
/**
* Called when a remote OpenFin identity, such as a view, disconnects from a Search topic.
*/
export type DisconnectListener = (identity: OpenFin.Identity) => Promise<void>;
/**
* Called when search provider deregisters from SearchTopic
*/
export type DeregisterListener = () => void | Promise<void>;
/**
* Called when search provider registers to SearchTopic
*/
export type RegisterListener = () => void | Promise<void>;
/**
* The client returned from subscribing as a secondary node to a search topic, which is managed by a primary node.
* Can be used to interact with a search topic.
*/
export interface SearchTopicClient {
/**
* Obtain information about all search providers listening in on the topic.
*/
getAllProviders(): Promise<SearchProviderInfo[]>;
/**
* Execute a search on the search topic.
*
* The generator returned by this function can be called multiple times, returning the current list of search provider responses.
* As more search providers respond to the search request the returned list of responses will grow in length.
*
* When all the search providers have responded to the search request, the generator will return the final
* set of search response under the `value` attribute and set the 'done' attribute set to true.
*
* If no targets are included in request, will search against all search providers.
* @param request the request object that contains parameters to base the search on.
*
* @experimental
*/
search(request: SearchRequest): Promise<SearchProviderResponseGeneratorExtended>;
/**
* Register a search provider.
* @param provider the search provider to register.
*/
register(provider: SearchProvider): Promise<RegistrationMetaInfo>;
/**
* Deregister a search provider by its name.
* @param name the name of the search provider to deregister
*/
deregister(name: string): Promise<void>;
/**
* Dispatch a search result back to the search provider.
* It is then the search providers duty to perform what ever action was chosen.
* @param providerId the id of the search provider to send the search result back to.
* @param result the search result to send back to the search provider.
* @param action the action for the search provider to perform with the search result.
* @param identity optionally provide the identity of the dispatcher, otherwise the current identity will be used.
*/
dispatch(providerId: string, result: SearchResult, action: Action, identity?: OpenFin.Identity): Promise<any>;
/**
* Disconnect from the search topic.
* NOTE: All search providers registered by this search client will be deregistered.
*/
disconnect(): Promise<void>;
/** The channel client for the search topic. */
channel: OpenFin.ChannelClient;
}
/**
* A search topic created by the primary node.
*/
export interface SearchTopic extends Omit<SearchTopicClient, 'channel'> {
/**
* Add a subscription listener that will be called when ever a search client subscribes
* to this topic.
*
* Returning false in said listener will reject the request.
* @param listener the listener to add.
*/
onSubscription(listener: SubscriptionListener): void;
/**
* Remove a listener.
* @param listener the listener to remove.
*/
removeListener(listener: (...args: any[]) => any): void;
/**
* Add a listener that will be called when ever a search client disconnects from this topic.
* @param listener the listener to add.
*/
onDisconnect(listener: DisconnectListener): void;
/**
* Add a listener that will be called whenever a search provider registers
* @param listener the listener to add
*/
onRegister(listener: RegisterListener): void;
/**
* Add a listener that will be called whenever a search provider deregisters
* @param listener the listener to add.
*/
onDeregister(listener: DeregisterListener): void;
/** The channel provider for the search topic. */
channel: OpenFin.ChannelProvider;
}
/**
* Information about a search provider.
*/
export interface SearchProviderInfo {
/**
* A unique ID used to identify the search provider.
*/
id: string;
/**
* A UI friendly title for the search provider.
*/
title: string;
/**
* The OpenFin identity that registered this search provider.
*/
identity?: OpenFin.Identity;
/**
* The order to sort the score in. The default is `ascending`.
* @experimental
*/
scoreOrder?: ScoreOrder;
/**
* A keycode that can be used to interact with this Search Provider.
*/
commandCode?: string;
/**
* A short description of the Search Provider.
*/
description?: string;
/**
* An icon that a UI can display for the Search Provider.
*/
icon: string;
/**
* A flag to indicate this provider will not be displayed as a command.
*/
hidden?: boolean;
/**
* A title to display above the result list in a UI when targeting this specific Search Provider.
*/
listTitle?: string;
/**
* The placeholder string to be displayed in a UI when targeting this specific Search Provider.
*/
inputPlaceholder?: string;
/**
* Logo to show render when targeting this specific Search Provider.
*/
logoUrl?: string;
/**
* If set, focusing on a search result will trigger onResultDispatch callback.
*/
dispatchFocusEvents?: boolean;
/**
* version of client SDK, set by the API
*/
clientAPIVersion?: string;
}
/**
* The order to sort scored search results in.
*/
export type ScoreOrder = 'ascending' | 'descending';
/**
* The reason which triggered the search result dispatch callback.
*/
export declare enum ActionTrigger {
/**
* The search result dispatch was triggered with a regular user action (click, hotkey, etc.)
*/
UserAction = "user-action",
/**
* The search result was dispatched back because the user has focused on another search result.
*/
FocusChange = "focus-change",
/**
* The search result was dispatched back because there was a load error and the user requested a reload.
*/
Reload = "reload"
}
/**
* Each action is defined by its title and a hotkey
*/
export type Action = {
name: string;
hotkey?: string;
};
export declare enum SearchTagBackground {
Active = "active",
Default = "default"
}
export interface SearchTag {
name: string;
background: SearchTagBackground;
}
/**
* Common properties of a {@link SearchResult | search result}.
*/
export interface SearchResult<A extends Action = Action> {
/**
* A unique ID for the search result.
* Can be used to update a previously returned search result by calling
* `searchRequestContext.respond(result)` with the same search result key.
*/
key: string;
/**
* UI friendly name for the search result.
*/
title: string;
/**
* Unused.
* @experimental
*/
description?: string;
/**
* Unused.
* @experimental
*/
shortDescription?: string;
/**
* An optional icon that can be used when displaying the search result in a UI.
*/
icon?: string;
/**
* Used when sorting a list of search results for a single provider.
* @experimental
*/
score?: number;
/**
* Additional custom metadata about the search result.
* Can be used when actioning the search result.
*/
data?: any;
/**
* Actions that can be performed with this search result.
* Used when dispatching search results back to the respective provider.
*/
actions: A[];
/**
* Tags associated with the search result.
*/
tags?: SearchTag[];
/**
* A label to render with the search result.
*/
label?: string;
}
/**
* Representation of a search request passed as a parameter to a {@link SearchProvider | SearchProvider's} `onUserInput` listener function.
*
* ```js
* const provider = {
* name: "my-provider",
* title: "My Provider",
* onUserInput: (request) => {
* const query = request.query;
* return getMyResults(query);
* }
* };
* ```
*/
export interface SearchListenerRequest extends SearchRequest {
/**
* The ID of the search request.
* Can be used to tie related search requests together between providers.
*/
id: string;
/**
* Registers a listener that is called when the search request is
* closed by the search requester.
*
* Can be used to cleanup pending queries:
* ```js
* async function onUserInput(request) {
* const myQuery = makeQuery(request.query);
*
* request.onClose(() => {
* myQuery.cancel();
* });
*
* const results = await myQuery.getResults();
* return { results };
* }
* ```
*
* @param listener the listener to call when the request is closed.
*/
onClose(listener: () => void): void;
/**
* Remove a registered listener.
*
* ```ts
*
* function myListener(request, listener) {
* // Do something
* }
*
* request.removeListener(myListener);
* ```
* @param listener the listener to remove.
*/
removeListener(listener: () => void): void;
}
/**
* Representation of a search response from a specific invocation of a {@link SearchProvider | SearchProvider's} `onUserInput` listener function.
* Can optionally be used to push search results to the requester.
*
* ```js
* function onUserInput(searchListenerRequest, searchListenerResponse) {
* searchListenerResponse.open();
*
* const myLongRunningQuery = makeMyLongRunningQuery(searchListenerRequest.query);
* myLongRunningQuery.onNewResults(myNewResults => {
* searchListenerResponse.respond(myNewResults);
* });
*
* searchListenerRequest.onClose(() => {
* myLongRunningQuery.close();
* });
* }
* ```
*/
export interface SearchListenerResponse {
/**
* Open the response stream, notifying the search requester that
* there are new or updated search results that have yet to be pushed
* by the current provider.
* @experimental
*
* ```ts
* import type { SearchListenerResponse } from './my-shape-definition';
* function openStream(response:SearchListenerResponse) {
* response.open();
* }
*
* openStream();
* ```
*/
open(): void;
/**
* Close the response stream.
* This notifies the requester that the current search provider is done sending results.
*
* ```ts
* import type { SearchListenerResponse } from './my-shape-definition';
* function closeStream(request:SearchListenerRequest, response:SearchListenerResponse) {
* response.close();
* }
*
* closeStream();
* ```
* @experimental
*/
close(): void;
/**
* Respond to the search request with new or updated search results.
*
* ```ts
*
* response.respond([
* { name: 'result-1' },
* { name: 'result-2' },
* { name: 'result-3' },
* ]);
*
* ```
*
* @param results new or updated search results to respond with.
* @experimental
*/
respond(results: SearchResult[]): void;
/**
* Remove a search result from the list of responded search results.
*
* ```ts
* response.revoke({ name: 'result-1' }, { name: 'result-2' });
* ```
* @param resultKeys the keys of the search results to revoke.
* @experimental
*/
revoke(...resultKeys: string[]): void;
/**
* Respond to the search request with new or updated search results context.
* @param context The new or updated search result context to respond with.
*/
updateContext(context: any): void;
}
/**
* An object resolved from 'onUserInput' function containing results and optional context
*/
export interface SearchResponse {
results: SearchResult[];
context?: any;
}
/**
* A function that listens for search requests on a search topic.
* Returns a set of search results based on arguments provided.
* @param request - The search request coming in
* @param response - EXPERIMENTAL - streaming response
*/
export type UserInputListener = (request: SearchListenerRequest, response: SearchListenerResponse) => Promise<SearchResponse>;
/**
* The triggered action that should be performed by the search provider.
*/
export type DispatchedAction = Action & {
trigger: ActionTrigger;
};
/**
* A search result that has been dispatched back to the {@link SearchProvider | SearchProvider's} `onResultDispatch` listener function.
* Contains the action that should be performed by the search provider.
*
* ```js
* const provider = {
* name: "my-provider",
* title: "My Provider",
* onUserInput: myOnUserInput,
* onResultDispatch: (dispatchedSearchResult) => {
* if (dispatchedSearchResult.action.name === "my-action") {
* doMyAction(dispatchedSearchResult);
* }
* }
* };
* ```
*/
export interface DispatchedSearchResult extends SearchResult {
/**
* The selected action for the search provider to perform.
*/
action: DispatchedAction;
/**
* The OpenFin identity that dispatched this search result.
*/
dispatcherIdentity: OpenFin.Identity;
}
/**
* A listener called when a search result generated by this provider is dispatched.
*
* ```js
* searchTopic.dispatch("My Provider Name", searchResult, "My Action");
* ```
*/
export type ResultDispatchListener = (result: DispatchedSearchResult) => void;
/**
* A search provider listens for search requests on a search topic and returns search results.
* It optionally can also perform custom actions when a search result is dispatched back to the provider.
*/
export interface SearchProvider extends SearchProviderInfo {
/**
* The search listener for the search provider.
*
* When a search is requested on the subscribed search topic, this
* listener will be called and have the opportunity to return search results.
*/
onUserInput: UserInputListener;
/**
* An optional listener for actioning search results.
*
* When this search provider returns search results via its `onUserInput` listener,
* the receiver of the results can select and dispatch a single result back to the provider.
*
* It is then up to the search provider to perform the custom requested action.
*/
onResultDispatch?: ResultDispatchListener;
}