Workspace Search
The Search Extension is a framework for searching, fetching, aggregating and actioning data through application interopability.
Getting Started
There are two options for using this package.
Import functions from NPM package and bundle:
import { create, subscribe } from '@openfin/search-api';
Or import the script fron our CDN and use the fin.Search
global namespace.
<script src="https://cdn.openfin.co/search-api/index.js" />
<script>
const create = fin.Search.create;
const subscribe = fin.Search.subscribe;
</script>
API Reference
More in depth API documentation can be found here.
Examples
Searching for Data
import { subscribe } from '@openfin/search-api';
const searchTopic = await subscribe({ topic: 'foo' });
const generator = searchTopic.search({ query: 'bar' });
while (true) {
const { value, done } = await generator.next();
render(results);
if (done) {
break;
}
}
generator.close();
Registering a Search Provider
import { subscribe } from '@openfin/search-api';
const openWindowAction = 'Open Window';
async function getSearchResults({ query }) {
const res = await fetch('/search?q=' + encodeURIComponent(query));
if (!res.ok) {
throw new Error('uh oh something went wrong');
}
const json = await res.json();
return json.map((myResult) => ({
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction],
data: myResult.customMetadata
}));
}
function openWindowForSearchResult(result) {
const dispatchedAction = result.action;
if (dispatchedAction !== openWindowAction) return;
window.open(result.data.url);
}
const searchTopic = await subscribe({ topic: 'foo' });
const provider = {
name: 'bar',
onSearch: getSearchResults,
onResultDispatch: openWindowForSearchResult
};
await searchTopic.register(provider);
Actioning Search Results
import { subscribe } from '@openfin/search-api';
const searchTopic = await subscribe({ topic: 'foo' });
const generator = searchTopic.search({ query: 'bar' });
const { value } = await generator.next();
const firstSearchProviderResponse = value[0];
const firstSearchProviderName = firstSearchProviderResponse.provider.name;
const firstSearchResult = firstSearchProviderResponse.results[0];
const firstSearchAction = firstSearchResult.actions[0];
await searchTopic.dispatch(firstSearchProviderName, firstSearchResult, firstSearchAction);
Control Search Topic Subscriptions
import { create } from "@openfin/search-api";
const searchTopic = await create({ topic: "foo" });
const allowedHosts = ["www.vendor.com"];
searchTopic.onSubscription(identity => {
const info = await fin.View.wrapSync(identity).getInfo();
const url = new URL(info.url);
return allowedHosts.includes(url.host);
});
List Search Providers
import { create } from '@openfin/search-api';
const searchTopic = await create({ topic: 'foo' });
const info = await searchTopic.getAllProviderInfo();
for (let provider of info) {
console.log(`Provider Name: ${provider.name}, Openfin Identity: ${provider.identity}`);
}
Searching Specific Providers
import { create } from '@openfin/search-api';
const searchTopic = await create({ topic: 'foo' });
searchTopic.searchProviders(['Provider Name 1', 'Provider Name 2'], 'bar');
Pushing Search Results
For simple use cases, the Search Extension allows search providers to register an async handler function that returns a set of search results.
Internally the Search Extension uses a pull architecture, allowing the search requester to pull in an initial set of results from all search providers
listening in on a search topic.
async function getSearchResults({ query }) {
const res = await fetch('/search?q=' + encodeURIComponent(query));
if (!res.ok) {
throw new Error('uh oh something went wrong');
}
const json = await res.json();
return json.map((myResult) => ({
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction],
data: myResult.customMetadata
}));
}
For a more complex use case, like a long running query, it might be desired to push new or updated search results to the search requester after a long period of time. For said use case, you can use the search listener response object as highlighted in the example below.
async function getSearchResults(request, response) {
const id = request.id;
const query = request.query;
response.open();
const myLongRunningQuery = makeMyLongRunningQuery(query);
const onNewResults = (myResults) => {
const newResults = myResults.map((myResult) => ({
key: myResult.keyAttribute,
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction],
data: myResult.customMetadata
}));
response.respond(newResults);
};
myLongRunningQuery.onNewResults(onNewResults);
request.onClose(() => {
myLongRunningQuery.close();
});
myLongRunningQuery.onQueryDone(() => {
response.close();
});
}