Skip to content

[7.x] [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement a subset of the EuiDataGridColumn API (#98241)#98665

Merged
andrew-goldstein merged 1 commit intoelastic:7.xfrom
andrew-goldstein:backport/7.x/pr-98241
Apr 28, 2021
Merged

[7.x] [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement a subset of the EuiDataGridColumn API (#98241)#98665
andrew-goldstein merged 1 commit intoelastic:7.xfrom
andrew-goldstein:backport/7.x/pr-98241

Conversation

@andrew-goldstein
Copy link
Contributor

Backports the following commits to 7.x:

…lement a subset of the `EuiDataGridColumn` API (elastic#98241)

## [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement a subset of the `EuiDataGridColumn` API

This PR implements the following subset of the `EuiDataGridColumn` API from [EuiDataGrid](https://elastic.github.io/eui/#/tabular-content/data-grid) in the `TGrid` (Timeline grid):

```ts
Pick<EuiDataGridColumn, 'display' | 'displayAsText' | 'id' | 'initialWidth'>
```

The above properties are [documented in EuiDataGrid's data_grid_types.ts](https://github.com/elastic/eui/blob/master/src/components/datagrid/data_grid_types.ts), and summarized in the table below:

| Property                   | Description                                                                                                                                                                                                                        |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `display?:  ReactNode`    | A `ReactNode` used when rendering the column header                                                                                                                                                                                |
| `displayAsText?:  string` | Displays the column name as text (in lieu of using `display`). If not used, `id` will be shown as the column name. |
| `id:  string`             | The unique identifier for this column, e.g. `user.name`                                                                                                                                                                            |
| `initialWidth?:  number`   | Initial width (in pixels) of the column                                                                                                                                                                                            |

The following screenshot shows the `TGrid` rendering (from left-to-right):

- An (example) RAC-flavored Observability alerts table
- An (example) RAC-flavored Security Solution alerts table
- The production alerts table in the Security Solutions `Detections` page, which remains the default

![three_table_configurations](https://user-images.githubusercontent.com/4459398/115944491-5a69a780-a473-11eb-85b6-36120c3092d6.png)

_Above, three table configurations, rendered via the updated API_

The `public/detections/configurations` directory contains the configurations for the three tables shown in the screenshot above

This change works in concert with another recent change to the `TGrid` that [added support for the `renderCellValue` API](elastic#96098).

### Example configurations

#### (example) RAC-flavored Observability alerts table

![observability_alerts_example](https://user-images.githubusercontent.com/4459398/115944556-b3d1d680-a473-11eb-8338-6097731f2d48.png)

The column specification for the (example) RAC-flavored Observability alerts table, shown in the screenshot above is defined in `x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/columns.ts`:

```ts
export const columns: Array<
  Pick<EuiDataGridColumn, 'display' | 'displayAsText' | 'id' | 'initialWidth'> & ColumnHeaderOptions
> = [
  {
    columnHeaderType: defaultColumnHeaderType,
    displayAsText: i18n.STATUS,
    id: 'kibana.rac.alert.status',
    initialWidth: 74,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    displayAsText: i18n.TRIGGERED,
    id: '@timestamp',
    initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH + 5,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    displayAsText: i18n.ALERT_DURATION,
    id: 'kibana.rac.alert.duration.us',
    initialWidth: 116,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    displayAsText: i18n.ALERTS_HEADERS_SEVERITY,
    id: 'signal.rule.severity',
    initialWidth: 102,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    displayAsText: i18n.ALERTS_HEADERS_REASON,
    id: 'signal.reason',
    initialWidth: 644,
  },
];
```

The example implementation of `EuiDataGrid`'s [`renderCellValue` API](elastic#96098) used to render the RAC-flavored Observability alerts table shown in the screenshot above is located in `x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/render_cell_value.tsx`:

```ts
/**
 * This implementation of `EuiDataGrid`'s `renderCellValue`
 * accepts `EuiDataGridCellValueElementProps`, plus `data`
 * from the TGrid
 */
export const renderCellValue: React.FC<
  EuiDataGridCellValueElementProps & CellValueElementProps
> = ({
  columnId,
  data,
  eventId,
  header,
  isDetails,
  isExpandable,
  isExpanded,
  linkValues,
  rowIndex,
  setCellProps,
  timelineId,
}) => {
  const value =
    getMappedNonEcsValue({
      data,
      fieldName: columnId,
    })?.reduce((x) => x[0]) ?? '';

  switch (columnId) {
    case 'kibana.rac.alert.status':
      return <Status status={random(0, 1) ? 'recovered' : 'active'} />;
    case 'kibana.rac.alert.duration.us':
      return <span>{moment(value).fromNow(true)}</span>;
    case 'signal.rule.severity':
      return <Severity severity={value} />;
    case 'signal.reason':
      return (
        <EuiLink>
          <TruncatableText>{reason}</TruncatableText>
        </EuiLink>
      );
    default:
      // NOTE: we're using `DefaultCellRenderer` in this example configuration as a fallback, but
      // using `DefaultCellRenderer` here is entirely optional
      return (
        <DefaultCellRenderer
          columnId={columnId}
          data={data}
          eventId={eventId}
          header={header}
          isDetails={isDetails}
          isExpandable={isExpandable}
          isExpanded={isExpanded}
          linkValues={linkValues}
          rowIndex={rowIndex}
          setCellProps={setCellProps}
          timelineId={timelineId}
        />
      );
  }
};
```

#### (example) RAC-flavored Security Solution alerts table

![secuirty_solution_rac_example](https://user-images.githubusercontent.com/4459398/115944592-e8459280-a473-11eb-9e0f-cef8519102d4.png)

The column specification for the (example) RAC-flavored Security Solution alerts table, shown in the screenshot above is defined in `x-pack/plugins/security_solution/public/detections/configurations/examples/security_solution_rac/columns.ts`:

```ts
/**
 * columns implements a subset of `EuiDataGrid`'s `EuiDataGridColumn` interface,
 * plus additional TGrid column properties
 */
export const columns: Array<
  Pick<EuiDataGridColumn, 'display' | 'displayAsText' | 'id' | 'initialWidth'> & ColumnHeaderOptions
> = [
  {
    columnHeaderType: defaultColumnHeaderType,
    id: '@timestamp',
    initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH + 5,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    id: 'signal.rule.name',
    displayAsText: i18n.ALERTS_HEADERS_RULE_NAME,
    linkField: 'signal.rule.id',
    initialWidth: 212,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    id: 'signal.rule.severity',
    displayAsText: i18n.ALERTS_HEADERS_SEVERITY,
    initialWidth: 104,
  },
  {
    columnHeaderType: defaultColumnHeaderType,
    id: 'signal.reason',
    displayAsText: i18n.ALERTS_HEADERS_REASON,
    initialWidth: 644,
  },
];
```

### Testing the example configurations locally

For now, the alerts table in the Security Solution's `Detections` page is configured to use the existing (`7.13`) column configuration.

To test the Alerts table in the Security Solution `Detections` page with the example configurations provided in this PR:

1. Edit `x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx` and change the following line:

```ts
import { columns, RenderCellValue } from '../../configurations/security_solution_detections';
```

from the above to

```ts
import { columns, RenderCellValue } from '../../configurations/examples/observablity_alerts';
```

for the (example) RAC-flavored Observability alerts table, or change it to

```ts
import { columns, RenderCellValue } from '../../configurations/examples/security_solution_rac';
```

for the (example) RAC-flavored Security solution alerts table.

2. Navigate to your local instance of the Security Solution [Detections page](http://localhost:5601/xyx/app/security/detections) (Note: you may need to enable detection rules to populate the alerts table.)

3. Click the `customize_columns` button shown in the screenshot below:

![customize_columns](https://user-images.githubusercontent.com/4459398/115796322-e3f37980-a38e-11eb-930b-5b21dfcb5e65.png)

4. In the `Customize Columns` popover, click the `Reset Fields` button, shown in the screenshot below:

![reset-fields](https://user-images.githubusercontent.com/4459398/115797081-49943580-a390-11eb-9485-7e6cae2f2a6f.png)

After clicking `Reset Fields`, the new default columns will be displayed.

### Backwards compatibility

The `width` property of Timeline's model was changed to `initialWidth` as part of this PR.

- This change has no effect on Timelines persisted as saved objects
- This change has no effect on Timeline's [Export and Import Timelines](https://www.elastic.co/guide/en/security/current/timelines-ui.html#import-export-timelines) feature
- When a TGrid's column configuration containing the legacy `width` and `label` `ColumnHeaderOptions` is read from `localstorage`, these properties are migrated to `initialWidth` and `displayAsText` respectively.
  - Backwards compatibility was desk tested by persisting a custom column configuration while running off `master`, and then re-visiting the page after running this PR branch. As expected, the previously persisted column configuration was rendered correctly after running the PR branch.
  - Unit tests were added to `x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts` to test the migration of the `width` and `label` properties

### Other changes

- The minium width of a resized column is now `70px`. The new minium is no longer data-type specific.
@andrew-goldstein andrew-goldstein added the backport This PR is a backport of another PR label Apr 28, 2021
@andrew-goldstein andrew-goldstein enabled auto-merge (squash) April 28, 2021 18:29
@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 2178 2181 +3

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 7.0MB 7.0MB +5.9KB

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@andrew-goldstein andrew-goldstein merged commit 4dac2af into elastic:7.x Apr 28, 2021
@andrew-goldstein andrew-goldstein deleted the backport/7.x/pr-98241 branch April 28, 2021 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport This PR is a backport of another PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants