Skip to content

Commit

Permalink
Merge branch 'master' of github.com:elastic/kibana into implement/lin…
Browse files Browse the repository at this point in the history
…k-data-plugin
  • Loading branch information
spalger committed Apr 7, 2020
2 parents eb84a72 + a8f84f8 commit 1da77f8
Show file tree
Hide file tree
Showing 45 changed files with 1,968 additions and 980 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { EuiLink, EuiText } from '@elastic/eui';
import Mustache from 'mustache';
import React from 'react';
import styled from 'styled-components';
import { CustomLink } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types';
import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction';
import {
SectionLinks,
SectionLink
} from '../../../../../../../../plugins/observability/public';
import { px, truncate, units } from '../../../../style/variables';

const LinkContainer = styled.li`
margin-top: ${px(units.half)};
&:first-of-type {
margin-top: 0;
}
`;

const TruncateText = styled(EuiText)`
font-weight: 500;
line-height: ${px(units.unit)};
${truncate(px(units.unit * 25))}
`;

export const CustomLinkSection = ({
customLinks,
Expand All @@ -19,7 +31,7 @@ export const CustomLinkSection = ({
customLinks: CustomLink[];
transaction: Transaction;
}) => (
<SectionLinks>
<ul>
{customLinks.map(link => {
let href = link.url;
try {
Expand All @@ -28,13 +40,12 @@ export const CustomLinkSection = ({
// ignores any error that happens
}
return (
<SectionLink
key={link.id}
label={link.label}
href={href}
target="_blank"
/>
<LinkContainer key={link.id}>
<EuiLink href={href} target="_blank">
<TruncateText size="s">{link.label}</TruncateText>
</EuiLink>
</LinkContainer>
);
})}
</SectionLinks>
</ul>
);
8 changes: 6 additions & 2 deletions x-pack/legacy/plugins/monitoring/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,15 @@ export const ALERT_TYPE_PREFIX = 'monitoring_';
* This is the alert type id for the license expiration alert
*/
export const ALERT_TYPE_LICENSE_EXPIRATION = `${ALERT_TYPE_PREFIX}alert_type_license_expiration`;
/**
* This is the alert type id for the cluster state alert
*/
export const ALERT_TYPE_CLUSTER_STATE = `${ALERT_TYPE_PREFIX}alert_type_cluster_state`;

/**
* A listing of all alert types
*/
export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION];
export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_STATE];

/**
* Matches the id for the built-in in email action type
Expand All @@ -254,7 +258,7 @@ export const ALERT_ACTION_TYPE_EMAIL = '.email';
/**
* The number of alerts that have been migrated
*/
export const NUMBER_OF_MIGRATED_ALERTS = 1;
export const NUMBER_OF_MIGRATED_ALERTS = 2;

/**
* The advanced settings config name for the email address
Expand Down
44 changes: 27 additions & 17 deletions x-pack/legacy/plugins/monitoring/public/components/alerts/alerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@

import React from 'react';
import chrome from '../../np_imports/ui/chrome';
import { capitalize } from 'lodash';
import { capitalize, get } from 'lodash';
import { formatDateTimeLocal } from '../../../common/formatting';
import { formatTimestampToDuration } from '../../../common';
import { CALCULATE_DURATION_SINCE, EUI_SORT_DESCENDING } from '../../../common/constants';
import {
CALCULATE_DURATION_SINCE,
EUI_SORT_DESCENDING,
ALERT_TYPE_LICENSE_EXPIRATION,
ALERT_TYPE_CLUSTER_STATE,
} from '../../../common/constants';
import { mapSeverity } from './map_severity';
import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert';
import { EuiMonitoringTable } from 'plugins/monitoring/components/table';
Expand All @@ -21,6 +26,8 @@ const linkToCategories = {
'elasticsearch/indices': 'Elasticsearch Indices',
'kibana/instances': 'Kibana Instances',
'logstash/instances': 'Logstash Nodes',
[ALERT_TYPE_LICENSE_EXPIRATION]: 'License expiration',
[ALERT_TYPE_CLUSTER_STATE]: 'Cluster state',
};
const getColumns = (kbnUrl, scope, timezone) => [
{
Expand Down Expand Up @@ -94,19 +101,22 @@ const getColumns = (kbnUrl, scope, timezone) => [
}),
field: 'message',
sortable: true,
render: (message, alert) => (
<FormattedAlert
prefix={alert.prefix}
suffix={alert.suffix}
message={message}
metadata={alert.metadata}
changeUrl={target => {
scope.$evalAsync(() => {
kbnUrl.changePath(target);
});
}}
/>
),
render: (_message, alert) => {
const message = get(alert, 'message.text', get(alert, 'message', ''));
return (
<FormattedAlert
prefix={alert.prefix}
suffix={alert.suffix}
message={message}
metadata={alert.metadata}
changeUrl={target => {
scope.$evalAsync(() => {
kbnUrl.changePath(target);
});
}}
/>
);
},
},
{
name: i18n.translate('xpack.monitoring.alerts.categoryColumnTitle', {
Expand Down Expand Up @@ -148,8 +158,8 @@ const getColumns = (kbnUrl, scope, timezone) => [
export const Alerts = ({ alerts, angular, sorting, pagination, onTableChange }) => {
const alertsFlattened = alerts.map(alert => ({
...alert,
status: alert.metadata.severity,
category: alert.metadata.link,
status: get(alert, 'metadata.severity', get(alert, 'severity', 0)),
category: get(alert, 'metadata.link', get(alert, 'type', null)),
}));

const injector = chrome.dangerouslyGetActiveInjector();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { kfetch } from 'ui/kfetch';
import { AlertsStatus, AlertsStatusProps } from './status';
import { ALERT_TYPE_PREFIX } from '../../../common/constants';
import { ALERT_TYPES } from '../../../common/constants';
import { getSetupModeState } from '../../lib/setup_mode';
import { mockUseEffects } from '../../jest.helpers';

Expand Down Expand Up @@ -63,11 +63,7 @@ describe('Status', () => {

it('should render a success message if all alerts have been migrated and in setup mode', async () => {
(kfetch as jest.Mock).mockReturnValue({
data: [
{
alertTypeId: ALERT_TYPE_PREFIX,
},
],
data: ALERT_TYPES.map(type => ({ alertTypeId: type })),
});

(getSetupModeState as jest.Mock).mockReturnValue({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export const AlertsStatus: React.FC<AlertsStatusProps> = (props: AlertsStatusPro
);
}

const allMigrated = kibanaAlerts.length === NUMBER_OF_MIGRATED_ALERTS;
const allMigrated = kibanaAlerts.length >= NUMBER_OF_MIGRATED_ALERTS;
if (allMigrated) {
if (setupModeEnabled) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@

import React, { Fragment } from 'react';
import moment from 'moment-timezone';
import chrome from '../../../np_imports/ui/chrome';
import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert';
import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity';
import { formatTimestampToDuration } from '../../../../common/format_timestamp_to_duration';
import {
CALCULATE_DURATION_SINCE,
KIBANA_ALERTING_ENABLED,
ALERT_TYPE_LICENSE_EXPIRATION,
CALCULATE_DURATION_UNTIL,
} from '../../../../common/constants';
import { formatDateTimeLocal } from '../../../../common/formatting';
Expand All @@ -31,6 +29,37 @@ import {
EuiLink,
} from '@elastic/eui';

function replaceTokens(alert) {
if (!alert.message.tokens) {
return alert.message.text;
}

let text = alert.message.text;

for (const token of alert.message.tokens) {
if (token.type === 'time') {
text = text.replace(
token.startToken,
token.isRelative
? formatTimestampToDuration(alert.expirationTime, CALCULATE_DURATION_UNTIL)
: moment.tz(alert.expirationTime, moment.tz.guess()).format('LLL z')
);
} else if (token.type === 'link') {
const linkPart = new RegExp(`${token.startToken}(.+?)${token.endToken}`).exec(text);
// TODO: we assume this is at the end, which works for now but will not always work
const nonLinkText = text.replace(linkPart[0], '');
text = (
<Fragment>
{nonLinkText}
<EuiLink href={`#${token.url}`}>{linkPart[1]}</EuiLink>
</Fragment>
);
}
}

return text;
}

export function AlertsPanel({ alerts, changeUrl }) {
const goToAlerts = () => changeUrl('/alerts');

Expand Down Expand Up @@ -58,9 +87,6 @@ export function AlertsPanel({ alerts, changeUrl }) {
severityIcon.iconType = 'check';
}

const injector = chrome.dangerouslyGetActiveInjector();
const timezone = injector.get('config').get('dateFormat:tz');

return (
<EuiCallOut
key={`alert-item-${index}`}
Expand All @@ -83,7 +109,7 @@ export function AlertsPanel({ alerts, changeUrl }) {
id="xpack.monitoring.cluster.overview.alertsPanel.lastCheckedTimeText"
defaultMessage="Last checked {updateDateTime} (triggered {duration} ago)"
values={{
updateDateTime: formatDateTimeLocal(item.update_timestamp, timezone),
updateDateTime: formatDateTimeLocal(item.update_timestamp),
duration: formatTimestampToDuration(item.timestamp, CALCULATE_DURATION_SINCE),
}}
/>
Expand All @@ -96,14 +122,7 @@ export function AlertsPanel({ alerts, changeUrl }) {
const alertsList = KIBANA_ALERTING_ENABLED
? alerts.map((alert, idx) => {
const callOutProps = mapSeverity(alert.severity);
let message = alert.message
// scan message prefix and replace relative times
// \w: Matches any alphanumeric character from the basic Latin alphabet, including the underscore. Equivalent to [A-Za-z0-9_].
.replace(
'#relative',
formatTimestampToDuration(alert.expirationTime, CALCULATE_DURATION_UNTIL)
)
.replace('#absolute', moment.tz(alert.expirationTime, moment.tz.guess()).format('LLL z'));
const message = replaceTokens(alert);

if (!alert.isFiring) {
callOutProps.title = i18n.translate(
Expand All @@ -118,22 +137,30 @@ export function AlertsPanel({ alerts, changeUrl }) {
);
callOutProps.color = 'success';
callOutProps.iconType = 'check';
} else {
if (alert.type === ALERT_TYPE_LICENSE_EXPIRATION) {
message = (
<Fragment>
{message}
&nbsp;
<EuiLink href="#license">Please update your license</EuiLink>
</Fragment>
);
}
}

return (
<EuiCallOut key={idx} {...callOutProps}>
<p>{message}</p>
</EuiCallOut>
<Fragment key={idx}>
<EuiCallOut {...callOutProps}>
<p>{message}</p>
<EuiText size="xs">
<p data-test-subj="alertMeta" className="monCallout--meta">
<FormattedMessage
id="xpack.monitoring.cluster.overview.alertsPanel.lastCheckedTimeText"
defaultMessage="Last checked {updateDateTime} (triggered {duration} ago)"
values={{
updateDateTime: formatDateTimeLocal(alert.lastCheckedMS),
duration: formatTimestampToDuration(
alert.triggeredMS,
CALCULATE_DURATION_SINCE
),
}}
/>
</p>
</EuiText>
</EuiCallOut>
<EuiSpacer />
</Fragment>
);
})
: alerts.map((item, index) => (
Expand Down
30 changes: 21 additions & 9 deletions x-pack/legacy/plugins/monitoring/public/views/alerts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,37 @@ import { Alerts } from '../../components/alerts';
import { MonitoringViewBaseEuiTableController } from '../base_eui_table_controller';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer, EuiLink } from '@elastic/eui';
import { CODE_PATH_ALERTS } from '../../../common/constants';
import { CODE_PATH_ALERTS, KIBANA_ALERTING_ENABLED } from '../../../common/constants';

function getPageData($injector) {
const globalState = $injector.get('globalState');
const $http = $injector.get('$http');
const Private = $injector.get('Private');
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/legacy_alerts`;
const url = KIBANA_ALERTING_ENABLED
? `../api/monitoring/v1/alert_status`
: `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/legacy_alerts`;

const timeBounds = timefilter.getBounds();
const data = {
timeRange: {
min: timeBounds.min.toISOString(),
max: timeBounds.max.toISOString(),
},
};

if (!KIBANA_ALERTING_ENABLED) {
data.ccs = globalState.ccs;
}

return $http
.post(url, {
ccs: globalState.ccs,
timeRange: {
min: timeBounds.min.toISOString(),
max: timeBounds.max.toISOString(),
},
.post(url, data)
.then(response => {
const result = get(response, 'data', []);
if (KIBANA_ALERTING_ENABLED) {
return result.alerts;
}
return result;
})
.then(response => get(response, 'data', []))
.catch(err => {
const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider);
return ajaxErrorHandlers(err);
Expand Down
Loading

0 comments on commit 1da77f8

Please sign in to comment.