kibana/src/plugins/unified_histogram/public/container/container.tsx
Davis McPhee 3e1865513d
[Discover] Add resize support to the Discover field list sidebar (#167066)
## Summary

This PR adds resize support to the Discover field list sidebar, which is
persisted to a user's local storage similar to the resizable chart
height.

Additionally it migrates the resizable layout code from Unified
Histogram to a new package called `kbn-resizable-layout` so it can be
shared between Discover and Unified Histogram, as well as act as a new
platform component that other teams can consume to create their own
resizable layouts.


![resize](71b9a0ae-1795-43c8-acb0-e75fe46e2a8a)

Resolves #9531.

### Checklist

- [ ] ~Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)~
- [ ]
~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials~
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] ~Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))~
- [ ] ~If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
2023-09-27 21:52:25 -03:00

159 lines
4.8 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { Subject } from 'rxjs';
import { pick } from 'lodash';
import useMount from 'react-use/lib/useMount';
import { LensSuggestionsApi } from '@kbn/lens-plugin/public';
import { UnifiedHistogramLayout, UnifiedHistogramLayoutProps } from '../layout';
import type { UnifiedHistogramInputMessage, UnifiedHistogramRequestContext } from '../types';
import {
createStateService,
UnifiedHistogramStateOptions,
UnifiedHistogramStateService,
} from './services/state_service';
import { useStateProps } from './hooks/use_state_props';
import { useStateSelector } from './utils/use_state_selector';
import { topPanelHeightSelector, currentSuggestionSelector } from './utils/state_selectors';
type LayoutProps = Pick<
UnifiedHistogramLayoutProps,
'disableAutoFetching' | 'disableTriggers' | 'disabledActions'
>;
/**
* The options used to initialize the container
*/
export type UnifiedHistogramCreationOptions = Omit<UnifiedHistogramStateOptions, 'services'> &
LayoutProps;
/**
* The props exposed by the container
*/
export type UnifiedHistogramContainerProps = {
getCreationOptions?: () =>
| UnifiedHistogramCreationOptions
| Promise<UnifiedHistogramCreationOptions>;
searchSessionId?: UnifiedHistogramRequestContext['searchSessionId'];
requestAdapter?: UnifiedHistogramRequestContext['adapter'];
isChartLoading?: boolean;
} & Pick<
UnifiedHistogramLayoutProps,
| 'services'
| 'className'
| 'dataView'
| 'query'
| 'filters'
| 'timeRange'
| 'relativeTimeRange'
| 'columns'
| 'container'
| 'appendHitsCounter'
| 'children'
| 'onBrushEnd'
| 'onFilter'
| 'withDefaultActions'
| 'disabledActions'
>;
/**
* The API exposed by the container
*/
export type UnifiedHistogramApi = {
/**
* Manually trigger a refetch of the data
*/
refetch: () => void;
} & Pick<
UnifiedHistogramStateService,
| 'state$'
| 'setChartHidden'
| 'setTopPanelHeight'
| 'setBreakdownField'
| 'setTimeInterval'
| 'setTotalHits'
>;
export const UnifiedHistogramContainer = forwardRef<
UnifiedHistogramApi,
UnifiedHistogramContainerProps
>((containerProps, ref) => {
const [layoutProps, setLayoutProps] = useState<LayoutProps>();
const [stateService, setStateService] = useState<UnifiedHistogramStateService>();
const [lensSuggestionsApi, setLensSuggestionsApi] = useState<LensSuggestionsApi>();
const [input$] = useState(() => new Subject<UnifiedHistogramInputMessage>());
const [api, setApi] = useState<UnifiedHistogramApi>();
// Expose the API to the parent component
useImperativeHandle(ref, () => api!, [api]);
// Call for creation options once the container is mounted
useMount(async () => {
const { getCreationOptions, services } = containerProps;
const options = await getCreationOptions?.();
const apiHelper = await services.lens.stateHelperApi();
setLayoutProps(pick(options, 'disableAutoFetching', 'disableTriggers', 'disabledActions'));
setStateService(createStateService({ services, ...options }));
setLensSuggestionsApi(() => apiHelper.suggestions);
});
// Initialize the API once the state service is available
useEffect(() => {
if (!stateService) {
return;
}
setApi({
refetch: () => {
input$.next({ type: 'refetch' });
},
...pick(
stateService,
'state$',
'setChartHidden',
'setTopPanelHeight',
'setBreakdownField',
'setTimeInterval',
'setTotalHits'
),
});
}, [input$, stateService]);
const { dataView, query, searchSessionId, requestAdapter, isChartLoading } = containerProps;
const currentSuggestion = useStateSelector(stateService?.state$, currentSuggestionSelector);
const topPanelHeight = useStateSelector(stateService?.state$, topPanelHeightSelector);
const stateProps = useStateProps({
stateService,
dataView,
query,
searchSessionId,
requestAdapter,
});
// Don't render anything until the container is initialized
if (!layoutProps || !lensSuggestionsApi || !api) {
return null;
}
return (
<UnifiedHistogramLayout
{...containerProps}
{...layoutProps}
{...stateProps}
currentSuggestion={currentSuggestion}
isChartLoading={Boolean(isChartLoading)}
topPanelHeight={topPanelHeight}
input$={input$}
lensSuggestionsApi={lensSuggestionsApi}
/>
);
});
// eslint-disable-next-line import/no-default-export
export default UnifiedHistogramContainer;