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

wrapping SearchKitClient requests with a react component #1337

Open
zaalgol opened this issue Jan 29, 2024 Discussed in #1336 · 0 comments
Open

wrapping SearchKitClient requests with a react component #1337

zaalgol opened this issue Jan 29, 2024 Discussed in #1336 · 0 comments

Comments

@zaalgol
Copy link

zaalgol commented Jan 29, 2024

Discussed in #1336

Originally posted by zaalgol January 29, 2024
We use searchKit client of @searchkit/client in our react application.

The search kit config looks like this:


export const searchkitConfig = (authHeaders) => {

const config = {
    host: '/api/<URL>/v1/audit',
    index: 'in_app_audit',
    connectionOptions: {
    headers: authHeaders,
    },
    hits: {
    fields: ['category', 'type', 'level', 'message', 'user_email', 'timestamp'],
    },
    sortOptions: [
    {
        id: 'timestamp.desc', label: 'Time', field: [{ timestamp: 'desc' }], defaultOption: true,
    },
…
    return config;
};

export default {
  searchkitConfig,
};

The AuditView component that uses it:

import { inject, observer } from 'mobx-react';
import React, { useState, useContext } from 'react';

import {
  Button, Divider,
} from 'antd';

import _ from 'lodash';
import {
  DefaultActionModes, Icon, ModalFormButton, SearchButton,
} from 'ot-components';

import {
  useElasticWrapper, DropdownFacet, UserFacetDropdown, AccountFacetDropdown, TimestampFilter, getDefaultTimeStampFilter,
  AssetFacetDropdown,
} from 'ot-components';

import { withSearchkit, SearchkitClient } from '@searchkit/client';
import style from './AuditView.less';
import AuditMessages from './AuditMessages';
import { MessageService } from '../../utils';
import { downloadBlob, formatDateTime } from '../../utils/utils';
import { withCloudTokenProvider, CloudTokenContext } from '../../utils/CloudTokenProvider';
import { searchkitConfig } from '../../services/audit';
import AuditTableView from './AuditTableView/AuditTableView';

import {
  addSyslogServer,
  deleteSyslogServer, updateSyslogServer,
} from '../../services/management';

import SyslogServersForm from './SyslogServerForm';
import appStore from '../../stores/appStore';
import SyslogStore from '../../stores/SyslogStore';
import Messages from './SyslogMessages';

const getDefaultFilters = () => ([getDefaultTimeStampFilter()]);

const AuditView = (props) => {
  const cloudAuthHeaders = useContext(CloudTokenContext);
  const elasticwrapper = useElasticWrapper(searchkitConfig(cloudAuthHeaders), getDefaultFilters());
  // Setting a 'key' prop is the best way to force a re-render with react hooks
  const [searchComponentKey, setSearchComponentKey] = useState(0);
….
};


const createInitialSearchkitClient = () => {
  const searchkitClient = new SearchkitClient();
  searchkitClient.updateBaseSearchState({ filters: getDefaultFilters() });
  return searchkitClient;
};

export default withCloudTokenProvider(withSearchkit(inject('appStore', 'SyslogStore')(observer(AuditView)), createInitialSearchkitClient));

This is the ElasticWrapper code:

import { useEffect, useState } from 'react';
import { useSearchkit, useSearchkitVariables } from '@searchkit/client';
import { useSearchkitSDK } from '@searchkit/sdk/lib/esm/react-hooks';
import _ from 'lodash';

const pageSize = 30;

/**
 * A wrapper for searchkit SDK/client.
 *
 * Features:
 * - Map facets by id: because we can't use searchkit's
 *   FacetsList component.
 * - Infinite scroll support: searckit client doesn't
 *   have a native "load more data" method without
 *   losing all usage of its state management. In this
 *   wrapper we wrap searchkit's interface to
 *   accumulate results. We export 'resetResultsPage'
 *   method to drop all accumulated data and re-load
 *   the first page.
 * - Fix a bug in searchkit where is doesn't apply the
 *   default sort option.
 */
export function useElasticWrapper(searchkitConfig, defaultFilters) {
  const [wasSortSet, setWasSortSet] = useState(false);
  const [fullResults, setFullResults] = useState([]);
  const [facets, setFacets] = useState({});
  const variables = useSearchkitVariables();
  variables.page.size = pageSize;
  if (!wasSortSet) {
    setDefaultSort();
  }
  const { results, loading } = useSearchkitSDK(searchkitConfig, variables);
  const api = useSearchkit();

  const isLoading = loading || results === null;

  function setDefaultSort() {
    // Searchkit's default sort option doesn't work (possibly only
    // without apollo) so we set it manually
    variables.sortBy = searchkitConfig.sortOptions?.find((sortOption) => (
      sortOption.defaultOption
    ))?.id;
  }

  const search = async ({ shouldKeepResultsPage = false } = {}) => {
    if (!shouldKeepResultsPage) {
      resetResultsPage();
    }
    api.search();
  };
...

This works, but I need to wrap our request with an async TokenRequest component. the TokenRequest handles all the token logic, and if the request fails, it sends a request for a new token, then calls the original request again.
Here is an example of how we do it in other places in the code:

export async function createAccount(data, messages) {
  return tokenRequest({
  path: 'asset-service/v1/accounts', method: 'POST', data, messages,
});
}

In general, I could use transporter to add complicated logic, but we don’t do the API request directly with the Searchkit request method. 
instead, the code uses useSearchkit from @searchkit/client, and does these requests with this code:

const api = useSearchkit();
api.search();

Also, the useSearchkitSDK constructor expects a searchkitConfig object as first parameter, not SearchkitRequest (the output of Searchkit(config, transporter)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant