Skip to content

Commit

Permalink
Create UI for alerting and actions plugin (elastic#48959)
Browse files Browse the repository at this point in the history
* Refactored reducers type definitions

* Fixed dependancy objects

* Fixed action add

* Fixed logging app icon

* Added action types params fields

* Added fields for check and re-notify alert

* Add tags to alert list

* Adjusted threshold expression with validation, added visualization

* Move delete button to the left and hide when no selection

* Rename action list title column to name

* fixed request

* Removed watcher labels

* Design cleanup

* Added expression default values

* Added visualization for index threshold alert

* Rename Actions tab to Connectors

* Rename "create action" to "create connector"

* Remove actions column name

* Add count per action type

* Hide checkboxes when user can't delete

* Add title to home, rename Alerting UI breadcrumb (remove UI part)

* Added correct binding for interval and throttle

* Added tags support for create Alert UI

* Added server error display in UI on save alert

* Added connectors for action forms

* Update button styles

* Switch inputs to compressed forms

* Fixed some fields for add alert form

* Fixed updating action by index

* Fixed filter for index/fields api requests

* Remove the test alert type that was in the init function

* Fixed action type icon on add connector form and did small refactoring on action forms; added action validation

* Rename alerting UI plugin to triggers and actions UI (or something else) elastic#50305

* Implemented action connector edit UI

* Add bulk actions to alerts list

* Update home title spacing

* Fixed editing secrets action property

* Changing behaviour of bulk actions and disable buttons during request

* Refactored plugin definition with appdependency interface

* Moved add dependencies to the separate file

* Enable visualization if only hasExpressionErrors passed

* Fixed add action twice on click card

* Fix actions column in alert list

* Fixed action canSave capability

* Renamed Actions to ActionConnectors in appropriate UI files

* Renamed alertTypeParams to params in UI code

* Add filter for tags

* Cleanup previous commit

* Fix alert type filter

* Refactored edit form to use ActionTableItem

* Renamed ActionTableItem to ActionConnectorTableItem

* Fixed missing button key error for alerts list filter

* Renamed translation labels for connectors

* Enable UI plugin by default

* Rename buildin to builtin

* Fix some type checks

* Add API tests

* Split API file into smaller files

* Rename plugin id

* Remove dependency on actions plugin (should be optional dep in NP)

* Fix some translation ids

* Revert "Rename plugin id"

This reverts commit f6daeb3.

* Rename method for loading connectors

* Added functional tests base

* Fix functional test type filter

* Add test alert type for now

* Initial connectors functional tests

* Rename description to name

* Use unique connector names to allow re-running tests

* Assert on more things

* Update alert/action menu items. Flyout width. Add index.scss file

* Added action connector list unit tests

* Add bulk delete functional test

* Move tests to SSL functional environment

* Fix tests

* Added unit tests for actionTypeRegistry and alertTypeRegistry

* Fixed update connector with only properties

* Added some functional tests for alerts with TODOs

* connectors list page cleanup

* empty state cleanup

* Added connector edit flyout unit test

* Fix functional tests

* text cleanup

* zindex fix for index threshold trigger

* Expand the functional tests, add assertions

* Fixed edit connector from the Name column, and removed pencil button

* Remove tags filter, use search bar instead

* Finalize functional tests

* Support filtering alerts by action type

* Rename plugin name for translations

* Rename default breadcrumb title to alerts and actions

* Added unit tests for connectors empty prompt, fixed api tests

* Added unit test for select action type menu for create connector; Fixed update selected connector for edit form

* Added unit test for edit connector flyout

* Added alerts list unit tests

* Added connector form unit tests

* Added connector reducer unit tests

* Fixed some failing unit tests

* Fixed alerts list unit tests

* Set alert tab default if it is available

* Added doc_title and get_time_units unit tests

* Added some test fixes

* Fixed index threshold expression to display only index and fields

* Added email building action unit tests

* Added unit tests for builtin action types

* Remove test alert type

* Move create alert UI behind feature flag 'createAlertUiEnabled'

* Fix functional tests

* Update codeowners

* Update codeowners for tests

* Revert watcher changes

* Fix type check failure

* Fix unit test failures

* Fixed typecheck failures

* Fixed language check errors

* Did some text/type fixes

* Fixed typecheck

* Fixed unit tests warning

* Fix failing functional tests

* Fix registry tests to have cleaner diff when it fails

* Make DEFAULT_SECTION a Section type

* Remove unused constructor

* Make app dependency error string same line

* Remove unused error pages

* Set interface to alerts context

* Fix action_connector_form.tsx label

* Fix label in connector_add_flyout.tsx

* Fix label in alert_add.tsx

* Move alert_types to builtin_alert_types

* Move some threshold constants into threshold folder

* Move api.ts within threshold folder

* Removed duplication logic from action type and alert type registry list

* Fixed email action type test and adjusted validation to support arrays ony

* Added missing connector fields for email action type

* Fixed building action types issues due to comments

* Refactored with more new platform structure; fixed some comments from review

* Capitalize Actions in 'Alerts and Actions' labels

* Skip flaky tests

* Fix failing functional test

* Fixed failing unit tests, added new deps

* Fixed type checks

* Fixed language check failing

* Fix broken functional tests

* Refactored actionConnectors and alerting context

* Removed doc title service

* added get time options type definitions

* removed obsolete code

* Made generic registry type for actionTypes and alert types

* Fixed some enum types

* fixed type check CI

* Convert EuiSearchBar to normal text field

* Fix typo

* Fix conditional rendering

* Fix bug where selection doesn't reset

* Fix broken functional test, wait for ENTER key to search alerts

* Make app section hide from menu when user doesn't have access

* Fixed connector name validation (error due to renaming from description)

* Removed obsolete useEffect

* Removed unused ShareRouter

* Fixed key validation error

* Mobed wrongly wrapped objects

* Removed useEffect from connectors form

* Replaced error forms with eui controls props

* Added delete confirmation dialog for connectors list

* Fixed build errors

* Fixed failing test

* Skip flaky tests

* Added null check for app context - render components tree only if it isn't null

* Fixed type check eror

* Did changes on the UX and text/labels commnets

* Fixed failing tests

* Fixed error handling

* Refactored Webhook form http headers due to the mockup

* Fixed build

* Fix labels issue

* Fix spacing and form row alignment

* Fixed failing type check

* put ownfocus on popover in actions list

* fix spacing and flex

* fix color on conectors list

* clean up webhook headers form

* fix logic check for headers

* Made changes due to review comments

* Fixed delete connector test

* Fixed all flaky test for delete connectors 53956

* Fixed type check due to NP changes

* Disable plugin by default

* Added configuration props for functional tests to enable triggers and actions ui

* removed timeout from test

* added enable triggers and actions to functional/config.js

* fix the build

* Changed ci group and disabled plugin

* changed config setting to root

* Changed disable approach

* Experiment with index managment

* Set back configuration settings for triggers and actions

* Enable plugins

* Set index management to disabled to see the failing issue

* Revert experimental back for index_managment

* Fixed type check

Co-authored-by: Mike Côté <[email protected]>
Co-authored-by: [email protected] <[email protected]>
Co-authored-by: DeFazio <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: Peter Schretlen <[email protected]>
  • Loading branch information
6 people authored and jkelastic committed Jan 17, 2020
1 parent 38f9d01 commit b049cb0
Show file tree
Hide file tree
Showing 111 changed files with 11,511 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@
/x-pack/test/alerting_api_integration @elastic/kibana-alerting-services
/x-pack/test/plugin_api_integration/plugins/task_manager @elastic/kibana-alerting-services
/x-pack/test/plugin_api_integration/test_suites/task_manager @elastic/kibana-alerting-services
/x-pack/legacy/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services
/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/kibana-alerting-services
/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services

# Design
**/*.scss @elastic/kibana-design
Expand Down
1 change: 1 addition & 0 deletions x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"xpack.actions": "legacy/plugins/actions",
"xpack.advancedUiActions": "plugins/advanced_ui_actions",
"xpack.alerting": "legacy/plugins/alerting",
"xpack.triggersActionsUI": "legacy/plugins/triggers_actions_ui",
"xpack.apm": "legacy/plugins/apm",
"xpack.beatsManagement": "legacy/plugins/beats_management",
"xpack.canvas": "legacy/plugins/canvas",
Expand Down
2 changes: 2 additions & 0 deletions x-pack/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { transform } from './legacy/plugins/transform';
import { actions } from './legacy/plugins/actions';
import { alerting } from './legacy/plugins/alerting';
import { lens } from './legacy/plugins/lens';
import { triggersActionsUI } from './legacy/plugins/triggers_actions_ui';

module.exports = function(kibana) {
return [
Expand Down Expand Up @@ -83,5 +84,6 @@ module.exports = function(kibana) {
snapshotRestore(kibana),
actions(kibana),
alerting(kibana),
triggersActionsUI(kibana),
];
};
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ beforeEach(() => {
describe('actionTypeRegistry.get() works', () => {
test('action type static data is as expected', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('email');
expect(actionType.name).toEqual('Email');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ export function getActionType(params: GetActionTypeParams): ActionType {
const { logger, configurationUtilities } = params;
return {
id: '.email',
name: 'email',
name: i18n.translate('xpack.actions.builtin.emailTitle', {
defaultMessage: 'Email',
}),
validate: {
config: schema.object(ConfigSchemaProps, {
validate: curry(validateConfig)(configurationUtilities),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ beforeEach(() => {
describe('actionTypeRegistry.get() works', () => {
test('action type static data is as expected', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('index');
expect(actionType.name).toEqual('Index');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ const ParamsSchema = schema.object({
export function getActionType({ logger }: { logger: Logger }): ActionType {
return {
id: '.index',
name: 'index',
name: i18n.translate('xpack.actions.builtin.esIndexTitle', {
defaultMessage: 'Index',
}),
validate: {
config: ConfigSchema,
params: ParamsSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ beforeAll(() => {
describe('get()', () => {
test('should return correct action type', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('pagerduty');
expect(actionType.name).toEqual('PagerDuty');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ export function getActionType({
}): ActionType {
return {
id: '.pagerduty',
name: 'pagerduty',
name: i18n.translate('xpack.actions.builtin.pagerdutyTitle', {
defaultMessage: 'PagerDuty',
}),
validate: {
config: schema.object(configSchemaProps, {
validate: curry(valdiateActionTypeConfig)(configurationUtilities),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ beforeAll(() => {
describe('get()', () => {
test('returns action type', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('server-log');
expect(actionType.name).toEqual('Server log');
});
});

Expand Down Expand Up @@ -98,6 +98,6 @@ describe('execute()', () => {
config: {},
secrets: {},
});
expect(mockedLogger.info).toHaveBeenCalledWith('server-log: message text here');
expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Logger } from '../../../../../../src/core/server';
import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types';
import { withoutControlCharacters } from './lib/string_utils';

const ACTION_NAME = 'server-log';
const ACTION_NAME = 'Server log';

// params definition

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ beforeAll(() => {
describe('action registeration', () => {
test('returns action type', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('slack');
expect(actionType.name).toEqual('Slack');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export function getActionType({
}): ActionType {
return {
id: '.slack',
name: 'slack',
name: i18n.translate('xpack.actions.builtin.slackTitle', {
defaultMessage: 'Slack',
}),
validate: {
secrets: schema.object(secretsSchemaProps, {
validate: curry(valdiateActionTypeConfig)(configurationUtilities),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ beforeAll(() => {
describe('actionType', () => {
test('exposes the action as `webhook` on its Id and Name', () => {
expect(actionType.id).toEqual('.webhook');
expect(actionType.name).toEqual('webhook');
expect(actionType.name).toEqual('Webhook');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export function getActionType({
}): ActionType {
return {
id: '.webhook',
name: 'webhook',
name: i18n.translate('xpack.actions.builtin.webhookTitle', {
defaultMessage: 'Webhook',
}),
validate: {
config: schema.object(configSchemaProps, {
validate: curry(valdiateActionTypeConfig)(configurationUtilities),
Expand Down
21 changes: 19 additions & 2 deletions x-pack/legacy/plugins/siem/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,16 @@ export class Plugin {
],
read: ['config'],
},
ui: ['show', 'crud'],
ui: [
'show',
'crud',
'alerting:show',
'actions:show',
'alerting:save',
'actions:save',
'alerting:delete',
'actions:delete',
],
},
read: {
api: ['siem', 'actions-read', 'actions-all', 'alerting-read', 'alerting-all'],
Expand All @@ -73,7 +82,15 @@ export class Plugin {
timelineSavedObjectType,
],
},
ui: ['show'],
ui: [
'show',
'alerting:show',
'actions:show',
'alerting:save',
'actions:save',
'alerting:delete',
'actions:delete',
],
},
},
});
Expand Down
43 changes: 43 additions & 0 deletions x-pack/legacy/plugins/triggers_actions_ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { Legacy } from 'kibana';
import { Root } from 'joi';
import { resolve } from 'path';

export function triggersActionsUI(kibana: any) {
return new kibana.Plugin({
id: 'triggers_actions_ui',
configPrefix: 'xpack.triggers_actions_ui',
isEnabled(config: Legacy.KibanaConfig) {
return (
config.get('xpack.triggers_actions_ui.enabled') &&
(config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled'))
);
},
publicDir: resolve(__dirname, 'public'),
require: ['kibana'],
config(Joi: Root) {
return Joi.object()
.keys({
enabled: Joi.boolean().default(false),
createAlertUiEnabled: Joi.boolean().default(false),
})
.default();
},
uiExports: {
home: ['plugins/triggers_actions_ui/hacks/register'],
managementSections: ['plugins/triggers_actions_ui/legacy'],
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
injectDefaultVars(server: Legacy.Server) {
const serverConfig = server.config();
return {
createAlertUiEnabled: serverConfig.get('xpack.triggers_actions_ui.createAlertUiEnabled'),
};
},
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "triggers_actions_ui",
"version": "kibana",
"server": false,
"ui": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { ActionTypeRegistryContract } from '../types';

const createActionTypeRegistryMock = () => {
const mocked: jest.Mocked<ActionTypeRegistryContract> = {
has: jest.fn(x => true),
register: jest.fn(),
get: jest.fn(),
list: jest.fn(),
};
return mocked;
};

export const actionTypeRegistryMock = {
create: createActionTypeRegistryMock,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { AlertTypeRegistryContract } from '../types';

const createAlertTypeRegistryMock = () => {
const mocked: jest.Mocked<AlertTypeRegistryContract> = {
has: jest.fn(),
register: jest.fn(),
get: jest.fn(),
list: jest.fn(),
};
return mocked;
};

export const alertTypeRegistryMock = {
create: createAlertTypeRegistryMock,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* 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 { Switch, Route, Redirect, HashRouter } from 'react-router-dom';
import {
ChromeStart,
DocLinksStart,
ToastsSetup,
HttpSetup,
IUiSettingsClient,
} from 'kibana/public';
import { BASE_PATH, Section } from './constants';
import { TriggersActionsUIHome } from './home';
import { AppContextProvider, useAppDependencies } from './app_context';
import { hasShowAlertsCapability } from './lib/capabilities';
import { LegacyDependencies, ActionTypeModel, AlertTypeModel } from '../types';
import { TypeRegistry } from './type_registry';

export interface AppDeps {
chrome: ChromeStart;
docLinks: DocLinksStart;
toastNotifications: ToastsSetup;
injectedMetadata: any;
http: HttpSetup;
uiSettings: IUiSettingsClient;
legacy: LegacyDependencies;
actionTypeRegistry: TypeRegistry<ActionTypeModel>;
alertTypeRegistry: TypeRegistry<AlertTypeModel>;
}

export const App = (appDeps: AppDeps) => {
const sections: Section[] = ['alerts', 'connectors'];

const sectionsRegex = sections.join('|');

return (
<HashRouter>
<AppContextProvider appDeps={appDeps}>
<AppWithoutRouter sectionsRegex={sectionsRegex} />
</AppContextProvider>
</HashRouter>
);
};

export const AppWithoutRouter = ({ sectionsRegex }: any) => {
const {
legacy: { capabilities },
} = useAppDependencies();
const canShowAlerts = hasShowAlertsCapability(capabilities.get());
const DEFAULT_SECTION: Section = canShowAlerts ? 'alerts' : 'connectors';
return (
<Switch>
<Route
exact
path={`${BASE_PATH}/:section(${sectionsRegex})`}
component={TriggersActionsUIHome}
/>
<Redirect from={`${BASE_PATH}`} to={`${BASE_PATH}/${DEFAULT_SECTION}`} />
</Switch>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* 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, { createContext, useContext } from 'react';
import { AppDeps } from './app';

const AppContext = createContext<AppDeps | null>(null);

export const AppContextProvider = ({
children,
appDeps,
}: {
appDeps: AppDeps | null;
children: React.ReactNode;
}) => {
return appDeps ? <AppContext.Provider value={appDeps}>{children}</AppContext.Provider> : null;
};

export const useAppDependencies = (): AppDeps => {
const ctx = useContext(AppContext);
if (!ctx) {
throw new Error(
'The app dependencies Context has not been set. Use the "setAppDependencies()" method when bootstrapping the app.'
);
}
return ctx;
};
Loading

0 comments on commit b049cb0

Please sign in to comment.