Add description and documentation link in alert flyout (#81526)

* Add description and documentation URL in alert flyout

* Add unit tests

* Fix type check

* Add horizontal rule

* Design fixes

* Fix uptime alert link

* Fix uptime urls

* Add anchor tag

* Fix jest test failures

* Fix monitoring links
This commit is contained in:
Mike Côté 2020-11-05 19:50:50 -05:00 committed by GitHub
parent f3599fec4c
commit 1ecd12cdf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 127 additions and 2 deletions

View file

@ -22,6 +22,7 @@ export function getAlertType(): AlertTypeModel {
name: 'Always Fires', name: 'Always Fires',
description: 'Alert when called', description: 'Alert when called',
iconClass: 'bolt', iconClass: 'bolt',
documentationUrl: null,
alertParamsExpression: AlwaysFiringExpression, alertParamsExpression: AlwaysFiringExpression,
validate: (alertParams: AlwaysFiringParamsProps['alertParams']) => { validate: (alertParams: AlwaysFiringParamsProps['alertParams']) => {
const { instances } = alertParams; const { instances } = alertParams;

View file

@ -47,6 +47,7 @@ export function getAlertType(): AlertTypeModel {
name: 'People Are In Space Right Now', name: 'People Are In Space Right Now',
description: 'Alert when people are in space right now', description: 'Alert when people are in space right now',
iconClass: 'globe', iconClass: 'globe',
documentationUrl: null,
alertParamsExpression: PeopleinSpaceExpression, alertParamsExpression: PeopleinSpaceExpression,
validate: (alertParams: PeopleinSpaceParamsProps['alertParams']) => { validate: (alertParams: PeopleinSpaceParamsProps['alertParams']) => {
const { outerSpaceCapacity, craft, op } = alertParams; const { outerSpaceCapacity, craft, op } = alertParams;

View file

@ -22,6 +22,9 @@ export function registerApmAlerts(
'Alert when the number of errors in a service exceeds a defined threshold.', 'Alert when the number of errors in a service exceeds a defined threshold.',
}), }),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/apm-alerts.html`;
},
alertParamsExpression: lazy(() => import('./ErrorCountAlertTrigger')), alertParamsExpression: lazy(() => import('./ErrorCountAlertTrigger')),
validate: () => ({ validate: () => ({
errors: [], errors: [],
@ -53,6 +56,9 @@ export function registerApmAlerts(
} }
), ),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/apm-alerts.html`;
},
alertParamsExpression: lazy( alertParamsExpression: lazy(
() => import('./TransactionDurationAlertTrigger') () => import('./TransactionDurationAlertTrigger')
), ),
@ -87,6 +93,9 @@ export function registerApmAlerts(
} }
), ),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/apm-alerts.html`;
},
alertParamsExpression: lazy( alertParamsExpression: lazy(
() => import('./TransactionErrorRateAlertTrigger') () => import('./TransactionErrorRateAlertTrigger')
), ),
@ -121,6 +130,9 @@ export function registerApmAlerts(
} }
), ),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/apm-alerts.html`;
},
alertParamsExpression: lazy( alertParamsExpression: lazy(
() => import('./TransactionDurationAnomalyAlertTrigger') () => import('./TransactionDurationAnomalyAlertTrigger')
), ),

View file

@ -21,6 +21,9 @@ export function createInventoryMetricAlertType(): AlertTypeModel {
defaultMessage: 'Alert when the inventory exceeds a defined threshold.', defaultMessage: 'Alert when the inventory exceeds a defined threshold.',
}), }),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/infrastructure-threshold-alert.html`;
},
alertParamsExpression: React.lazy(() => import('./components/expression')), alertParamsExpression: React.lazy(() => import('./components/expression')),
validate: validateMetricThreshold, validate: validateMetricThreshold,
defaultActionMessage: i18n.translate( defaultActionMessage: i18n.translate(

View file

@ -19,6 +19,9 @@ export function getAlertType(): AlertTypeModel {
defaultMessage: 'Alert when the log aggregation exceeds the threshold.', defaultMessage: 'Alert when the log aggregation exceeds the threshold.',
}), }),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/logs-threshold-alert.html`;
},
alertParamsExpression: React.lazy(() => import('./components/expression_editor/editor')), alertParamsExpression: React.lazy(() => import('./components/expression_editor/editor')),
validate: validateExpression, validate: validateExpression,
defaultActionMessage: i18n.translate( defaultActionMessage: i18n.translate(

View file

@ -21,6 +21,9 @@ export function createMetricThresholdAlertType(): AlertTypeModel {
defaultMessage: 'Alert when the metrics aggregation exceeds the threshold.', defaultMessage: 'Alert when the metrics aggregation exceeds the threshold.',
}), }),
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/metrics-threshold-alert.html`;
},
alertParamsExpression: React.lazy(() => import('./components/expression')), alertParamsExpression: React.lazy(() => import('./components/expression')),
validate: validateMetricThreshold, validate: validateMetricThreshold,
defaultActionMessage: i18n.translate( defaultActionMessage: i18n.translate(

View file

@ -16,6 +16,9 @@ export function createCpuUsageAlertType(): AlertTypeModel {
name: ALERT_DETAILS[ALERT_CPU_USAGE].label, name: ALERT_DETAILS[ALERT_CPU_USAGE].label,
description: ALERT_DETAILS[ALERT_CPU_USAGE].description, description: ALERT_DETAILS[ALERT_CPU_USAGE].description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html#kibana-alerts-cpu-threshold`;
},
alertParamsExpression: (props: Props) => ( alertParamsExpression: (props: Props) => (
<Expression {...props} paramDetails={ALERT_DETAILS[ALERT_CPU_USAGE].paramDetails} /> <Expression {...props} paramDetails={ALERT_DETAILS[ALERT_CPU_USAGE].paramDetails} />
), ),

View file

@ -18,6 +18,9 @@ export function createDiskUsageAlertType(): AlertTypeModel {
name: ALERT_DETAILS[ALERT_DISK_USAGE].label, name: ALERT_DETAILS[ALERT_DISK_USAGE].label,
description: ALERT_DETAILS[ALERT_DISK_USAGE].description, description: ALERT_DETAILS[ALERT_DISK_USAGE].description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html#kibana-alerts-disk-usage-threshold`;
},
alertParamsExpression: (props: Props) => ( alertParamsExpression: (props: Props) => (
<Expression {...props} paramDetails={ALERT_DETAILS[ALERT_DISK_USAGE].paramDetails} /> <Expression {...props} paramDetails={ALERT_DETAILS[ALERT_DISK_USAGE].paramDetails} />
), ),

View file

@ -18,6 +18,9 @@ export function createLegacyAlertTypes(): AlertTypeModel[] {
name: LEGACY_ALERT_DETAILS[legacyAlert].label, name: LEGACY_ALERT_DETAILS[legacyAlert].label,
description: LEGACY_ALERT_DETAILS[legacyAlert].description, description: LEGACY_ALERT_DETAILS[legacyAlert].description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/cluster-alerts.html`;
},
alertParamsExpression: () => ( alertParamsExpression: () => (
<Fragment> <Fragment>
<EuiSpacer /> <EuiSpacer />

View file

@ -18,6 +18,9 @@ export function createMemoryUsageAlertType(): AlertTypeModel {
name: ALERT_DETAILS[ALERT_MEMORY_USAGE].label, name: ALERT_DETAILS[ALERT_MEMORY_USAGE].label,
description: ALERT_DETAILS[ALERT_MEMORY_USAGE].description, description: ALERT_DETAILS[ALERT_MEMORY_USAGE].description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html#kibana-alerts-jvm-memory-threshold`;
},
alertParamsExpression: (props: Props) => ( alertParamsExpression: (props: Props) => (
<Expression {...props} paramDetails={ALERT_DETAILS[ALERT_MEMORY_USAGE].paramDetails} /> <Expression {...props} paramDetails={ALERT_DETAILS[ALERT_MEMORY_USAGE].paramDetails} />
), ),

View file

@ -16,6 +16,9 @@ export function createMissingMonitoringDataAlertType(): AlertTypeModel {
name: ALERT_DETAILS[ALERT_MISSING_MONITORING_DATA].label, name: ALERT_DETAILS[ALERT_MISSING_MONITORING_DATA].label,
description: ALERT_DETAILS[ALERT_MISSING_MONITORING_DATA].description, description: ALERT_DETAILS[ALERT_MISSING_MONITORING_DATA].description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html#kibana-alerts-missing-monitoring-data`;
},
alertParamsExpression: (props: any) => ( alertParamsExpression: (props: any) => (
<Expression <Expression
{...props} {...props}

View file

@ -31,6 +31,9 @@ export function createThreadPoolRejectionsAlertType(
name: threadPoolAlertDetails.label, name: threadPoolAlertDetails.label,
description: threadPoolAlertDetails.description, description: threadPoolAlertDetails.description,
iconClass: 'bell', iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html`;
},
alertParamsExpression: (props: Props) => ( alertParamsExpression: (props: Props) => (
<> <>
<EuiSpacer /> <EuiSpacer />

View file

@ -20,6 +20,8 @@ export function getAlertType(): AlertTypeModel<GeoThresholdAlertParams, AlertsCo
defaultMessage: 'Alert when an entity enters or leaves a geo boundary.', defaultMessage: 'Alert when an entity enters or leaves a geo boundary.',
}), }),
iconClass: 'globe', iconClass: 'globe',
// TODO: Add documentation for geo threshold alert
documentationUrl: null,
alertParamsExpression: lazy(() => import('./query_builder')), alertParamsExpression: lazy(() => import('./query_builder')),
validate: validateExpression, validate: validateExpression,
requiresAppContext: false, requiresAppContext: false,

View file

@ -281,7 +281,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent<AlertTyp
<EuiSpacer /> <EuiSpacer />
</Fragment> </Fragment>
) : null} ) : null}
<EuiSpacer size="l" />
<EuiTitle size="xs"> <EuiTitle size="xs">
<h5> <h5>
<FormattedMessage <FormattedMessage

View file

@ -21,6 +21,9 @@ export function getAlertType(): AlertTypeModel<IndexThresholdAlertParams, Alerts
defaultMessage: 'Alert when an aggregated query meets the threshold.', defaultMessage: 'Alert when an aggregated query meets the threshold.',
}), }),
iconClass: 'alert', iconClass: 'alert',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/alert-types.html#alert-type-index-threshold`;
},
alertParamsExpression: lazy(() => import('./expression')), alertParamsExpression: lazy(() => import('./expression')),
validate: validateExpression, validate: validateExpression,
requiresAppContext: false, requiresAppContext: false,

View file

@ -99,6 +99,7 @@ describe('alert_add', () => {
iconClass: 'test', iconClass: 'test',
name: 'test-alert', name: 'test-alert',
description: 'test', description: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },

View file

@ -52,6 +52,7 @@ describe('alert_edit', () => {
iconClass: 'test', iconClass: 'test',
name: 'test-alert', name: 'test-alert',
description: 'test', description: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },

View file

@ -31,7 +31,8 @@ describe('alert_form', () => {
id: 'my-alert-type', id: 'my-alert-type',
iconClass: 'test', iconClass: 'test',
name: 'test-alert', name: 'test-alert',
description: 'test', description: 'Alert when testing',
documentationUrl: 'https://localhost.local/docs',
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },
@ -59,6 +60,7 @@ describe('alert_form', () => {
iconClass: 'test', iconClass: 'test',
name: 'non edit alert', name: 'non edit alert',
description: 'test', description: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },
@ -182,6 +184,22 @@ describe('alert_form', () => {
); );
expect(alertTypeSelectOptions.exists()).toBeFalsy(); expect(alertTypeSelectOptions.exists()).toBeFalsy();
}); });
it('renders alert type description', async () => {
await setup();
wrapper.find('[data-test-subj="my-alert-type-SelectOption"]').first().simulate('click');
const alertDescription = wrapper.find('[data-test-subj="alertDescription"]');
expect(alertDescription.exists()).toBeTruthy();
expect(alertDescription.first().text()).toContain('Alert when testing');
});
it('renders alert type documentation link', async () => {
await setup();
wrapper.find('[data-test-subj="my-alert-type-SelectOption"]').first().simulate('click');
const alertDocumentationLink = wrapper.find('[data-test-subj="alertDocumentationLink"]');
expect(alertDocumentationLink.exists()).toBeTruthy();
expect(alertDocumentationLink.first().prop('href')).toBe('https://localhost.local/docs');
});
}); });
describe('alert_form create alert non alerting consumer and producer', () => { describe('alert_form create alert non alerting consumer and producer', () => {
@ -244,6 +262,7 @@ describe('alert_form', () => {
iconClass: 'test', iconClass: 'test',
name: 'test-alert', name: 'test-alert',
description: 'test', description: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },
@ -255,6 +274,7 @@ describe('alert_form', () => {
iconClass: 'test', iconClass: 'test',
name: 'test-alert', name: 'test-alert',
description: 'test', description: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },
@ -423,5 +443,19 @@ describe('alert_form', () => {
const throttleFieldAfterUpdate = wrapper.find('[data-test-subj="throttleInput"]'); const throttleFieldAfterUpdate = wrapper.find('[data-test-subj="throttleInput"]');
expect(throttleFieldAfterUpdate.at(1).prop('value')).toEqual(newThrottle); expect(throttleFieldAfterUpdate.at(1).prop('value')).toEqual(newThrottle);
}); });
it('renders alert type description', async () => {
await setup();
const alertDescription = wrapper.find('[data-test-subj="alertDescription"]');
expect(alertDescription.exists()).toBeTruthy();
expect(alertDescription.first().text()).toContain('Alert when testing');
});
it('renders alert type documentation link', async () => {
await setup();
const alertDocumentationLink = wrapper.find('[data-test-subj="alertDocumentationLink"]');
expect(alertDocumentationLink.exists()).toBeTruthy();
expect(alertDocumentationLink.first().prop('href')).toBe('https://localhost.local/docs');
});
}); });
}); });

View file

@ -25,6 +25,8 @@ import {
EuiHorizontalRule, EuiHorizontalRule,
EuiLoadingSpinner, EuiLoadingSpinner,
EuiEmptyPrompt, EuiEmptyPrompt,
EuiLink,
EuiText,
} from '@elastic/eui'; } from '@elastic/eui';
import { some, filter, map, fold } from 'fp-ts/lib/Option'; import { some, filter, map, fold } from 'fp-ts/lib/Option';
import { pipe } from 'fp-ts/lib/pipeable'; import { pipe } from 'fp-ts/lib/pipeable';
@ -247,6 +249,33 @@ export const AlertForm = ({
</EuiFlexItem> </EuiFlexItem>
) : null} ) : null}
</EuiFlexGroup> </EuiFlexGroup>
{alertTypeModel?.description && (
<EuiFlexGroup>
<EuiFlexItem>
<EuiText color="subdued" size="s" data-test-subj="alertDescription">
{alertTypeModel.description}&nbsp;
{alertTypeModel?.documentationUrl && (
<EuiLink
external
target="_blank"
data-test-subj="alertDocumentationLink"
href={
typeof alertTypeModel.documentationUrl === 'function'
? alertTypeModel.documentationUrl(docLinks)
: alertTypeModel.documentationUrl
}
>
<FormattedMessage
id="xpack.triggersActionsUI.sections.alertForm.documentationLabel"
defaultMessage="Documentation"
/>
</EuiLink>
)}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
)}
<EuiHorizontalRule />
{AlertParamsExpressionComponent ? ( {AlertParamsExpressionComponent ? (
<Suspense fallback={<CenterJustifiedSpinner />}> <Suspense fallback={<CenterJustifiedSpinner />}>
<AlertParamsExpressionComponent <AlertParamsExpressionComponent

View file

@ -44,6 +44,7 @@ const alertType = {
name: 'some alert type', name: 'some alert type',
description: 'test', description: 'test',
iconClass: 'test', iconClass: 'test',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },

View file

@ -17,6 +17,7 @@ const getTestAlertType = (id?: string, name?: string, iconClass?: string) => {
name: name || 'Test alert type', name: name || 'Test alert type',
description: 'Test description', description: 'Test description',
iconClass: iconClass || 'icon', iconClass: iconClass || 'icon',
documentationUrl: null,
validate: (): ValidationResult => { validate: (): ValidationResult => {
return { errors: {} }; return { errors: {} };
}, },

View file

@ -176,6 +176,7 @@ export interface AlertTypeModel<AlertParamsType = any, AlertsContextValue = any>
name: string | JSX.Element; name: string | JSX.Element;
description: string; description: string;
iconClass: string; iconClass: string;
documentationUrl: string | ((docLinks: DocLinksStart) => string) | null;
validate: (alertParams: AlertParamsType) => ValidationResult; validate: (alertParams: AlertParamsType) => ValidationResult;
alertParamsExpression: alertParamsExpression:
| React.FunctionComponent<any> | React.FunctionComponent<any>

View file

@ -204,6 +204,7 @@ describe('monitor status alert type', () => {
"alertParamsExpression": [Function], "alertParamsExpression": [Function],
"defaultActionMessage": "Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}", "defaultActionMessage": "Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}",
"description": "Alert when a monitor is down or an availability threshold is breached.", "description": "Alert when a monitor is down or an availability threshold is breached.",
"documentationUrl": [Function],
"iconClass": "uptimeApp", "iconClass": "uptimeApp",
"id": "xpack.uptime.alerts.monitorStatus", "id": "xpack.uptime.alerts.monitorStatus",
"name": <FormattedMessage "name": <FormattedMessage

View file

@ -19,6 +19,9 @@ export const initDurationAnomalyAlertType: AlertTypeInitializer = ({
}): AlertTypeModel => ({ }): AlertTypeModel => ({
id: CLIENT_ALERT_TYPES.DURATION_ANOMALY, id: CLIENT_ALERT_TYPES.DURATION_ANOMALY,
iconClass: 'uptimeApp', iconClass: 'uptimeApp',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html`;
},
alertParamsExpression: (params: unknown) => ( alertParamsExpression: (params: unknown) => (
<DurationAnomalyAlert core={core} plugins={plugins} params={params} /> <DurationAnomalyAlert core={core} plugins={plugins} params={params} />
), ),

View file

@ -31,6 +31,9 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({
), ),
description, description,
iconClass: 'uptimeApp', iconClass: 'uptimeApp',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html#_monitor_status_alerts`;
},
alertParamsExpression: (params: any) => ( alertParamsExpression: (params: any) => (
<MonitorStatusAlert core={core} plugins={plugins} params={params} /> <MonitorStatusAlert core={core} plugins={plugins} params={params} />
), ),

View file

@ -15,6 +15,9 @@ const TLSAlert = React.lazy(() => import('./lazy_wrapper/tls_alert'));
export const initTlsAlertType: AlertTypeInitializer = ({ core, plugins }): AlertTypeModel => ({ export const initTlsAlertType: AlertTypeInitializer = ({ core, plugins }): AlertTypeModel => ({
id: CLIENT_ALERT_TYPES.TLS, id: CLIENT_ALERT_TYPES.TLS,
iconClass: 'uptimeApp', iconClass: 'uptimeApp',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html#_tls_alerts`;
},
alertParamsExpression: (params: any) => ( alertParamsExpression: (params: any) => (
<TLSAlert core={core} plugins={plugins} params={params} /> <TLSAlert core={core} plugins={plugins} params={params} />
), ),

View file

@ -31,6 +31,7 @@ export class AlertingFixturePlugin implements Plugin<Setup, Start, AlertingExamp
name: 'Test Always Firing', name: 'Test Always Firing',
description: 'Always fires', description: 'Always fires',
iconClass: 'alert', iconClass: 'alert',
documentationUrl: null,
alertParamsExpression: () => React.createElement('div', null, 'Test Always Firing'), alertParamsExpression: () => React.createElement('div', null, 'Test Always Firing'),
validate: () => { validate: () => {
return { errors: {} }; return { errors: {} };
@ -43,6 +44,7 @@ export class AlertingFixturePlugin implements Plugin<Setup, Start, AlertingExamp
name: 'Test Noop', name: 'Test Noop',
description: `Doesn't do anything`, description: `Doesn't do anything`,
iconClass: 'alert', iconClass: 'alert',
documentationUrl: null,
alertParamsExpression: () => React.createElement('div', null, 'Test Noop'), alertParamsExpression: () => React.createElement('div', null, 'Test Noop'),
validate: () => { validate: () => {
return { errors: {} }; return { errors: {} };