Skip to content

Commit

Permalink
[Alerts] Create UI for alerting tabs navigation elastic#47754
Browse files Browse the repository at this point in the history
  • Loading branch information
YulNaumenko committed Oct 10, 2019
1 parent ac28c98 commit 001a3e8
Show file tree
Hide file tree
Showing 16 changed files with 509 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Component } from 'react';
import { some } from 'fp-ts/lib/Option';
import PropTypes from 'prop-types';
import { HashRouter, Switch, Route, Redirect } from 'react-router-dom';

import { ActionsList } from './sections/actions_list/components/actions_list';
import { Switch, Route, Redirect } from 'react-router-dom';
import { registerRouter } from './lib/navigation';
import { BASE_PATH } from './constants';
import { BASE_PATH, Section } from './constants';
import { AlertsUIHome } from './home';

class ShareRouter extends Component {
static contextTypes = {
Expand Down Expand Up @@ -38,18 +36,20 @@ class ShareRouter extends Component {
}

export const App = (api: any) => {
const sections: Section[] = ['alerts', 'actions', 'notifications', 'activity_logs'];

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

return (
<HashRouter>
<ShareRouter>
<AppWithoutRouter api={api} />
</ShareRouter>
</HashRouter>
<ShareRouter>
<AppWithoutRouter sectionsRegex={sectionsRegex} />
</ShareRouter>
);
};

export const AppWithoutRouter = ({ api }: any) => (
export const AppWithoutRouter = ({ sectionsRegex }: any) => (
<Switch>
<Route exact path={`${BASE_PATH}actions`} render={() => <ActionsList api={some(api)} />} />
<Redirect from={BASE_PATH} to={`${BASE_PATH}actions`} />
<Route exact path={`${BASE_PATH}/:section(${sectionsRegex})`} component={AlertsUIHome} />
<Redirect from={`${BASE_PATH}`} to={`${BASE_PATH}/alerts`} />
</Switch>
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,28 @@
* you may not use this file except in compliance with the Elastic License.
*/

export const BASE_PATH = '/management/kibana/alerting/';
export const BASE_PATH = '/management/kibana/alerting';
export const BASE_API_PATH = '../api/action';

export const DEFAULT_SECTION: Section = 'alerts';
export type Section = 'actions' | 'alerts' | 'activity_logs' | 'notifications';

export function linkToHome() {
return `#${BASE_PATH}`;
}

export function linkToAlerts() {
return `#${BASE_PATH}/alerts`;
}

export function linkToActions() {
return `#${BASE_PATH}/actions`;
}

export function linkToActivityLogs() {
return `#${BASE_PATH}/activity_logs`;
}

export function linkToNotifications() {
return `#${BASE_PATH}/notifications`;
}
112 changes: 112 additions & 0 deletions x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* 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, { useEffect } from 'react';
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui';
import { BASE_PATH, Section } from '../../../np_ready/public/application/constants';
import { useAppDependencies } from './index';
import { breadcrumbService } from './lib/breadcrumb';
import { docTitleService } from './lib/doc_title';

import { ActionsList } from './sections/actions_list/components/actions_list';
import { AlertsList } from './sections/alerts_list/components/alerts_list';

interface MatchParams {
section: Section;
}

export const AlertsUIHome: React.FunctionComponent<RouteComponentProps<MatchParams>> = ({
match: {
params: { section },
},
history,
}) => {
const {
core: { chrome },
} = useAppDependencies();

const notificationsUiEnabled = chrome.getIsVisible$();

const tabs: Array<{
id: Section;
name: React.ReactNode;
}> = [
{
id: 'alerts',
name: (
<FormattedMessage id="xpack.alertingUI.home.snapshotsTabTitle" defaultMessage="Alerts" />
),
},
{
id: 'actions',
name: (
<FormattedMessage
id="xpack.alertingUI.home.repositoriesTabTitle"
defaultMessage="Actions"
/>
),
},
{
id: 'activity_logs',
name: (
<FormattedMessage
id="xpack.alertingUI.home.restoreTabTitle"
defaultMessage="Activity Log"
/>
),
},
];

// Just example of Enable/Disable some UI tabs
if (notificationsUiEnabled) {
tabs.splice(2, 0, {
id: 'notifications',
name: (
<FormattedMessage id="xpack.alertingUI.home.policiesTabTitle" defaultMessage="Policies" />
),
});
}

const onSectionChange = (newSection: Section) => {
history.push(`${BASE_PATH}/${newSection}`);
};

// Set breadcrumb and page title
useEffect(() => {
breadcrumbService.setBreadcrumbs(section || 'home');
docTitleService.setTitle(section || 'home');
}, [section]);

return (
<EuiPageBody>
<EuiPageContent>
<EuiTabs>
{tabs.map(tab => (
<EuiTab
onClick={() => onSectionChange(tab.id)}
isSelected={tab.id === section}
key={tab.id}
data-test-subj="tab"
>
{tab.name}
</EuiTab>
))}
</EuiTabs>

<EuiSpacer size="s" />

<Switch>
<Route exact path={`${BASE_PATH}/actions`} component={ActionsList} />
<Route exact path={`${BASE_PATH}/alerts`} component={AlertsList} />
<Route exact path={`${BASE_PATH}/notifications`} />
<Route exact path={`${BASE_PATH}/activitylog`} />
</Switch>
</EuiPageContent>
</EuiPageBody>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,62 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { createContext, useContext, ReactNode } from 'react';
import { HashRouter } from 'react-router-dom';
import { render } from 'react-dom';
import { I18nContext } from 'ui/i18n';
import { HttpServiceBase } from 'kibana/public';
import { CoreStart } from 'src/core/public';
import { App } from './app';

export const renderReact = async (element: any, http: HttpServiceBase) => {
render(
import { AppDependencies, AppPlugins } from '../../../public/shim';

export { BASE_PATH as CLIENT_BASE_PATH } from './constants';

/**
* App dependencies
*/
let DependenciesContext: React.Context<AppDependencies>;

export const setAppDependencies = (deps: AppDependencies) => {
DependenciesContext = createContext<AppDependencies>(deps);
return DependenciesContext.Provider;
};

export const useAppDependencies = () => {
if (!DependenciesContext) {
throw new Error(`The app dependencies Context hasn't been set.
Use the "setAppDependencies()" method when bootstrapping the app.`);
}
return useContext<AppDependencies>(DependenciesContext);
};

const getAppProviders = (deps: AppDependencies) => {
const {
i18n: { Context: I18nContext },
} = deps.core;

// Create App dependencies context and get its provider
const AppDependenciesProvider = setAppDependencies(deps);

return ({ children }: { children: ReactNode }) => (
<I18nContext>
<App api={{ http }} />
</I18nContext>,
element
<HashRouter>
<AppDependenciesProvider value={deps}>{children}</AppDependenciesProvider>
</HashRouter>
</I18nContext>
);
};

export const renderReact = async (
elem: HTMLElement | null,
core: CoreStart,
plugins: AppPlugins
) => {
const Providers = getAppProviders({ core, plugins });

render(
<Providers>
<App />
</Providers>,
elem
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Option, fromNullable } from 'fp-ts/lib/Option';
import { Option } from 'fp-ts/lib/Option';
import { HttpServiceBase } from 'kibana/public';
import { useRequestNp } from '../../../../public/shared_imports';
import { BASE_API_PATH } from '../constants';

import { ActionType } from '../../../../../actions/server/types';
import { Result, asOk, asErr } from './result_type';

export interface RequestData<T> {
isLoading: boolean;
Expand Down Expand Up @@ -51,15 +50,6 @@ export function hasReceivedAErrorCode(
return false;
}

function wrapInResult<T, E>(status: any): Result<RequestData<T>, E> {
return hasReceivedAErrorCode(status.error)
? asErr(status.error)
: asOk({
...status,
data: fromNullable(status.data),
});
}

export interface ActionTypesResponse extends ActionType {
id: string;
name: string;
Expand All @@ -72,23 +62,16 @@ export interface LoadActionTypese {
}

export interface ActionTypesApi {
loadActionTypes: (
pollIntervalMs: number
) => Result<RequestData<LoadActionTypesResponse>, LoadActionTypesErrorResponse>;
loadActionTypes: (pollIntervalMs: number) => RequestData<LoadActionTypesResponse>;
}

export function loadActionTypes(
http: HttpServiceBase,
pollIntervalMs?: number
): Result<RequestData<LoadActionTypesResponse>, LoadActionTypesErrorResponse> {
return wrapInResult<LoadActionTypesResponse, LoadActionTypesErrorResponse>(
useRequestNp(http, {
path: `${BASE_API_PATH}/types`,
method: 'get',
pollIntervalMs,
deserializer: (response: { data?: any[]; error?: any }) => {
return response;
},
})
);
export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) {
return useRequestNp(http, {
path: `${BASE_API_PATH}/types`,
method: 'get',
pollIntervalMs,
deserializer: (response: { data?: any[]; error?: any }) => {
return response;
},
});
}
Loading

0 comments on commit 001a3e8

Please sign in to comment.