Skip to content

[7.x] [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement renderCellValue (#96098)#96233

Merged
andrew-goldstein merged 2 commits intoelastic:7.xfrom
andrew-goldstein:backport/7.x/pr-96098
Apr 5, 2021
Merged

[7.x] [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement renderCellValue (#96098)#96233
andrew-goldstein merged 2 commits intoelastic:7.xfrom
andrew-goldstein:backport/7.x/pr-96098

Conversation

@andrew-goldstein
Copy link
Contributor

Backports the following commits to 7.x:

…lement `renderCellValue` (elastic#96098)

### [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement `renderCellValue`

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

- The TGrid API was also updated to accept a collection of `RowRenderer`s as a prop

The API changes are summarized by the following screenshot:

<img width="1239" alt="render-cell-value" src="https://user-images.githubusercontent.com/4459398/113345484-c121f800-92ef-11eb-8a21-2b6dd8ef499b.png">

The following screenshot shows the `signal.rule.risk_score` column in the Alerts table being rendered with a green background color, using the same technique illustrated by `EuiDataGrid`'s [codesandbox example](https://codesandbox.io/s/nsmzs):

<img width="1231" alt="alerts" src="https://user-images.githubusercontent.com/4459398/113349015-a30ac680-92f4-11eb-8518-5c1b7465e76e.png">

Note: In the screenshot above, the values in the Alerts table are also _not_ rendered as draggables.

Related (RAC) issue: elastic#94520

### Details

The `StatefulEventsViewer` has been updated to accept `renderCellValue` as a (required) prop:

```
renderCellValue: (props: CellValueElementProps) => React.ReactNode;
```

The type definition of `CellValueElementProps` is:

```
export type CellValueElementProps = EuiDataGridCellValueElementProps & {
  data: TimelineNonEcsData[];
  eventId: string; // _id
  header: ColumnHeaderOptions;
  linkValues: string[] | undefined;
  timelineId: string;
};
```

The `CellValueElementProps` type above is a _superset_ of `EuiDataGridCellValueElementProps`. The additional properties above include the `data` returned by the TGrid when it performs IO to retrieve alerts and events.

### Using `renderCellValue` to control rendering

The internal implementation of TGrid's cell rendering didn't change with this PR; it moved to

`x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx` as shown below:

```
export const DefaultCellRenderer: React.FC<CellValueElementProps> = ({
  columnId,
  data,
  eventId,
  header,
  linkValues,
  setCellProps,
  timelineId,
}) => (
  <>
    {getColumnRenderer(header.id, columnRenderers, data).renderColumn({
      columnName: header.id,
      eventId,
      field: header,
      linkValues,
      timelineId,
      truncate: true,
      values: getMappedNonEcsValue({
        data,
        fieldName: header.id,
      }),
    })}
  </>
);
```

Any usages of TGrid were updated to pass `DefaultCellRenderer` as the value of the `renderCellValue` prop, as shown in the screenshot below:

<img width="1239" alt="render-cell-value" src="https://user-images.githubusercontent.com/4459398/113345484-c121f800-92ef-11eb-8a21-2b6dd8ef499b.png">

The `EuiDataGrid` [codesandbox example](https://codesandbox.io/s/nsmzs) provides the following example `renderCellValue` implementation, which highlights a cell green based on it's numeric value:

```
  const renderCellValue = useMemo(() => {
    return ({ rowIndex, columnId, setCellProps }) => {
      const data = useContext(DataContext);
      useEffect(() => {
        if (columnId === 'amount') {
          if (data.hasOwnProperty(rowIndex)) {
            const numeric = parseFloat(
              data[rowIndex][columnId].match(/\d+\.\d+/)[0],
              10
            );
            setCellProps({
              style: {
                backgroundColor: `rgba(0, 255, 0, ${numeric * 0.0002})`,
              },
            });
          }
        }
      }, [rowIndex, columnId, setCellProps, data]);

      function getFormatted() {
        return data[rowIndex][columnId].formatted
          ? data[rowIndex][columnId].formatted
          : data[rowIndex][columnId];
      }

      return data.hasOwnProperty(rowIndex)
        ? getFormatted(rowIndex, columnId)
        : null;
    };
  }, []);
```

The sample code above formats the `amount` column in the example `EuiDataGrid` with a green `backgroundColor` based on the value of the data, as shown in the screenshot below:

<img width="956" alt="datagrid-cell-formatting" src="https://user-images.githubusercontent.com/4459398/113348300-a782af80-92f3-11eb-896a-3d92cf4b9b53.png">

To demonstrate that similar styling can be applied to TGrid using the same technique illustrated by `EuiDataGrid`'s [codesandbox example](https://codesandbox.io/s/nsmzs), we can update the `DefaultCellRenderer` in `x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx` to apply a similar technique:

```
export const DefaultCellRenderer: React.FC<CellValueElementProps> = ({
  columnId,
  data,
  eventId,
  header,
  linkValues,
  setCellProps,
  timelineId,
}) => {
  useEffect(() => {
    if (columnId === 'signal.rule.risk_score') {
      const value = getMappedNonEcsValue({
        data,
        fieldName: columnId,
      });
      if (Array.isArray(value) && value.length > 0) {
        const numeric = parseFloat(value[0]);
        setCellProps({
          style: {
            backgroundColor: `rgba(0, 255, 0, ${numeric * 0.002})`,
          },
        });
      }
    }
  }, [columnId, data, setCellProps]);

  return (
    <>
      {getMappedNonEcsValue({
        data,
        fieldName: columnId,
      })}
    </>
  );
};
```

The example code above renders the  `signal.rule.risk_score` column in the Alerts table with a green `backgroundColor` based on the value of the data, as shown in the screenshot below:

<img width="1231" alt="alerts" src="https://user-images.githubusercontent.com/4459398/113349015-a30ac680-92f4-11eb-8518-5c1b7465e76e.png">

Note: In the screenshot above, the values in the Alerts table are not rendered as draggables.
@andrew-goldstein andrew-goldstein added the backport This PR is a backport of another PR label Apr 5, 2021
@andrew-goldstein andrew-goldstein enabled auto-merge (squash) April 5, 2021 17:47
@andrew-goldstein
Copy link
Contributor Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 2207 2209 +2

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.3MB 7.3MB +5.2KB

History

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

@andrew-goldstein andrew-goldstein merged commit 560e671 into elastic:7.x Apr 5, 2021
@andrew-goldstein andrew-goldstein deleted the backport/7.x/pr-96098 branch April 5, 2021 22:55
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