mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Follow up to #40830 and #41054 in preparation for single metric viewer migration. The previous PR introduced the navigation menu as a React component. This PR moves dependencies down from the angularjs wrapper directive directly to the React component so the component can also be used stand-alone without the angularjs wrapper. For simple angularjs based HTML templates this stand-alone usage is also part of this PR. Unfortunately the PR turned out to be quite big due to: Most page react components had to be wrapped in another <Fragment> to allow the addition of <NavigationMenu> thus leading to large diffs for the components. All component code inside the <Fragment> was not touched though.
This commit is contained in:
parent
feb77574db
commit
b6093548df
52 changed files with 1874 additions and 1738 deletions
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="access-denied"></ml-nav-menu>
|
||||
<ml-nav-menu name="access-denied" />
|
||||
<div class="col-md-12">
|
||||
<div class="euiSpacer euiSpacer--m"></div>
|
||||
<div class="euiCallOut euiCallOut--danger">
|
||||
|
|
|
@ -6,39 +6,40 @@
|
|||
|
||||
import React, { Fragment, FC } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
|
||||
// @ts-ignore
|
||||
import { isFullLicense } from '../../license/check_license';
|
||||
|
||||
import { TopNav } from './top_nav';
|
||||
import { Tabs } from './tabs';
|
||||
|
||||
const tabSupport = [
|
||||
'jobs',
|
||||
'settings',
|
||||
'data_frames',
|
||||
'datavisualizer',
|
||||
'filedatavisualizer',
|
||||
'timeseriesexplorer',
|
||||
'access-denied',
|
||||
'explorer',
|
||||
];
|
||||
|
||||
interface Props {
|
||||
dateFormat: string;
|
||||
disableLinks: boolean;
|
||||
forceRefresh: () => void;
|
||||
showTabs: boolean;
|
||||
tabId: string;
|
||||
timeHistory: any;
|
||||
timefilter: any;
|
||||
}
|
||||
|
||||
export const NavigationMenu: FC<Props> = ({
|
||||
dateFormat,
|
||||
disableLinks,
|
||||
forceRefresh,
|
||||
showTabs,
|
||||
tabId,
|
||||
timeHistory,
|
||||
timefilter,
|
||||
}) => (
|
||||
<Fragment>
|
||||
<EuiFlexGroup justifyContent="flexEnd" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<TopNav
|
||||
dateFormat={dateFormat}
|
||||
timeHistory={timeHistory}
|
||||
timefilter={timefilter}
|
||||
forceRefresh={forceRefresh}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{showTabs && <Tabs tabId={tabId} disableLinks={disableLinks} />}
|
||||
</Fragment>
|
||||
);
|
||||
export const NavigationMenu: FC<Props> = ({ tabId }) => {
|
||||
const disableLinks = isFullLicense() === false;
|
||||
const showTabs = tabSupport.includes(tabId);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFlexGroup justifyContent="flexEnd" gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>
|
||||
<TopNav />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{showTabs && <Tabs tabId={tabId} disableLinks={disableLinks} />}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,47 +7,28 @@
|
|||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { NavigationMenu } from './navigation_menu';
|
||||
import { isFullLicense } from '../../license/check_license';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
const module = uiModules.get('apps/ml');
|
||||
import { mlTimefilterRefresh$ } from '../../services/timefilter_refresh_service';
|
||||
|
||||
import 'ui/directives/kbn_href';
|
||||
import chrome from 'ui/chrome';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
import { NavigationMenuContext } from '../../util/context_utils';
|
||||
|
||||
module.directive('mlNavMenu', function (config) {
|
||||
import { NavigationMenu } from './navigation_menu';
|
||||
|
||||
module.directive('mlNavMenu', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
link: function (scope, element, attrs) {
|
||||
const { name } = attrs;
|
||||
let showTabs = false;
|
||||
|
||||
if (name === 'jobs' ||
|
||||
name === 'settings' ||
|
||||
name === 'data_frames' ||
|
||||
name === 'datavisualizer' ||
|
||||
name === 'filedatavisualizer' ||
|
||||
name === 'timeseriesexplorer' ||
|
||||
name === 'access-denied' ||
|
||||
name === 'explorer') {
|
||||
showTabs = true;
|
||||
}
|
||||
|
||||
const props = {
|
||||
dateFormat: config.get('dateFormat'),
|
||||
disableLinks: (isFullLicense() === false),
|
||||
showTabs,
|
||||
tabId: name,
|
||||
timeHistory,
|
||||
timefilter,
|
||||
forceRefresh: () => mlTimefilterRefresh$.next()
|
||||
};
|
||||
|
||||
ReactDOM.render(React.createElement(NavigationMenu, props),
|
||||
ReactDOM.render(
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<NavigationMenu tabId={attrs.name} />
|
||||
</NavigationMenuContext.Provider>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
|
|
|
@ -4,36 +4,37 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC, Fragment, useState, useEffect } from 'react';
|
||||
import React, { FC, Fragment, useContext, useState, useEffect } from 'react';
|
||||
import { EuiSuperDatePicker } from '@elastic/eui';
|
||||
import { TimeHistory, TimeRange } from 'src/legacy/ui/public/timefilter/time_history';
|
||||
import { Timefilter } from 'ui/timefilter';
|
||||
import { TimeHistory, TimeRange } from 'ui/timefilter/time_history';
|
||||
|
||||
interface Props {
|
||||
dateFormat: string;
|
||||
forceRefresh: () => void;
|
||||
timeHistory: TimeHistory;
|
||||
timefilter: Timefilter;
|
||||
}
|
||||
import { mlTimefilterRefresh$ } from '../../../services/timefilter_refresh_service';
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
interface Duration {
|
||||
start: string;
|
||||
end: string;
|
||||
}
|
||||
|
||||
function getRecentlyUsedRanges(timeHistory: TimeHistory): Duration[] {
|
||||
return timeHistory.get().map(({ from, to }: TimeRange) => {
|
||||
return {
|
||||
start: from,
|
||||
end: to,
|
||||
};
|
||||
});
|
||||
function getRecentlyUsedRangesFactory(timeHistory: TimeHistory) {
|
||||
return function(): Duration[] {
|
||||
return timeHistory.get().map(({ from, to }: TimeRange) => {
|
||||
return {
|
||||
start: from,
|
||||
end: to,
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const TopNav: FC<Props> = ({ dateFormat, forceRefresh, timeHistory, timefilter }) => {
|
||||
export const TopNav: FC = () => {
|
||||
const navigationMenuContext = useContext(NavigationMenuContext);
|
||||
const timefilter = navigationMenuContext.timefilter;
|
||||
const getRecentlyUsedRanges = getRecentlyUsedRangesFactory(navigationMenuContext.timeHistory);
|
||||
|
||||
const [refreshInterval, setRefreshInterval] = useState(timefilter.getRefreshInterval());
|
||||
const [time, setTime] = useState(timefilter.getTime());
|
||||
const [recentlyUsedRanges, setRecentlyUsedRanges] = useState(getRecentlyUsedRanges(timeHistory));
|
||||
const [recentlyUsedRanges, setRecentlyUsedRanges] = useState(getRecentlyUsedRanges());
|
||||
const [isAutoRefreshSelectorEnabled, setIsAutoRefreshSelectorEnabled] = useState(
|
||||
timefilter.isAutoRefreshSelectorEnabled
|
||||
);
|
||||
|
@ -41,6 +42,8 @@ export const TopNav: FC<Props> = ({ dateFormat, forceRefresh, timeHistory, timef
|
|||
timefilter.isTimeRangeSelectorEnabled
|
||||
);
|
||||
|
||||
const dateFormat = navigationMenuContext.chrome.getUiSettingsClient().get('dateFormat');
|
||||
|
||||
useEffect(() => {
|
||||
timefilter.on('refreshIntervalUpdate', timefilterUpdateListener);
|
||||
timefilter.on('timeUpdate', timefilterUpdateListener);
|
||||
|
@ -70,7 +73,7 @@ export const TopNav: FC<Props> = ({ dateFormat, forceRefresh, timeHistory, timef
|
|||
// Update timefilter for controllers listening for changes
|
||||
timefilter.setTime(newTime);
|
||||
setTime(newTime);
|
||||
setRecentlyUsedRanges(getRecentlyUsedRanges(timeHistory));
|
||||
setRecentlyUsedRanges(getRecentlyUsedRanges());
|
||||
}
|
||||
|
||||
function updateInterval({
|
||||
|
@ -101,7 +104,7 @@ export const TopNav: FC<Props> = ({ dateFormat, forceRefresh, timeHistory, timef
|
|||
isAutoRefreshOnly={!isTimeRangeSelectorEnabled}
|
||||
refreshInterval={refreshInterval.value}
|
||||
onTimeChange={updateFilter}
|
||||
onRefresh={forceRefresh}
|
||||
onRefresh={() => mlTimefilterRefresh$.next()}
|
||||
onRefreshChange={updateInterval}
|
||||
recentlyUsedRanges={recentlyUsedRanges}
|
||||
dateFormat={dateFormat}
|
||||
|
|
|
@ -14,8 +14,13 @@ import uiChrome from 'ui/chrome';
|
|||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { InjectorService } from '../../../../common/types/angular';
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlDataFrameAccessDenied', ($injector: InjectorService) => {
|
||||
|
@ -34,9 +39,14 @@ module.directive('mlDataFrameAccessDenied', ($injector: InjectorService) => {
|
|||
kbnUrl.redirect('/data_frames');
|
||||
};
|
||||
|
||||
const props = { goToKibana, retry };
|
||||
|
||||
ReactDOM.render(<I18nContext>{React.createElement(Page, props)}</I18nContext>, element[0]);
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<Page goToKibana={goToKibana} retry={retry} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
|
|
|
@ -12,6 +12,10 @@ import { I18nProvider } from '@kbn/i18n/react';
|
|||
|
||||
import { Page } from './page';
|
||||
|
||||
jest.mock('../../../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />,
|
||||
}));
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('Data Frame: Access denied <Page />', () => {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC, Fragment } from 'react';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -24,70 +24,75 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
|
||||
interface PageProps {
|
||||
goToKibana: () => void;
|
||||
retry: () => void;
|
||||
}
|
||||
export const Page: SFC<PageProps> = ({ goToKibana, retry }) => (
|
||||
<EuiPage>
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDeniedTitle"
|
||||
defaultMessage="Access denied"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.ml.dataframe.noPermissionToAccessMLLabel', {
|
||||
defaultMessage: 'You need permission to access Data Frames',
|
||||
})}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.noGrantedPrivilegesDescription"
|
||||
defaultMessage="You must have the privileges granted in the {kibanaUserParam} and {dataFrameUserParam} roles.{br}Your system admin can set these roles on the Management User page."
|
||||
values={{
|
||||
kibanaUserParam: <span className="text-monospace">kibana_user</span>,
|
||||
dataFrameUserParam: (
|
||||
<span className="text-monospace">data_frame_transforms_user</span>
|
||||
),
|
||||
br: <br />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={goToKibana} size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDenied.backToKibanaHomeButtonLabel"
|
||||
defaultMessage="Back to Kibana home"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={retry} size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDenied.retryButtonLabel"
|
||||
defaultMessage="Retry"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
export const Page: FC<PageProps> = ({ goToKibana, retry }) => (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="access-denied" />
|
||||
<EuiPage>
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDeniedTitle"
|
||||
defaultMessage="Access denied"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.ml.dataframe.noPermissionToAccessMLLabel', {
|
||||
defaultMessage: 'You need permission to access Data Frames',
|
||||
})}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.noGrantedPrivilegesDescription"
|
||||
defaultMessage="You must have the privileges granted in the {kibanaUserParam} and {dataFrameUserParam} roles.{br}Your system admin can set these roles on the Management User page."
|
||||
values={{
|
||||
kibanaUserParam: <span className="text-monospace">kibana_user</span>,
|
||||
dataFrameUserParam: (
|
||||
<span className="text-monospace">data_frame_transforms_user</span>
|
||||
),
|
||||
br: <br />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={goToKibana} size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDenied.backToKibanaHomeButtonLabel"
|
||||
defaultMessage="Back to Kibana home"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={retry} size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.accessDenied.retryButtonLabel"
|
||||
defaultMessage="Retry"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ import uiRoutes from 'ui/routes';
|
|||
// @ts-ignore
|
||||
import { getDataFrameBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
const template = `<ml-nav-menu name="access-denied" /><ml-data-frame-access-denied />`;
|
||||
const template = `<ml-data-frame-access-denied />`;
|
||||
|
||||
uiRoutes.when('/data_frames/access-denied', {
|
||||
template,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
@ -15,6 +16,7 @@ import { IndexPattern } from 'ui/index_patterns';
|
|||
import { I18nContext } from 'ui/i18n';
|
||||
import { IPrivate } from 'ui/private';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { InjectorService } from '../../../../common/types/angular';
|
||||
|
||||
// @ts-ignore
|
||||
|
@ -26,6 +28,7 @@ type CreateSearchItems = () => {
|
|||
combinedQuery: any;
|
||||
};
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
import { KibanaContext } from '../../common';
|
||||
import { Page } from './page';
|
||||
|
||||
|
@ -56,9 +59,11 @@ module.directive('mlNewDataFrame', ($injector: InjectorService) => {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
{React.createElement(Page)}
|
||||
</KibanaContext.Provider>
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
<Page />
|
||||
</KibanaContext.Provider>
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC, Fragment } from 'react';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -20,39 +20,43 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
import { Wizard } from './components/wizard';
|
||||
|
||||
export const Page: SFC = () => (
|
||||
<EuiPage>
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.transformsWizard.newDataFrameTitle"
|
||||
defaultMessage="New data frame"
|
||||
/>
|
||||
<span> </span>
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.ml.dataframe.transformsWizard.betaBadgeLabel', {
|
||||
defaultMessage: `Beta`,
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.ml.dataframe.transformsWizard.betaBadgeTooltipContent',
|
||||
{
|
||||
defaultMessage: `Data frames are a beta feature. We'd love to hear your feedback.`,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="l" />
|
||||
<Wizard />
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
export const Page: FC = () => (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="new_data_frame" />
|
||||
<EuiPage>
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.transformsWizard.newDataFrameTitle"
|
||||
defaultMessage="New data frame"
|
||||
/>
|
||||
<span> </span>
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.ml.dataframe.transformsWizard.betaBadgeLabel', {
|
||||
defaultMessage: `Beta`,
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.ml.dataframe.transformsWizard.betaBadgeTooltipContent',
|
||||
{
|
||||
defaultMessage: `Data frames are a beta feature. We'd love to hear your feedback.`,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="l" />
|
||||
<Wizard />
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
getDataFrameIndexOrSearchBreadcrumbs,
|
||||
} from '../../breadcrumbs';
|
||||
|
||||
const wizardTemplate = `<ml-nav-menu name="new_data_frame" /><ml-new-data-frame />`;
|
||||
const wizardTemplate = `<ml-new-data-frame />`;
|
||||
|
||||
uiRoutes.when('/data_frames/new_transform/step/pivot?', {
|
||||
template: wizardTemplate,
|
||||
|
|
|
@ -1,62 +1,67 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Data Frame: Job List <Page /> Minimal initialization 1`] = `
|
||||
<EuiPage
|
||||
data-test-subj="mlPageDataFrame"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageBody
|
||||
<Fragment>
|
||||
<NavigationMenu
|
||||
tabId="data_frames"
|
||||
/>
|
||||
<EuiPage
|
||||
data-test-subj="mlPageDataFrame"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContentHeader
|
||||
responsive={true}
|
||||
<EuiPageBody
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Data frame transforms"
|
||||
id="xpack.ml.dataframe.transformList.dataFrameTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
<span>
|
||||
|
||||
</span>
|
||||
<EuiBetaBadge
|
||||
label="Beta"
|
||||
tooltipContent="Data frames are a beta feature. We'd love to hear your feedback."
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<RefreshTransformListButton
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<CreateTransformButton />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="m"
|
||||
<EuiPageContentHeader
|
||||
responsive={true}
|
||||
>
|
||||
<DataFrameTransformList />
|
||||
</EuiPanel>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Data frame transforms"
|
||||
id="xpack.ml.dataframe.transformList.dataFrameTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
<span>
|
||||
|
||||
</span>
|
||||
<EuiBetaBadge
|
||||
label="Beta"
|
||||
tooltipContent="Data frames are a beta feature. We'd love to hear your feedback."
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<RefreshTransformListButton
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<CreateTransformButton />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="m"
|
||||
>
|
||||
<DataFrameTransformList />
|
||||
</EuiPanel>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -10,8 +10,12 @@ import ReactDOM from 'react-dom';
|
|||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
import chrome from 'ui/chrome';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlDataFramePage', () => {
|
||||
|
@ -19,7 +23,14 @@ module.directive('mlDataFramePage', () => {
|
|||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
ReactDOM.render(<I18nContext>{React.createElement(Page)}</I18nContext>, element[0]);
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<Page />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { SFC, useState } from 'react';
|
||||
import React, { FC, Fragment, useState } from 'react';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -23,59 +23,63 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
import { useRefreshTransformList } from '../../common';
|
||||
import { CreateTransformButton } from './components/create_transform_button';
|
||||
import { DataFrameTransformList } from './components/transform_list';
|
||||
import { RefreshTransformListButton } from './components/refresh_transform_list_button';
|
||||
|
||||
export const Page: SFC = () => {
|
||||
export const Page: FC = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { refresh } = useRefreshTransformList({ isLoading: setIsLoading });
|
||||
|
||||
return (
|
||||
<EuiPage data-test-subj="mlPageDataFrame">
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.transformList.dataFrameTitle"
|
||||
defaultMessage="Data frame transforms"
|
||||
/>
|
||||
<span> </span>
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.ml.dataframe.transformList.betaBadgeLabel', {
|
||||
defaultMessage: `Beta`,
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.ml.dataframe.transformList.betaBadgeTooltipContent',
|
||||
{
|
||||
defaultMessage: `Data frames are a beta feature. We'd love to hear your feedback.`,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<RefreshTransformListButton onClick={refresh} isLoading={isLoading} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<CreateTransformButton />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiPanel>
|
||||
<DataFrameTransformList />
|
||||
</EuiPanel>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="data_frames" />
|
||||
<EuiPage data-test-subj="mlPageDataFrame">
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.transformList.dataFrameTitle"
|
||||
defaultMessage="Data frame transforms"
|
||||
/>
|
||||
<span> </span>
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.ml.dataframe.transformList.betaBadgeLabel', {
|
||||
defaultMessage: `Beta`,
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.ml.dataframe.transformList.betaBadgeTooltipContent',
|
||||
{
|
||||
defaultMessage: `Data frames are a beta feature. We'd love to hear your feedback.`,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<RefreshTransformListButton onClick={refresh} isLoading={isLoading} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<CreateTransformButton />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiPanel>
|
||||
<DataFrameTransformList />
|
||||
</EuiPanel>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ import { loadIndexPatterns } from '../../../util/index_utils';
|
|||
// @ts-ignore
|
||||
import { getDataFrameBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
const template = `<ml-nav-menu name="data_frames" /><ml-data-frame-page />`;
|
||||
const template = `<ml-data-frame-page />`;
|
||||
|
||||
uiRoutes.when('/data_frames/?', {
|
||||
template,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="datavisualizer"></ml-nav-menu>
|
||||
<ml-nav-menu name="datavisualizer" />
|
||||
<ml-chart-tooltip></ml-chart-tooltip>
|
||||
<ml-datavisualizer class="data-visualizer-container">
|
||||
<div ng-controller="MlDataVisualizerViewFields" >
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
|
@ -22,7 +22,12 @@ import {
|
|||
|
||||
import { isFullLicense } from '../../license/check_license';
|
||||
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||
import chrome from 'ui/chrome';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
import { NavigationMenuContext } from '../../util/context_utils';
|
||||
import { NavigationMenu } from '../../components/navigation_menu/navigation_menu';
|
||||
|
||||
function startTrialDescription() {
|
||||
return (
|
||||
|
@ -32,159 +37,151 @@ function startTrialDescription() {
|
|||
defaultMessage="To experience the full Machine Learning features that a {platinumSubscriptionLink} offers, start a 30-day trial."
|
||||
values={{
|
||||
platinumSubscriptionLink: (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/subscriptions"
|
||||
target="_blank"
|
||||
>
|
||||
<EuiLink href="https://www.elastic.co/subscriptions" target="_blank">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.startTrial.platinumSubscriptionTitle"
|
||||
defaultMessage="Platinum subscription"
|
||||
/>
|
||||
</EuiLink>
|
||||
)
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export const DatavisualizerSelector = injectI18n(function (props) {
|
||||
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const startTrialVisible = (isFullLicense() === false);
|
||||
const startTrialVisible = isFullLicense() === false;
|
||||
|
||||
return (
|
||||
<EuiPage restrictWidth={1000}>
|
||||
<EuiPageBody>
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="l">
|
||||
<h2>
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
<EuiPage restrictWidth={1000}>
|
||||
<EuiPageBody>
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="l">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataVisualizerTitle"
|
||||
defaultMessage="Data Visualizer"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="xl" />
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataVisualizerTitle"
|
||||
defaultMessage="Data Visualizer"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="xl" />
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataVisualizerDescription"
|
||||
defaultMessage="The Machine Learning Data Visualizer tool helps you understand your data,
|
||||
id="xpack.ml.datavisualizer.selector.dataVisualizerDescription"
|
||||
defaultMessage="The Machine Learning Data Visualizer tool helps you understand your data,
|
||||
by analyzing the metrics and fields in a log file or an existing Elasticsearch index."
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="xl" />
|
||||
<EuiFlexGroup justifyContent="spaceAround" gutterSize="xl">
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="addDataApp" />}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.importDataTitle"
|
||||
defaultMessage="Import data"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.importDataDescription"
|
||||
defaultMessage="Import data from a log file. You can upload files up to 100 MB."
|
||||
/>
|
||||
}
|
||||
betaBadgeLabel={props.intl.formatMessage({
|
||||
id: 'xpack.ml.datavisualizer.selector.experimentalBadgeLabel',
|
||||
defaultMessage: 'Experimental'
|
||||
})}
|
||||
betaBadgeTooltipContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.experimentalBadgeTooltipLabel"
|
||||
defaultMessage="Experimental feature. We'd love to hear your feedback."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<EuiButton
|
||||
target="_self"
|
||||
href="#/filedatavisualizer"
|
||||
>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="xl" />
|
||||
<EuiFlexGroup justifyContent="spaceAround" gutterSize="xl">
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="addDataApp" />}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.uploadFileButtonLabel"
|
||||
defaultMessage="Upload file"
|
||||
id="xpack.ml.datavisualizer.selector.importDataTitle"
|
||||
defaultMessage="Import data"
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
data-test-subj="mlDataVisualizerCardImportData"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="dataVisualizer" />}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexPatternTitle"
|
||||
defaultMessage="Select an index pattern"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexPatternDescription"
|
||||
defaultMessage="Visualize the data in an existing Elasticsearch index."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<EuiButton
|
||||
target="_self"
|
||||
href="#datavisualizer_index_select"
|
||||
>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexButtonLabel"
|
||||
defaultMessage="Select index"
|
||||
id="xpack.ml.datavisualizer.selector.importDataDescription"
|
||||
defaultMessage="Import data from a log file. You can upload files up to 100 MB."
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
data-test-subj="mlDataVisualizerCardIndexData"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{startTrialVisible === true &&
|
||||
<React.Fragment>
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiFlexGroup justifyContent="spaceAround" gutterSize="xl">
|
||||
<EuiFlexItem grow={false} style={{ width: '600px' }}>
|
||||
<EuiCard
|
||||
title={
|
||||
}
|
||||
betaBadgeLabel={props.intl.formatMessage({
|
||||
id: 'xpack.ml.datavisualizer.selector.experimentalBadgeLabel',
|
||||
defaultMessage: 'Experimental',
|
||||
})}
|
||||
betaBadgeTooltipContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.experimentalBadgeTooltipLabel"
|
||||
defaultMessage="Experimental feature. We'd love to hear your feedback."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<EuiButton target="_self" href="#/filedatavisualizer">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.startTrialTitle"
|
||||
defaultMessage="Start trial"
|
||||
id="xpack.ml.datavisualizer.selector.uploadFileButtonLabel"
|
||||
defaultMessage="Upload file"
|
||||
/>
|
||||
}
|
||||
description={startTrialDescription()}
|
||||
footer={
|
||||
<EuiButton
|
||||
target="_blank"
|
||||
href="kibana#/management/elasticsearch/license_management/home"
|
||||
>
|
||||
</EuiButton>
|
||||
}
|
||||
data-test-subj="mlDataVisualizerCardImportData"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="dataVisualizer" />}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexPatternTitle"
|
||||
defaultMessage="Select an index pattern"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexPatternDescription"
|
||||
defaultMessage="Visualize the data in an existing Elasticsearch index."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<EuiButton target="_self" href="#datavisualizer_index_select">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectIndexButtonLabel"
|
||||
defaultMessage="Select index"
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
data-test-subj="mlDataVisualizerCardIndexData"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{startTrialVisible === true && (
|
||||
<Fragment>
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiFlexGroup justifyContent="spaceAround" gutterSize="xl">
|
||||
<EuiFlexItem grow={false} style={{ width: '600px' }}>
|
||||
<EuiCard
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.startTrialButtonLabel"
|
||||
id="xpack.ml.datavisualizer.selector.startTrialTitle"
|
||||
defaultMessage="Start trial"
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</React.Fragment>
|
||||
}
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
}
|
||||
description={startTrialDescription()}
|
||||
footer={
|
||||
<EuiButton
|
||||
target="_blank"
|
||||
href="kibana#/management/elasticsearch/license_management/home"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.startTrialButtonLabel"
|
||||
defaultMessage="Start trial"
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
)}
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</NavigationMenuContext.Provider>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -18,7 +18,6 @@ import uiRoutes from 'ui/routes';
|
|||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="datavisualizer" />
|
||||
<datavisualizer-selector data-test-subj="mlPageDataVisualizerSelector" />
|
||||
`;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="explorer"></ml-nav-menu>
|
||||
<ml-nav-menu name="explorer" />
|
||||
<ml-chart-tooltip></ml-chart-tooltip>
|
||||
<div class="ml-explorer" ng-controller="MlExplorerController" data-test-subj="mlPageAnomalyExplorer" >
|
||||
|
||||
|
|
|
@ -7,13 +7,22 @@
|
|||
import { FileDataVisualizerView } from './components/file_datavisualizer_view';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
import { NavigationMenuContext } from '../util/context_utils';
|
||||
import { NavigationMenu } from '../components/navigation_menu/navigation_menu';
|
||||
|
||||
export function FileDataVisualizerPage({ indexPatterns, kibanaConfig }) {
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
return (
|
||||
<FileDataVisualizerView indexPatterns={indexPatterns} kibanaConfig={kibanaConfig} />
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
<FileDataVisualizerView indexPatterns={indexPatterns} kibanaConfig={kibanaConfig} />
|
||||
</NavigationMenuContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import uiRoutes from 'ui/routes';
|
|||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="datavisualizer" />
|
||||
<file-datavisualizer-page />
|
||||
`;
|
||||
|
||||
|
|
|
@ -17,10 +17,14 @@ import { checkGetJobsPrivilege } from 'plugins/ml/privilege/check_privilege';
|
|||
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
|
||||
import { getJobManagementBreadcrumbs } from 'plugins/ml/jobs/breadcrumbs';
|
||||
import { loadNewJobDefaults } from 'plugins/ml/jobs/new_job/utils/new_job_defaults';
|
||||
import { NavigationMenuContext } from '../../util/context_utils';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
const template = `<ml-nav-menu name="jobs" /><jobs-page data-test-subj="mlPageJobManagement" />`;
|
||||
const template = `<jobs-page data-test-subj="mlPageJobManagement" />`;
|
||||
|
||||
uiRoutes
|
||||
.when('/jobs/?', {
|
||||
|
@ -45,7 +49,9 @@ module.directive('jobsPage', function () {
|
|||
link: (scope, element) => {
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(JobsPage, { angularWrapperScope: scope })}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<JobsPage angularWrapperScope={scope} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { NavigationMenu } from '../../components/navigation_menu/navigation_menu';
|
||||
|
||||
import { JobsListView } from './components/jobs_list_view';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
export const JobsPage = (props) => (
|
||||
<JobsListView {...props} />
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="jobs" />
|
||||
<JobsListView {...props} />
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job_advanced"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job_advanced" />
|
||||
<ml-new-job class="ml-new-job euiPage euiPage--widthIsNotRestricted">
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div ng-controller="MlNewJob" class="euiPageBody">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job_multi_metric"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job_multi_metric" />
|
||||
<ml-new-job-multi-metric>
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div ng-controller="MlCreateMultiMetricJob" class="multi-metric-job-container">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job_population"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job_population" />
|
||||
<ml-chart-tooltip></ml-chart-tooltip>
|
||||
<ml-new-job-population>
|
||||
<ml-message-bar></ml-message-bar>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job_multi_metric"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job_multi_metric" />
|
||||
<ml-new-job-recognizer>
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div ng-controller="MlCreateRecognizerJobs" class="recognizer-job-container">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job_single_metric"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job_single_metric" />
|
||||
<ml-new-job-single-metric>
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div ng-controller="MlCreateSingleMetricJob" class="single-metric-job-container">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job" />
|
||||
<ml-new-job class="index-or-saved-search-selection">
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div class='kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem' >
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="new_job"></ml-nav-menu>
|
||||
<ml-nav-menu name="new_job" />
|
||||
<ml-new-job class="job-type-gallery">
|
||||
<ml-message-bar></ml-message-bar>
|
||||
<div ng-controller="MlNewJobStepJobType">
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Settings Renders settings page 1`] = `
|
||||
<EuiPage
|
||||
className="mlSettingsPage"
|
||||
data-test-subj="mlPageSettings"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageBody
|
||||
className="mlSettingsPage__body"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContent
|
||||
className="mlSettingsPage__content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
>
|
||||
<EuiPageContentHeader
|
||||
responsive={true}
|
||||
>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
defaultMessage="Job Management"
|
||||
id="xpack.ml.settings.jobManagementTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
<EuiFlexGroup
|
||||
gutterSize="xl"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
color="primary"
|
||||
data-test-subj="ml_calendar_mng_button"
|
||||
href="undefined/app/ml#/settings/calendars_list"
|
||||
iconSide="left"
|
||||
isDisabled={false}
|
||||
size="l"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Calendar management"
|
||||
id="xpack.ml.settings.calendarManagementButtonLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
color="primary"
|
||||
data-test-subj="ml_filter_lists_button"
|
||||
href="undefined/app/ml#/settings/filter_lists"
|
||||
iconSide="left"
|
||||
isDisabled={false}
|
||||
size="l"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Filter Lists"
|
||||
id="xpack.ml.settings.filterListsButtonLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
`;
|
|
@ -1,40 +1,45 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`NewCalendar Renders new calendar form 1`] = `
|
||||
<EuiPage
|
||||
className="mlCalendarEditForm"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContent
|
||||
className="mlCalendarEditForm__content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
<Fragment>
|
||||
<NavigationMenu
|
||||
tabId="settings"
|
||||
/>
|
||||
<EuiPage
|
||||
className="mlCalendarEditForm"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<InjectIntl(CalendarForm)
|
||||
calendarId=""
|
||||
canCreateCalendar={true}
|
||||
canDeleteCalendar={true}
|
||||
description=""
|
||||
eventsList={Array []}
|
||||
groupIds={Array []}
|
||||
isEdit={false}
|
||||
isNewCalendarIdValid={true}
|
||||
jobIds={Array []}
|
||||
onCalendarIdChange={[Function]}
|
||||
onCreate={[Function]}
|
||||
onCreateGroupOption={[Function]}
|
||||
onDescriptionChange={[Function]}
|
||||
onEdit={[Function]}
|
||||
onEventDelete={[Function]}
|
||||
onGroupSelection={[Function]}
|
||||
onJobSelection={[Function]}
|
||||
saving={false}
|
||||
selectedGroupOptions={Array []}
|
||||
selectedJobOptions={Array []}
|
||||
showImportModal={[Function]}
|
||||
showNewEventModal={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
<EuiPageContent
|
||||
className="mlCalendarEditForm__content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
>
|
||||
<InjectIntl(CalendarForm)
|
||||
calendarId=""
|
||||
canCreateCalendar={true}
|
||||
canDeleteCalendar={true}
|
||||
description=""
|
||||
eventsList={Array []}
|
||||
groupIds={Array []}
|
||||
isEdit={false}
|
||||
isNewCalendarIdValid={true}
|
||||
jobIds={Array []}
|
||||
onCalendarIdChange={[Function]}
|
||||
onCreate={[Function]}
|
||||
onCreateGroupOption={[Function]}
|
||||
onDescriptionChange={[Function]}
|
||||
onEdit={[Function]}
|
||||
onEventDelete={[Function]}
|
||||
onGroupSelection={[Function]}
|
||||
onJobSelection={[Function]}
|
||||
saving={false}
|
||||
selectedGroupOptions={Array []}
|
||||
selectedJobOptions={Array []}
|
||||
showImportModal={[Function]}
|
||||
showNewEventModal={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -17,13 +17,16 @@ import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check
|
|||
import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { getCreateCalendarBreadcrumbs, getEditCalendarBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="settings" />
|
||||
<ml-new-calendar />
|
||||
`;
|
||||
|
||||
|
@ -63,7 +66,9 @@ module.directive('mlNewCalendar', function ($route) {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(NewCalendar, props)}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<NewCalendar {...props} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
|
||||
|
||||
import React, {
|
||||
Component
|
||||
} from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
import {
|
||||
EuiPage,
|
||||
EuiPageContent,
|
||||
|
@ -18,14 +18,16 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
|
||||
import { getCalendarSettingsData, validateCalendarId } from './utils';
|
||||
import { CalendarForm } from './calendar_form/';
|
||||
import { NewEventModal } from './new_event_modal/';
|
||||
import { ImportModal } from './import_modal';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
export const NewCalendar = injectI18n(class NewCalendar extends Component {
|
||||
static propTypes = {
|
||||
|
@ -333,39 +335,42 @@ export const NewCalendar = injectI18n(class NewCalendar extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiPage className="mlCalendarEditForm">
|
||||
<EuiPageContent
|
||||
className="mlCalendarEditForm__content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<CalendarForm
|
||||
calendarId={selectedCalendar ? selectedCalendar.calendar_id : formCalendarId}
|
||||
canCreateCalendar={this.props.canCreateCalendar}
|
||||
canDeleteCalendar={this.props.canDeleteCalendar}
|
||||
description={selectedCalendar ? selectedCalendar.description : description}
|
||||
eventsList={events}
|
||||
groupIds={groupIdOptions}
|
||||
isEdit={selectedCalendar !== undefined}
|
||||
isNewCalendarIdValid={(selectedCalendar || isNewCalendarIdValid === null) ? true : isNewCalendarIdValid}
|
||||
jobIds={jobIdOptions}
|
||||
onCalendarIdChange={this.onCalendarIdChange}
|
||||
onCreate={this.onCreate}
|
||||
onDescriptionChange={this.onDescriptionChange}
|
||||
onEdit={this.onEdit}
|
||||
onEventDelete={this.onEventDelete}
|
||||
onGroupSelection={this.onGroupSelection}
|
||||
showImportModal={this.showImportModal}
|
||||
onJobSelection={this.onJobSelection}
|
||||
saving={saving}
|
||||
selectedGroupOptions={selectedGroupOptions}
|
||||
selectedJobOptions={selectedJobOptions}
|
||||
onCreateGroupOption={this.onCreateGroupOption}
|
||||
showNewEventModal={this.showNewEventModal}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
{modal}
|
||||
</EuiPage>
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="settings" />
|
||||
<EuiPage className="mlCalendarEditForm">
|
||||
<EuiPageContent
|
||||
className="mlCalendarEditForm__content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<CalendarForm
|
||||
calendarId={selectedCalendar ? selectedCalendar.calendar_id : formCalendarId}
|
||||
canCreateCalendar={this.props.canCreateCalendar}
|
||||
canDeleteCalendar={this.props.canDeleteCalendar}
|
||||
description={selectedCalendar ? selectedCalendar.description : description}
|
||||
eventsList={events}
|
||||
groupIds={groupIdOptions}
|
||||
isEdit={selectedCalendar !== undefined}
|
||||
isNewCalendarIdValid={(selectedCalendar || isNewCalendarIdValid === null) ? true : isNewCalendarIdValid}
|
||||
jobIds={jobIdOptions}
|
||||
onCalendarIdChange={this.onCalendarIdChange}
|
||||
onCreate={this.onCreate}
|
||||
onDescriptionChange={this.onDescriptionChange}
|
||||
onEdit={this.onEdit}
|
||||
onEventDelete={this.onEventDelete}
|
||||
onGroupSelection={this.onGroupSelection}
|
||||
showImportModal={this.showImportModal}
|
||||
onJobSelection={this.onJobSelection}
|
||||
saving={saving}
|
||||
selectedGroupOptions={selectedGroupOptions}
|
||||
selectedJobOptions={selectedJobOptions}
|
||||
onCreateGroupOption={this.onCreateGroupOption}
|
||||
showNewEventModal={this.showNewEventModal}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
{modal}
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
jest.mock('../../../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
checkPermission: () => true
|
||||
}));
|
||||
jest.mock('../../../license/check_license', () => ({
|
||||
hasLicenseExpired: () => false
|
||||
hasLicenseExpired: () => false,
|
||||
isFullLicense: () => false
|
||||
}));
|
||||
jest.mock('../../../privilege/get_privileges', () => ({
|
||||
getPrivileges: () => {}
|
||||
|
@ -18,9 +20,6 @@ jest.mock('../../../privilege/get_privileges', () => ({
|
|||
jest.mock('../../../ml_nodes_check/check_ml_nodes', () => ({
|
||||
mlNodesAvailable: () => true
|
||||
}));
|
||||
jest.mock('ui/chrome', () => ({
|
||||
getBasePath: jest.fn()
|
||||
}));
|
||||
jest.mock('../../../services/ml_api_service', () => ({
|
||||
ml: {
|
||||
calendars: () => {
|
||||
|
|
|
@ -1,69 +1,74 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CalendarsList Renders calendar list with calendars 1`] = `
|
||||
<EuiPage
|
||||
className="mlCalendarList"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContent
|
||||
className="mlCalendarList__content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
<Fragment>
|
||||
<NavigationMenu
|
||||
tabId="settings"
|
||||
/>
|
||||
<EuiPage
|
||||
className="mlCalendarList"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<CalendarsListHeader
|
||||
refreshCalendars={[Function]}
|
||||
totalCount={2}
|
||||
/>
|
||||
<InjectIntl(CalendarsListTable)
|
||||
calendarsList={
|
||||
Array [
|
||||
Object {
|
||||
"calendar_id": "farequote-calendar",
|
||||
"description": "test ",
|
||||
"events": Array [
|
||||
Object {
|
||||
"calendar_id": "farequote-calendar",
|
||||
"description": "Downtime feb 9 2017 10:10 to 10:30",
|
||||
"end_time": 1486657800000,
|
||||
"event_id": "Ee-YgGcBxHgQWEhCO_xj",
|
||||
"start_time": 1486656600000,
|
||||
},
|
||||
],
|
||||
"events_length": 1,
|
||||
"job_ids": Array [
|
||||
"farequote",
|
||||
],
|
||||
"job_ids_string": "farequote",
|
||||
},
|
||||
Object {
|
||||
"calendar_id": "this-is-a-new-calendar",
|
||||
"description": "new calendar",
|
||||
"events": Array [
|
||||
Object {
|
||||
"calendar_id": "this-is-a-new-calendar",
|
||||
"description": "New event!",
|
||||
"end_time": 1544162400000,
|
||||
"event_id": "ehWKhGcBqHkXuWNrIrSV",
|
||||
"start_time": 1544076000000,
|
||||
},
|
||||
],
|
||||
"events_length": 1,
|
||||
"job_ids": Array [
|
||||
"test",
|
||||
],
|
||||
"job_ids_string": "test",
|
||||
},
|
||||
]
|
||||
}
|
||||
canCreateCalendar={true}
|
||||
canDeleteCalendar={true}
|
||||
itemsSelected={false}
|
||||
loading={false}
|
||||
mlNodesAvailable={true}
|
||||
onDeleteClick={[Function]}
|
||||
setSelectedCalendarList={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
<EuiPageContent
|
||||
className="mlCalendarList__content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
>
|
||||
<CalendarsListHeader
|
||||
refreshCalendars={[Function]}
|
||||
totalCount={2}
|
||||
/>
|
||||
<InjectIntl(CalendarsListTable)
|
||||
calendarsList={
|
||||
Array [
|
||||
Object {
|
||||
"calendar_id": "farequote-calendar",
|
||||
"description": "test ",
|
||||
"events": Array [
|
||||
Object {
|
||||
"calendar_id": "farequote-calendar",
|
||||
"description": "Downtime feb 9 2017 10:10 to 10:30",
|
||||
"end_time": 1486657800000,
|
||||
"event_id": "Ee-YgGcBxHgQWEhCO_xj",
|
||||
"start_time": 1486656600000,
|
||||
},
|
||||
],
|
||||
"events_length": 1,
|
||||
"job_ids": Array [
|
||||
"farequote",
|
||||
],
|
||||
"job_ids_string": "farequote",
|
||||
},
|
||||
Object {
|
||||
"calendar_id": "this-is-a-new-calendar",
|
||||
"description": "new calendar",
|
||||
"events": Array [
|
||||
Object {
|
||||
"calendar_id": "this-is-a-new-calendar",
|
||||
"description": "New event!",
|
||||
"end_time": 1544162400000,
|
||||
"event_id": "ehWKhGcBqHkXuWNrIrSV",
|
||||
"start_time": 1544076000000,
|
||||
},
|
||||
],
|
||||
"events_length": 1,
|
||||
"job_ids": Array [
|
||||
"test",
|
||||
],
|
||||
"job_ids_string": "test",
|
||||
},
|
||||
]
|
||||
}
|
||||
canCreateCalendar={true}
|
||||
canDeleteCalendar={true}
|
||||
itemsSelected={false}
|
||||
loading={false}
|
||||
mlNodesAvailable={true}
|
||||
onDeleteClick={[Function]}
|
||||
setSelectedCalendarList={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
|
||||
|
||||
import React, {
|
||||
Component
|
||||
} from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
|
||||
import {
|
||||
|
@ -19,6 +17,7 @@ import {
|
|||
EUI_MODAL_CONFIRM_BUTTON,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
import { CalendarsListHeader } from './header';
|
||||
import { CalendarsListTable } from './table/';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
|
@ -147,29 +146,32 @@ export const CalendarsList = injectI18n(class CalendarsList extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiPage className="mlCalendarList">
|
||||
<EuiPageContent
|
||||
className="mlCalendarList__content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<CalendarsListHeader
|
||||
totalCount={calendars.length}
|
||||
refreshCalendars={this.loadCalendars}
|
||||
/>
|
||||
<CalendarsListTable
|
||||
loading={loading}
|
||||
calendarsList={this.addRequiredFieldsToList(calendars)}
|
||||
onDeleteClick={this.showDestroyModal}
|
||||
canCreateCalendar={canCreateCalendar}
|
||||
canDeleteCalendar={canDeleteCalendar}
|
||||
mlNodesAvailable={nodesAvailable}
|
||||
setSelectedCalendarList={this.setSelectedCalendarList}
|
||||
itemsSelected={selectedForDeletion.length > 0}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
{destroyModal}
|
||||
</EuiPage>
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="settings" />
|
||||
<EuiPage className="mlCalendarList">
|
||||
<EuiPageContent
|
||||
className="mlCalendarList__content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<CalendarsListHeader
|
||||
totalCount={calendars.length}
|
||||
refreshCalendars={this.loadCalendars}
|
||||
/>
|
||||
<CalendarsListTable
|
||||
loading={loading}
|
||||
calendarsList={this.addRequiredFieldsToList(calendars)}
|
||||
onDeleteClick={this.showDestroyModal}
|
||||
canCreateCalendar={canCreateCalendar}
|
||||
canDeleteCalendar={canDeleteCalendar}
|
||||
mlNodesAvailable={nodesAvailable}
|
||||
setSelectedCalendarList={this.setSelectedCalendarList}
|
||||
itemsSelected={selectedForDeletion.length > 0}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
{destroyModal}
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,13 +4,21 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
|
||||
import { CalendarsList } from './calendars_list';
|
||||
|
||||
jest.mock('../../../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
checkPermission: () => true
|
||||
}));
|
||||
jest.mock('../../../license/check_license', () => ({
|
||||
hasLicenseExpired: () => false
|
||||
hasLicenseExpired: () => false,
|
||||
isFullLicense: () => false
|
||||
}));
|
||||
jest.mock('../../../privilege/get_privileges', () => ({
|
||||
getPrivileges: () => {}
|
||||
|
@ -18,9 +26,6 @@ jest.mock('../../../privilege/get_privileges', () => ({
|
|||
jest.mock('../../../ml_nodes_check/check_ml_nodes', () => ({
|
||||
mlNodesAvailable: () => true
|
||||
}));
|
||||
jest.mock('ui/chrome', () => ({
|
||||
getBasePath: jest.fn()
|
||||
}));
|
||||
jest.mock('../../../services/ml_api_service', () => ({
|
||||
ml: {
|
||||
calendars: () => {
|
||||
|
@ -30,12 +35,6 @@ jest.mock('../../../services/ml_api_service', () => ({
|
|||
}
|
||||
}));
|
||||
|
||||
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
|
||||
import { CalendarsList } from './calendars_list';
|
||||
|
||||
const testingState = {
|
||||
loading: false,
|
||||
calendars: [
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
import 'ngreact';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
@ -17,27 +16,28 @@ import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check
|
|||
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { getCalendarManagementBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="settings" />
|
||||
<ml-calendars-list />
|
||||
`;
|
||||
|
||||
uiRoutes
|
||||
.when('/settings/calendars_list', {
|
||||
template,
|
||||
k7Breadcrumbs: getCalendarManagementBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
mlNodeCount: getMlNodeCount,
|
||||
}
|
||||
});
|
||||
|
||||
uiRoutes.when('/settings/calendars_list', {
|
||||
template,
|
||||
k7Breadcrumbs: getCalendarManagementBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
mlNodeCount: getMlNodeCount,
|
||||
},
|
||||
});
|
||||
|
||||
import { CalendarsList } from './calendars_list';
|
||||
|
||||
|
@ -54,10 +54,12 @@ module.directive('mlCalendarsList', function () {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(CalendarsList, props)}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<CalendarsList {...props} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,8 +9,6 @@ import 'ngreact';
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
|
@ -20,11 +18,16 @@ import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/che
|
|||
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
|
||||
import { EditFilterList } from './edit_filter_list';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="settings" />
|
||||
<ml-edit-filter-list />
|
||||
`;
|
||||
|
||||
|
@ -62,7 +65,9 @@ module.directive('mlEditFilterList', function ($route) {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(EditFilterList, props)}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<EditFilterList {...props} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
*/
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {
|
||||
Component
|
||||
} from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
|
@ -33,6 +31,7 @@ import { toastNotifications } from 'ui/notify';
|
|||
import { EditFilterListHeader } from './header';
|
||||
import { EditFilterListToolbar } from './toolbar';
|
||||
import { ItemsGrid } from '../../../components/items_grid';
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
import {
|
||||
isValidFilterListId,
|
||||
saveFilterList
|
||||
|
@ -309,71 +308,74 @@ export const EditFilterList = injectI18n(class extends Component {
|
|||
const totalItemCount = (items !== undefined) ? items.length : 0;
|
||||
|
||||
return (
|
||||
<EuiPage className="ml-edit-filter-lists">
|
||||
<EuiPageContent
|
||||
className="ml-edit-filter-lists-content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<EditFilterListHeader
|
||||
canCreateFilter={canCreateFilter}
|
||||
filterId={this.props.filterId}
|
||||
newFilterId={newFilterId}
|
||||
isNewFilterIdInvalid={isNewFilterIdInvalid}
|
||||
updateNewFilterId={this.updateNewFilterId}
|
||||
description={description}
|
||||
updateDescription={this.updateDescription}
|
||||
totalItemCount={totalItemCount}
|
||||
usedBy={loadedFilter.used_by}
|
||||
/>
|
||||
<EditFilterListToolbar
|
||||
canCreateFilter={canCreateFilter}
|
||||
canDeleteFilter={canDeleteFilter}
|
||||
onSearchChange={this.onSearchChange}
|
||||
addItems={this.addItems}
|
||||
deleteSelectedItems={this.deleteSelectedItems}
|
||||
selectedItemCount={selectedItems.length}
|
||||
/>
|
||||
<EuiSpacer size="xl" />
|
||||
<ItemsGrid
|
||||
totalItemCount={totalItemCount}
|
||||
items={matchingItems}
|
||||
selectedItems={selectedItems}
|
||||
itemsPerPage={itemsPerPage}
|
||||
setItemsPerPage={this.setItemsPerPage}
|
||||
setItemSelected={this.setItemSelected}
|
||||
activePage={activePage}
|
||||
setActivePage={this.setActivePage}
|
||||
/>
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
onClick={returnToFiltersList}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterLists.editFilterList.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={this.save}
|
||||
disabled={(saveInProgress === true) ||
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="settings" />
|
||||
<EuiPage className="ml-edit-filter-lists">
|
||||
<EuiPageContent
|
||||
className="ml-edit-filter-lists-content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<EditFilterListHeader
|
||||
canCreateFilter={canCreateFilter}
|
||||
filterId={this.props.filterId}
|
||||
newFilterId={newFilterId}
|
||||
isNewFilterIdInvalid={isNewFilterIdInvalid}
|
||||
updateNewFilterId={this.updateNewFilterId}
|
||||
description={description}
|
||||
updateDescription={this.updateDescription}
|
||||
totalItemCount={totalItemCount}
|
||||
usedBy={loadedFilter.used_by}
|
||||
/>
|
||||
<EditFilterListToolbar
|
||||
canCreateFilter={canCreateFilter}
|
||||
canDeleteFilter={canDeleteFilter}
|
||||
onSearchChange={this.onSearchChange}
|
||||
addItems={this.addItems}
|
||||
deleteSelectedItems={this.deleteSelectedItems}
|
||||
selectedItemCount={selectedItems.length}
|
||||
/>
|
||||
<EuiSpacer size="xl" />
|
||||
<ItemsGrid
|
||||
totalItemCount={totalItemCount}
|
||||
items={matchingItems}
|
||||
selectedItems={selectedItems}
|
||||
itemsPerPage={itemsPerPage}
|
||||
setItemsPerPage={this.setItemsPerPage}
|
||||
setItemSelected={this.setItemSelected}
|
||||
activePage={activePage}
|
||||
setActivePage={this.setActivePage}
|
||||
/>
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
onClick={returnToFiltersList}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterLists.editFilterList.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={this.save}
|
||||
disabled={(saveInProgress === true) ||
|
||||
(isNewFilterIdInvalid === true) ||
|
||||
(canCreateFilter === false)
|
||||
}
|
||||
fill
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterLists.editFilterList.saveButtonLabel"
|
||||
defaultMessage="Save"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
}
|
||||
fill
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterLists.editFilterList.saveButtonLabel"
|
||||
defaultMessage="Save"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
jest.mock('../../../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />
|
||||
}));
|
||||
|
||||
// Define the required mocks used for loading, saving and validating the filter list.
|
||||
jest.mock('./utils', () => ({
|
||||
isValidFilterListId: () => true,
|
||||
|
@ -19,7 +23,7 @@ const mockTestFilter = {
|
|||
items: ['google.com', 'google.co.uk', 'elastic.co', 'youtube.com'],
|
||||
used_by: {
|
||||
detectors: ['high info content'],
|
||||
jobs: ['dns_exfiltration']
|
||||
jobs: ['dns_exfiltration'],
|
||||
},
|
||||
};
|
||||
jest.mock('../../../services/ml_api_service', () => ({
|
||||
|
@ -27,12 +31,11 @@ jest.mock('../../../services/ml_api_service', () => ({
|
|||
filters: {
|
||||
filters: () => {
|
||||
return Promise.resolve(mockTestFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -40,14 +43,11 @@ import { EditFilterList } from './edit_filter_list';
|
|||
|
||||
const props = {
|
||||
canCreateFilter: true,
|
||||
canDeleteFilter: true
|
||||
canDeleteFilter: true,
|
||||
};
|
||||
|
||||
function prepareEditTest() {
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<EditFilterList.WrappedComponent {...props}/>
|
||||
);
|
||||
const wrapper = shallowWithIntl(<EditFilterList.WrappedComponent {...props} />);
|
||||
|
||||
// Cannot find a way to generate the snapshot after the Promise in the mock ml.filters
|
||||
// has resolved.
|
||||
|
@ -61,11 +61,8 @@ function prepareEditTest() {
|
|||
}
|
||||
|
||||
describe('EditFilterList', () => {
|
||||
|
||||
test('renders the edit page for a new filter list and updates ID', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<EditFilterList.WrappedComponent {...props}/>
|
||||
);
|
||||
const wrapper = shallowWithIntl(<EditFilterList.WrappedComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
const instance = wrapper.instance();
|
||||
|
@ -114,5 +111,4 @@ describe('EditFilterList', () => {
|
|||
wrapper.update();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,41 +1,46 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Filter Lists renders a list of filters 1`] = `
|
||||
<EuiPage
|
||||
className="ml-list-filter-lists"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageContent
|
||||
className="ml-list-filter-lists-content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
<Fragment>
|
||||
<NavigationMenu
|
||||
tabId="settings"
|
||||
/>
|
||||
<EuiPage
|
||||
className="ml-list-filter-lists"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<FilterListsHeader
|
||||
refreshFilterLists={[Function]}
|
||||
totalCount={1}
|
||||
/>
|
||||
<FilterListsTable
|
||||
canCreateFilter={true}
|
||||
canDeleteFilter={true}
|
||||
filterLists={
|
||||
Array [
|
||||
Object {
|
||||
"description": "List of known safe domains",
|
||||
"filter_id": "safe_domains",
|
||||
"item_count": 500,
|
||||
"used_by": Object {
|
||||
"jobs": Array [
|
||||
"dns_exfiltration",
|
||||
],
|
||||
<EuiPageContent
|
||||
className="ml-list-filter-lists-content"
|
||||
horizontalPosition="center"
|
||||
panelPaddingSize="l"
|
||||
verticalPosition="center"
|
||||
>
|
||||
<FilterListsHeader
|
||||
refreshFilterLists={[Function]}
|
||||
totalCount={1}
|
||||
/>
|
||||
<FilterListsTable
|
||||
canCreateFilter={true}
|
||||
canDeleteFilter={true}
|
||||
filterLists={
|
||||
Array [
|
||||
Object {
|
||||
"description": "List of known safe domains",
|
||||
"filter_id": "safe_domains",
|
||||
"item_count": 500,
|
||||
"used_by": Object {
|
||||
"jobs": Array [
|
||||
"dns_exfiltration",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
refreshFilterLists={[Function]}
|
||||
selectedFilterLists={Array []}
|
||||
setSelectedFilterLists={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
]
|
||||
}
|
||||
refreshFilterLists={[Function]}
|
||||
selectedFilterLists={Array []}
|
||||
setSelectedFilterLists={[Function]}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -9,8 +9,6 @@ import 'ngreact';
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
|
@ -20,11 +18,16 @@ import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/che
|
|||
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
|
||||
import { FilterLists } from './filter_lists';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { NavigationMenuContext } from '../../../util/context_utils';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="settings" />
|
||||
<ml-filter-lists />
|
||||
`;
|
||||
|
||||
|
@ -52,7 +55,9 @@ module.directive('mlFilterLists', function () {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(FilterLists, props)}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
|
||||
<FilterLists {...props} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
* React table for displaying a table of filter lists.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
Component
|
||||
} from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
|
||||
import {
|
||||
|
@ -23,6 +21,8 @@ import { injectI18n } from '@kbn/i18n/react';
|
|||
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu';
|
||||
|
||||
import { FilterListsHeader } from './header';
|
||||
import { FilterListsTable } from './table';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
|
@ -88,26 +88,29 @@ export const FilterLists = injectI18n(class extends Component {
|
|||
const { canCreateFilter, canDeleteFilter } = this.props;
|
||||
|
||||
return (
|
||||
<EuiPage className="ml-list-filter-lists">
|
||||
<EuiPageContent
|
||||
className="ml-list-filter-lists-content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<FilterListsHeader
|
||||
totalCount={filterLists.length}
|
||||
refreshFilterLists={this.refreshFilterLists}
|
||||
/>
|
||||
<FilterListsTable
|
||||
canCreateFilter={canCreateFilter}
|
||||
canDeleteFilter={canDeleteFilter}
|
||||
filterLists={filterLists}
|
||||
selectedFilterLists={selectedFilterLists}
|
||||
setSelectedFilterLists={this.setSelectedFilterLists}
|
||||
refreshFilterLists={this.refreshFilterLists}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="settings" />
|
||||
<EuiPage className="ml-list-filter-lists">
|
||||
<EuiPageContent
|
||||
className="ml-list-filter-lists-content"
|
||||
verticalPosition="center"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<FilterListsHeader
|
||||
totalCount={filterLists.length}
|
||||
refreshFilterLists={this.refreshFilterLists}
|
||||
/>
|
||||
<FilterListsTable
|
||||
canCreateFilter={canCreateFilter}
|
||||
canDeleteFilter={canDeleteFilter}
|
||||
filterLists={filterLists}
|
||||
selectedFilterLists={selectedFilterLists}
|
||||
setSelectedFilterLists={this.setSelectedFilterLists}
|
||||
refreshFilterLists={this.refreshFilterLists}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
|
||||
import { FilterLists } from './filter_lists';
|
||||
|
||||
jest.mock('../../../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />
|
||||
}));
|
||||
jest.mock('../../../privilege/check_privilege', () => ({
|
||||
checkPermission: () => true
|
||||
checkPermission: () => true,
|
||||
}));
|
||||
|
||||
// Mock the call for loading the list of filters.
|
||||
|
@ -23,28 +30,19 @@ jest.mock('../../../services/ml_api_service', () => ({
|
|||
filters: {
|
||||
filtersStats: () => {
|
||||
return Promise.resolve([mockTestFilter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
|
||||
import { FilterLists } from './filter_lists';
|
||||
|
||||
const props = {
|
||||
canCreateFilter: true,
|
||||
canDeleteFilter: true
|
||||
canDeleteFilter: true,
|
||||
};
|
||||
|
||||
describe('Filter Lists', () => {
|
||||
|
||||
test('renders a list of filters', () => {
|
||||
|
||||
const wrapper = shallowWithIntl(
|
||||
<FilterLists.WrappedComponent {...props}/>
|
||||
);
|
||||
const wrapper = shallowWithIntl(<FilterLists.WrappedComponent {...props} />);
|
||||
|
||||
// Cannot find a way to generate the snapshot after the Promise in the mock ml.filters
|
||||
// has resolved.
|
||||
|
@ -54,5 +52,4 @@ describe('Filter Lists', () => {
|
|||
wrapper.update();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
|
||||
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
|
||||
import {
|
||||
|
@ -20,67 +20,73 @@ import {
|
|||
EuiTitle
|
||||
} from '@elastic/eui';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { useNavigationMenuContext } from '../util/context_utils';
|
||||
import { NavigationMenu } from '../components/navigation_menu/navigation_menu';
|
||||
|
||||
export function Settings({
|
||||
canGetFilters,
|
||||
canGetCalendars
|
||||
}) {
|
||||
const basePath = useNavigationMenuContext().chrome.getBasePath();
|
||||
|
||||
return (
|
||||
<EuiPage className="mlSettingsPage" data-test-subj="mlPageSettings">
|
||||
<EuiPageBody className="mlSettingsPage__body">
|
||||
<EuiPageContent
|
||||
className="mlSettingsPage__content"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.jobManagementTitle"
|
||||
defaultMessage="Job Management"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="settings" />
|
||||
<EuiPage className="mlSettingsPage" data-test-subj="mlPageSettings">
|
||||
<EuiPageBody className="mlSettingsPage__body">
|
||||
<EuiPageContent
|
||||
className="mlSettingsPage__content"
|
||||
horizontalPosition="center"
|
||||
>
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.jobManagementTitle"
|
||||
defaultMessage="Job Management"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="ml_calendar_mng_button"
|
||||
size="l"
|
||||
color="primary"
|
||||
href={`${chrome.getBasePath()}/app/ml#/settings/calendars_list`}
|
||||
isDisabled={canGetCalendars === false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.calendarManagementButtonLabel"
|
||||
defaultMessage="Calendar management"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="ml_calendar_mng_button"
|
||||
size="l"
|
||||
color="primary"
|
||||
href={`${basePath}/app/ml#/settings/calendars_list`}
|
||||
isDisabled={canGetCalendars === false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.calendarManagementButtonLabel"
|
||||
defaultMessage="Calendar management"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="ml_filter_lists_button"
|
||||
size="l"
|
||||
color="primary"
|
||||
href={`${chrome.getBasePath()}/app/ml#/settings/filter_lists`}
|
||||
isDisabled={canGetFilters === false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterListsButtonLabel"
|
||||
defaultMessage="Filter Lists"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="ml_filter_lists_button"
|
||||
size="l"
|
||||
color="primary"
|
||||
href={`${basePath}/app/ml#/settings/filter_lists`}
|
||||
isDisabled={canGetFilters === false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.settings.filterListsButtonLabel"
|
||||
defaultMessage="Filter Lists"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,46 +4,65 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
jest.mock('ui/chrome', () => ({
|
||||
getBasePath: jest.fn()
|
||||
}));
|
||||
|
||||
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import * as ContextUtils from '../util/context_utils';
|
||||
import { Settings } from './settings';
|
||||
|
||||
const navigationMenuMock = ContextUtils.navigationMenuMock;
|
||||
const mountOptions = {
|
||||
context: { NavigationMenuContext: navigationMenuMock },
|
||||
childContextTypes: { NavigationMenuContext: PropTypes.object }
|
||||
};
|
||||
|
||||
jest.mock('../components/navigation_menu/navigation_menu', () => ({
|
||||
NavigationMenu: () => <div id="mockNavigationMenu" />
|
||||
}));
|
||||
jest.spyOn(ContextUtils, 'useNavigationMenuContext').mockImplementation(() => navigationMenuMock);
|
||||
|
||||
|
||||
describe('Settings', () => {
|
||||
test('Renders settings page with all buttons enabled.', () => {
|
||||
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={true} />, mountOptions);
|
||||
|
||||
test('Renders settings page', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Settings canGetFilters={true} canGetCalendars={true}/>
|
||||
);
|
||||
const filterButton = wrapper
|
||||
.find('[data-test-subj="ml_filter_lists_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(filterButton.prop('isDisabled')).toBe(false);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const calendarButton = wrapper
|
||||
.find('[data-test-subj="ml_calendar_mng_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(calendarButton.prop('isDisabled')).toBe(false);
|
||||
});
|
||||
|
||||
test('Filter Lists button disabled if canGetFilters is false', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<Settings canGetFilters={false} canGetCalendars={true}/>
|
||||
);
|
||||
const wrapper = mountWithIntl(<Settings canGetFilters={false} canGetCalendars={true} />, mountOptions);
|
||||
|
||||
const button = wrapper.find('[data-test-subj="ml_filter_lists_button"]');
|
||||
const filterButton = button.find('EuiButtonEmpty');
|
||||
const filterButton = wrapper
|
||||
.find('[data-test-subj="ml_filter_lists_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(filterButton.prop('isDisabled')).toBe(true);
|
||||
|
||||
const calendarButton = wrapper
|
||||
.find('[data-test-subj="ml_calendar_mng_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(calendarButton.prop('isDisabled')).toBe(false);
|
||||
});
|
||||
|
||||
test('Calendar management button disabled if canGetCalendars is false', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<Settings canGetFilters={true} canGetCalendars={false} />
|
||||
);
|
||||
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={false} />, mountOptions);
|
||||
|
||||
const button = wrapper.find('[data-test-subj="ml_calendar_mng_button"]');
|
||||
const calendarButton = button.find('EuiButtonEmpty');
|
||||
const filterButton = wrapper
|
||||
.find('[data-test-subj="ml_filter_lists_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(filterButton.prop('isDisabled')).toBe(false);
|
||||
|
||||
const calendarButton = wrapper
|
||||
.find('[data-test-subj="ml_calendar_mng_button"]')
|
||||
.find('EuiButtonEmpty');
|
||||
expect(calendarButton.prop('isDisabled')).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -15,15 +15,17 @@ const module = uiModules.get('apps/ml', ['react']);
|
|||
import { checkFullLicense } from '../license/check_license';
|
||||
import { checkGetJobsPrivilege, checkPermission } from '../privilege/check_privilege';
|
||||
import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes';
|
||||
import { NavigationMenuContext } from '../util/context_utils';
|
||||
import { getSettingsBreadcrumbs } from './breadcrumbs';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { timeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<ml-nav-menu name="settings" />
|
||||
<ml-settings />
|
||||
`;
|
||||
|
||||
|
@ -56,12 +58,9 @@ module.directive('mlSettings', function () {
|
|||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
{React.createElement(
|
||||
Settings, {
|
||||
canGetFilters,
|
||||
canGetCalendars
|
||||
})
|
||||
}
|
||||
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }} >
|
||||
<Settings canGetCalendars={canGetCalendars} canGetFilters={canGetFilters} />
|
||||
</NavigationMenuContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ml-nav-menu name="timeseriesexplorer"></ml-nav-menu>
|
||||
<ml-nav-menu name="timeseriesexplorer" />
|
||||
<ml-chart-tooltip></ml-chart-tooltip>
|
||||
<div class="ml-time-series-explorer" ng-controller="MlTimeSeriesExplorerController" data-test-subj="mlPageSingleMetricViewer" >
|
||||
|
||||
|
|
66
x-pack/legacy/plugins/ml/public/util/context_utils.tsx
Normal file
66
x-pack/legacy/plugins/ml/public/util/context_utils.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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, { useContext } from 'react';
|
||||
|
||||
import { Chrome } from 'ui/chrome';
|
||||
import { Timefilter } from 'ui/timefilter';
|
||||
import { TimeHistory } from 'ui/timefilter/time_history';
|
||||
|
||||
export const ChromeContext = React.createContext<Chrome>({} as Chrome);
|
||||
export const TimefilterContext = React.createContext<Timefilter>({} as Timefilter);
|
||||
export const TimeHistoryContext = React.createContext<TimeHistory>({} as TimeHistory);
|
||||
|
||||
interface NavigationMenuContextValue {
|
||||
chrome: Chrome;
|
||||
timefilter: Timefilter;
|
||||
timeHistory: TimeHistory;
|
||||
}
|
||||
export const NavigationMenuContext = React.createContext<NavigationMenuContextValue>({
|
||||
chrome: {} as Chrome,
|
||||
timefilter: {} as Timefilter,
|
||||
timeHistory: {} as TimeHistory,
|
||||
});
|
||||
|
||||
export const useNavigationMenuContext = () => {
|
||||
return useContext(NavigationMenuContext);
|
||||
};
|
||||
|
||||
// testing mocks
|
||||
export const chromeMock = {
|
||||
getBasePath: () => 'basePath',
|
||||
getUiSettingsClient: () => {
|
||||
return {
|
||||
get: (key: string) => {
|
||||
switch (key) {
|
||||
case 'dateFormat':
|
||||
case 'timepicker:timeDefaults':
|
||||
return {};
|
||||
case 'timepicker:refreshIntervalDefaults':
|
||||
return { pause: false, value: 0 };
|
||||
default:
|
||||
throw new Error(`Unexpected config key: ${key}`);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
} as Chrome;
|
||||
|
||||
export const timefilterMock = ({
|
||||
getRefreshInterval: () => '30s',
|
||||
getTime: () => ({ from: 0, to: 0 }),
|
||||
on: (event: string, reload: () => void) => {},
|
||||
} as unknown) as Timefilter;
|
||||
|
||||
export const timeHistoryMock = ({
|
||||
get: () => [{ from: 0, to: 0 }],
|
||||
} as unknown) as TimeHistory;
|
||||
|
||||
export const navigationMenuMock = {
|
||||
chrome: chromeMock,
|
||||
timefilter: timefilterMock,
|
||||
timeHistory: timeHistoryMock,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue