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

[RAC] [TGrid] Implements cell actions in the TGrid #107771

Merged
merged 1 commit into from
Aug 5, 2021

Commits on Aug 5, 2021

  1. ## Summary

    This PR implements cell actions in the `TGrid`, rendering them via `EuiDataGrid`, per the screenshots below:
    
    ### Before
    
    Users previously hovered over a draggable field to view and trigger cell actions, as illustrated by the `Before` screenshots below:
    
    <img width="1348" alt="legacy_cell_actions" src="https://user-images.githubusercontent.com/4459398/128351498-49b4d224-6c51-4293-b14f-46bbb58f7cb3.png">
    
    _Above: legacy `TGrid` cell action rendering_
    
    ### After
    
    Cell actions are now rendered via `EuiDataGrid` cell actions:
    
    <img width="997" alt="euidatagrid_cell_actions" src="https://user-images.githubusercontent.com/4459398/128358847-c5540ea4-8ba1-4b35-ab6b-3b3e39ae54ce.png">
    
    _Above: new `TGrid` cell action rendering via `EuiDataGrid`_
    
    ## Technical Details
    
    Every instance of the `TGrid` on a page can specify its own set of cell actions via `defaultCellActions` when calling the `timelines.getTGrid()` function create an instance.
    
    For example, the Observability Alerts `TGrid` is initialized in with a default set of actions in `x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx`, as shown in the code below:
    
    ```ts
          {timelines.getTGrid<'standalone'>({
            type: 'standalone',
            columns,
            deletedEventIds: [],
            defaultCellActions: getDefaultCellActions({ enableFilterActions: false }), // <-- defaultCellActions
            // ...
        </>
    ```
    
    The type of the `defaultCellActions` is:
    
    ```ts
    defaultCellActions?: TGridCellAction[];
    ```
    
    and the definition of `TGridCellAction` is in `x-pack/plugins/timelines/common/types/timeline/columns/index.tsx`:
    
    ```ts
    /**
     * A `TGridCellAction` function accepts `data`, where each row of data is
     * represented as a `TimelineNonEcsData[]`. For example, `data[0]` would
     * contain a `TimelineNonEcsData[]` with the first row of data.
     *
     * A `TGridCellAction` returns a function that has access to all the
     * `EuiDataGridColumnCellActionProps`, _plus_ access to `data`,
     *  which enables code like the following example to be written:
     *
     * Example:
     * ```
     * ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
     *   const value = getMappedNonEcsValue({
     *     data: data[rowIndex], // access a specific row's values
     *     fieldName: columnId,
     *   });
     *
     *   return (
     *     <Component onClick={() => alert(`row ${rowIndex} col ${columnId} has value ${value}`)} iconType="heart">
     *       {'Love it'}
     *      </Component>
     *   );
     * };
     * ```
     */
    export type TGridCellAction = ({
      browserFields,
      data,
    }: {
      browserFields: BrowserFields;
      /** each row of data is represented as one TimelineNonEcsData[] */
      data: TimelineNonEcsData[][];
    }) => (props: EuiDataGridColumnCellActionProps) => ReactNode;
    ```
    
    For example, the following `TGridCellAction[]` defines the `Copy to clipboard` action for the Observability Alerts table in `x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx`:
    
    ```ts
    /** actions common to all cells (e.g. copy to clipboard) */
    const commonCellActions: TGridCellAction[] = [
      ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => {
        const { timelines } = useKibanaServices();
    
        const value = getMappedNonEcsValue({
          data: data[rowIndex],
          fieldName: columnId,
        });
    
        return (
          <>
            {timelines.getHoverActions().getCopyButton({
              Component,
              field: columnId,
              isHoverAction: false,
              ownFocus: false,
              showTooltip: false,
              value,
            })}
          </>
        );
      },
    ];
    ```
    
    Note that an _implementation_ of the copy action, including the button, is available for both the Observability and Security solutions to use via `timelines.getHoverActions().getCopyButton()`, (and both solutions use it in this PR), but there's no requirement to use that specific implementation of the copy action.
    
    ### Security Solution cell actions
    
    All previously-available hover actions in the Security Solution are now available as cell actions, i.e.:
    
    - Filter for value
    - Filter out value
    - Add to timeline investigation
    - Show Top `<field>` (only enabled for some data types)
    - Copy to clipboard
    
    ### Observability cell actions
    
    In this PR:
    
    - Only the `Copy to clipboard` cell action is enabled by default in the Observability Alerts table
    - The `Filter for value` and `Filter out value` cell actions may be enabled in the `Observability` solution by changing a single line of code, (setting `enableFilterActions` to true), on the following line in `x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx`:
    
    ```js
    defaultCellActions: getDefaultCellActions({ enableFilterActions: false }), // <-- set this to `true` to enable the filter actions
    ```
    
    `enableFilterActions` is set to `false` in this PR because the Observability Alerts page's search bar, defined in `x-pack/plugins/observability/public/pages/alerts/alerts_search_bar.tsx`:
    
    ```ts
      return (
        <SearchBar
          indexPatterns={dynamicIndexPattern}
          placeholder={i18n.translate('xpack.observability.alerts.searchBarPlaceholder', {
            defaultMessage: 'kibana.alert.evaluation.threshold > 75',
          })}
          query={{ query: query ?? '', language: queryLanguage }}
          // ...
        />
    ````
    
    must be integrated with a `filterManager` to display the filters. A `filterManager` instance may be obtained in the Observability solution via the following boilerplate:
    
    ```ts
      const {
        services: {
          data: {
            query: { filterManager },
          },
        },
      } = useKibana<ObservabilityPublicPluginsStart>();
    ```
    
    ## Desk testing
    
    To desk test this PR, you must enable feature flags in the Observability and Security Solution:
    
    - To desk test the `Observability > Alerts` page, add the following settings to `config/kibana.dev.yml`:
    
    ```
    xpack.observability.unsafe.cases.enabled: true
    xpack.observability.unsafe.alertingExperience.enabled: true
    xpack.ruleRegistry.write.enabled: true
    ```
    
    - To desk test the TGrid in the following Security Solution, edit `x-pack/plugins/security_solution/common/experimental_features.ts` and in the `allowedExperimentalValues` section set:
    
    ```typescript
    tGridEnabled: true,
    ```
    
    cc @mdefazio
    andrew-goldstein committed Aug 5, 2021
    Configuration menu
    Copy the full SHA
    f24e4ea View commit details
    Browse the repository at this point in the history