Skip to content

Commit

Permalink
flyouts, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
smith committed Mar 31, 2021
1 parent d747074 commit 4316c07
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ import { AlertItem } from './alerts_table';
type AlertsFlyoutProps = AlertItem & EuiFlyoutProps;

export function AlertsFlyout(props: AlertsFlyoutProps) {
const { affectedEntity, expectedValue, onClose, reason, severityLog, status, type } = props;
const { affectedEntity, onClose, reason, severityLog } = props;
const actualValue = props['alert.severity.value'];
const duration = props['alert.duration.us'];
const expectedValue = props['evaluation.threshold'];
const severity = props['alert.severity.level'];
const actualValue = props['alert.severity.value'];
const status = props['alert.status'];
const timestamp = props['@timestamp'];
const type = props['rule.name'];

const overviewListItems = [
{
Expand Down
123 changes: 59 additions & 64 deletions x-pack/plugins/observability/public/pages/alerts/alerts_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@
*/

import {
EuiBasicTable,
EuiBasicTableColumn,
EuiBasicTableProps,
EuiButtonEmpty,
EuiDataGrid,
EuiDataGridCellValueElementProps,
EuiDataGridColumn,
EuiDataGridControlColumn,
DefaultItemAction,
EuiTableSelectionType,
EuiLink,
EuiDataGridColumnActions,
} from '@elastic/eui';
import moment from 'moment-timezone';
import React, { useState } from 'react';
import { usePluginContext } from '../../hooks/use_plugin_context';
import { AlertsFlyout } from './alerts_flyout';
Expand All @@ -30,69 +26,81 @@ import { AlertsFlyout } from './alerts_flyout';
* the API response.
*/
export interface AlertItem {
// These items may be included in the schema (https://github.com/elastic/kibana/issues/93728):
'@timestamp': number;
reason: string;
'alert.duration.us'?: number;
'alert.severity.level'?: string;
// These are just made up so we can make example links
'alert.severity.value'?: string;
'alert.status'?: string;
'evaluation.threshold'?: string;
'rule.name'?: string;

// These are either made up so we can make sample links, or could be included in the schema
'service.name'?: string;
pod?: string;
log?: boolean;
// Other fields used in the flyout
'alert.severity.value'?: string;

// These are used in example flyouts or are not yet reflected in the schema
affectedEntity?: string;
expectedValue?: string;
reason: string;
severityLog?: Array<{ '@timestamp': number; severity: string; message: string }>;
status?: string;
'alert.duration.us'?: number;
type?: string;
}

type AlertsTableProps = Omit<
EuiBasicTableProps<AlertItem>,
'columns' | 'isSelectable' | 'pagination' | 'selection'
>;
interface AlertsTableProps {
items: AlertItem[];
}

/**
* This is a contrived implementation of the reason field that shows how
* you could link to certain types of resources based on what's contained
* in their alert data.
*/
function ReasonRenderer(item: AlertItem) {
const { prepend } = usePluginContext().core.http.basePath;
const text = item.reason;
const serviceName = item['service.name'];
const pod = item.pod;
const log = item.log;

if (serviceName) {
return <EuiLink href={prepend(`/app/apm/services/${serviceName}`)}>{text}</EuiLink>;
} else if (pod) {
return <EuiLink href={prepend(`/app/metrics/link-to/host-detail/${pod}`)}>{text}</EuiLink>;
} else if (log) {
return <EuiLink href={prepend(`/app/logs/stream`)}>{text}</EuiLink>;
} else {
return <>{text}</>;
}
}

export function AlertsTable({ items }: AlertsTableProps) {
const [flyoutAlert, setFlyoutAlert] = useState<AlertItem | undefined>(undefined);
const handleFlyoutClose = () => setFlyoutAlert(undefined);
const { prepend } = usePluginContext().core.http.basePath;

// This is a contrived implementation of the reason field that shows how
// you could link to certain types of resources based on what's contained
// in their alert data.
function ReasonRenderer(props: AlertItem) {
const item = props;
const text = props.reason;
const serviceName = item['service.name'];
const pod = item.pod;
const log = item.log;
function ActionCellRenderer({ rowIndex }: EuiDataGridCellValueElementProps) {
const item = items[rowIndex];
const handleClick = () => {
setFlyoutAlert(item);
};

if (serviceName) {
return <EuiLink href={prepend(`/app/apm/services/${serviceName}`)}>{text}</EuiLink>;
} else if (pod) {
return <EuiLink href={prepend(`/app/metrics/link-to/host-detail/${pod}`)}>{text}</EuiLink>;
} else if (log) {
return <EuiLink href={prepend(`/app/logs/stream`)}>{text}</EuiLink>;
} else {
return <>{text}</>;
}
return <EuiButtonEmpty onClick={handleClick}>Alert details</EuiButtonEmpty>;
}

function ActionCellRenderer(props: EuiDataGridCellValueElementProps) {
return null;
function CellValueRenderer({ columnId, rowIndex }: EuiDataGridCellValueElementProps) {
const item = items[rowIndex];
const value = item[columnId as keyof AlertItem];
switch (columnId) {
case '@timestamp':
return <>{new Date(value as number).toISOString()}</>;
case 'alert.duration.us':
return <>{moment.duration((value as number) / 1000).humanize()}</>;
case 'reason':
return <ReasonRenderer {...item} />;
default:
return value ? <>{value}</> : null;
}
}

const actions: EuiDataGridColumnActions = [
{
name: 'Alert details',
description: 'Alert details',
onClick: (item) => {
setFlyoutAlert(item);
},
isPrimary: true,
},
];

const columns: EuiDataGridColumn[] = [
{
id: '@timestamp',
Expand All @@ -114,22 +122,9 @@ export function AlertsTable({ items }: AlertsTableProps) {
];

const trailingControlColumns: EuiDataGridControlColumn[] = [
{ id: 'actions', headerCellRender: () => null, rowCellRender: ActionCellRenderer, width: 40 },
{ id: 'actions', headerCellRender: () => null, rowCellRender: ActionCellRenderer, width: 120 },
];

function CellValueRenderer({ columnId, rowIndex }: EuiDataGridCellValueElementProps) {
const item = items[rowIndex];
const value = item[columnId as keyof AlertItem];
switch (columnId) {
case '@timestamp':
return <>{new Date(value as number).toISOString()}</>;
case 'reason':
return <ReasonRenderer {...item} />;
default:
return value ? <>{value}</> : null;
}
}

const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id));

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ export const wireframeData = [
reason: 'Error count is greater than 100 (current value is 135) on shippingService',
'service.name': 'opbeans-go',
affectedEntity: 'opbeans-go service',
status: 'Active',
expectedValue: '< 100',
'alert.status': 'active',
'evaluation.threshold': '100',
'alert.severity.value': '135',
severityLog: [
{ '@timestamp': 1615392661000, severity: 'critical', message: 'Load is 3.5' },
{ '@timestamp': 1615392600000, severity: 'warning', message: 'Load is 2.5' },
{ '@timestamp': 1615392552000, severity: 'critical', message: 'Load is 3.5' },
],
type: 'APM Error count',
'rule.name': 'APM Error count',
},
{
'@timestamp': 1615392600000,
Expand Down

0 comments on commit 4316c07

Please sign in to comment.