@openfin/search-api
TypeScript icon, indicating that this package has built-in type declarations

1.5.9 • Public • Published

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

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';

// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });

/* Search for data with query `bar`.
   This will return a generator which can be called multiple times
   while there are pending responses from search data providers. */
const generator = searchTopic.search({ query: 'bar' });
while (true) {
    const { value, done } = await generator.next();

    // Implementation specific rendering logic.
    render(results);

    // If done is true, all search providers have responded with their data.
    if (done) {
        break;
    }
}

// When done with search request, call close.
generator.close();

Registering a Search Provider

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';

const openWindowAction = 'Open Window';

// Example search handler that returns results from a backend query.
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 initial search results.

       All results must have the `name` and `description`
       field at the very least for rendering purposes. */
    return json.map((myResult) => ({
        name: myResult.nameAttribute,
        shortDescription: myResult.shortDescriptionAttribute,
        description: myResult.descriptionAttribute,
        actions: [openWindowAction], // Dispatchable actions for this search result.
        data: myResult.customMetadata
    }));
}

// Example function for actioning a result from `getSearchResults`.
function openWindowForSearchResult(result) {
    const dispatchedAction = result.action; // `result.action` is set to the action that was dispatched.
    if (dispatchedAction !== openWindowAction) return;
    window.open(result.data.url);
}

// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });

/* The `name` and `onSearch` attributes are required for a data provider.

   The `onSearch` function will be called back when the topic is searched
   on. (ex. `searchTopic.search("my query")`)

   The `onResultDispatch` function will be called back when a search result
   is dispatched. (ex. `searchTopic.dispatch("Provider Name", searchResult, "Open Window")`) */
const provider = {
    name: 'bar',
    onSearch: getSearchResults,
    onResultDispatch: openWindowForSearchResult
};

// Register the search data provider.
await searchTopic.register(provider);

Actioning Search Results

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';

// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });

// Get search results.
const generator = searchTopic.search({ query: 'bar' });
const { value } = await generator.next();

/* Dispatches the first search result in the first response back to the
   respective provider, such that the provider can action the result. */
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); // Omitting will default to first action in `result.actions`.

Control Search Topic Subscriptions

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from "@openfin/search-api";

const searchTopic = await create({ topic: "foo" });

// Only hosts in the list can subscribe to the search topic.
const allowedHosts = ["www.vendor.com"];
searchTopic.onSubscription(identity => {
    // Get the URL of the subscribing identity.
    const info = await fin.View.wrapSync(identity).getInfo();
    const url = new URL(info.url);

    return allowedHosts.includes(url.host);
});

List Search Providers

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from '@openfin/search-api';

// Subscribe or create a search topic.
const searchTopic = await create({ topic: 'foo' });

// Returns a list of provider info objects.
const info = await searchTopic.getAllProviderInfo();

for (let provider of info) {
    console.log(`Provider Name: ${provider.name}, Openfin Identity: ${provider.identity}`);
}

Searching Specific Providers

// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from '@openfin/search-api';

// Subscribe or create a search topic.
const searchTopic = await create({ topic: 'foo' });

// Only searches against providers in the provider name list.
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.

// A simple search handler that returns an initial set of search results.
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();

    // These results will be pulled in by the search requester.
    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.

/* An advanced search handler that pushes new or updated search results
   as long as the search request has not been closed. */
async function getSearchResults(request, response) {
    /* ID of the search request.
       Can be used to tie related search providers together. */
    const id = request.id;

    // The search query.
    const query = request.query;

    /* ▼ PUSH ARCHITECTURE ▼ */

    /* 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. */
    response.open();

    const myLongRunningQuery = makeMyLongRunningQuery(query);

    // On new or updated search results push them to the search requester.
    const onNewResults = (myResults) => {
        // Map the new results.
        const newResults = myResults.map((myResult) => ({
            key: myResult.keyAttribute,
            name: myResult.nameAttribute,
            shortDescription: myResult.shortDescriptionAttribute,
            description: myResult.descriptionAttribute,
            actions: [openWindowAction],
            data: myResult.customMetadata
        }));

        /* Push the new results to the search requester.

         If the `key` attribute matches a previously pushed search result,
         the old result will be updated with the new result's content. */
        response.respond(newResults);
    };
    myLongRunningQuery.onNewResults(onNewResults);

    /* Remove the listener and close the long running query if
       the request has been closed by the search requester. */
    request.onClose(() => {
        myLongRunningQuery.close();
    });

    /**
     * Upon query completion, close the response. This notifies
     * the requester that the current search provider is done sending results.
     */
    myLongRunningQuery.onQueryDone(() => {
        response.close();
    });
}

Readme

Keywords

Package Sidebar

Install

npm i @openfin/search-api

Weekly Downloads

0

Version

1.5.9

License

MIT

Unpacked Size

103 kB

Total Files

10

Last publish

Collaborators

  • ameet-openfin
  • jmransegnola
  • marek_openfin
  • yoge-openfin
  • nil.ffej
  • gilesstevenson-openfin
  • eheyder
  • newaz.sharif
  • efraim-herstic
  • royhafin
  • openfincolinhu
  • openfin-johans
  • alan15008
  • openfin-ci-gh
  • hina-khalid
  • ife-dev1
  • mjosling
  • elliott.burr
  • vsaw3
  • gallak-openfin
  • galim.kaudinov
  • hzhi0209
  • andy.westacott
  • __tomasz__
  • cameronopenfin
  • jennrondeau
  • dhilan
  • benstubbington
  • davidcoxon-of
  • openfin-jeff
  • gouthamc
  • hannahmcmillen
  • xyopenfin
  • smocarski
  • eugeneross-openfin
  • imansuri
  • manamiueda
  • sakibahmad
  • shahossain
  • openfinbrandon
  • pierrebaize
  • noyangunday
  • michaelmcoates
  • johnmandia-openfin
  • rdepena
  • tgoc99
  • wenjunche
  • harsimran.openfin.singh
  • luiemilio
  • licui3936
  • connormccafferty
  • adam.saland
  • openfin-ci
  • chrishobsonexpero
  • richbrowne-openfin
  • azizyok
  • openfin-gavin
  • oblarg