[ML] Fixing missing data visualizer links (#103932)
* [ML] Fixing missing data visualizer links * adding index dataviz links * fixing permission * re-enabling tests * fixing typo * adding check for non time based index * catching possible error when getting index pattern Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
5301403594
commit
10ea44b24c
|
@ -8,11 +8,12 @@
|
|||
import { lazyLoadModules } from '../lazy_load_bundle';
|
||||
import type { FileDataVisualizerSpec, IndexDataVisualizerSpec } from '../application';
|
||||
|
||||
export async function getFileDataVisualizerComponent(): Promise<FileDataVisualizerSpec> {
|
||||
export async function getFileDataVisualizerComponent(): Promise<() => FileDataVisualizerSpec> {
|
||||
const modules = await lazyLoadModules();
|
||||
return modules.FileDataVisualizer;
|
||||
return () => modules.FileDataVisualizer;
|
||||
}
|
||||
export async function getIndexDataVisualizerComponent(): Promise<IndexDataVisualizerSpec> {
|
||||
|
||||
export async function getIndexDataVisualizerComponent(): Promise<() => IndexDataVisualizerSpec> {
|
||||
const modules = await lazyLoadModules();
|
||||
return modules.IndexDataVisualizer;
|
||||
return () => modules.IndexDataVisualizer;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,12 @@ export const FilebeatConfigFlyout: FC<Props> = ({
|
|||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
|
||||
<EuiButtonEmpty
|
||||
iconType="cross"
|
||||
onClick={closeFlyout}
|
||||
flush="left"
|
||||
data-test-subj="fileBeatConfigFlyoutCloseButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.fileBeatConfigFlyout.closeButton"
|
||||
defaultMessage="Close"
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export { ResultsLinks } from './results_links';
|
||||
export { ResultsLinks, ResultLink } from './results_links';
|
||||
|
|
|
@ -18,6 +18,19 @@ import { FindFileStructureResponse } from '../../../../../../file_upload/common'
|
|||
import type { FileUploadPluginStart } from '../../../../../../file_upload/public';
|
||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||
|
||||
type LinkType = 'file' | 'index';
|
||||
|
||||
export interface ResultLink {
|
||||
id: string;
|
||||
type: LinkType;
|
||||
title: string;
|
||||
icon: string;
|
||||
description: string;
|
||||
getUrl(params?: any): Promise<string>;
|
||||
canDisplay(params?: any): Promise<boolean>;
|
||||
dataTestSubj?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
fieldStats: FindFileStructureResponse['field_stats'];
|
||||
index: string;
|
||||
|
@ -25,6 +38,7 @@ interface Props {
|
|||
timeFieldName?: string;
|
||||
createIndexPattern: boolean;
|
||||
showFilebeatFlyout(): void;
|
||||
additionalLinks: ResultLink[];
|
||||
}
|
||||
|
||||
interface GlobalState {
|
||||
|
@ -41,6 +55,7 @@ export const ResultsLinks: FC<Props> = ({
|
|||
timeFieldName,
|
||||
createIndexPattern,
|
||||
showFilebeatFlyout,
|
||||
additionalLinks,
|
||||
}) => {
|
||||
const {
|
||||
services: { fileUpload },
|
||||
|
@ -55,6 +70,7 @@ export const ResultsLinks: FC<Props> = ({
|
|||
const [discoverLink, setDiscoverLink] = useState('');
|
||||
const [indexManagementLink, setIndexManagementLink] = useState('');
|
||||
const [indexPatternManagementLink, setIndexPatternManagementLink] = useState('');
|
||||
const [generatedLinks, setGeneratedLinks] = useState<Record<string, string>>({});
|
||||
|
||||
const {
|
||||
services: {
|
||||
|
@ -100,6 +116,23 @@ export const ResultsLinks: FC<Props> = ({
|
|||
|
||||
getDiscoverUrl();
|
||||
|
||||
Promise.all(
|
||||
additionalLinks.map(async ({ canDisplay, getUrl }) => {
|
||||
if ((await canDisplay({ indexPatternId })) === false) {
|
||||
return null;
|
||||
}
|
||||
return getUrl({ globalState, indexPatternId });
|
||||
})
|
||||
).then((urls) => {
|
||||
const linksById = urls.reduce((acc, url, i) => {
|
||||
if (url !== null) {
|
||||
acc[additionalLinks[i].id] = url;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
setGeneratedLinks(linksById);
|
||||
});
|
||||
|
||||
if (!unmounted) {
|
||||
setIndexManagementLink(
|
||||
getUrlForApp('management', { path: '/data/index_management/indices' })
|
||||
|
@ -231,6 +264,19 @@ export const ResultsLinks: FC<Props> = ({
|
|||
onClick={showFilebeatFlyout}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{additionalLinks
|
||||
.filter(({ id }) => generatedLinks[id] !== undefined)
|
||||
.map((link) => (
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type={link.icon} />}
|
||||
data-test-subj="fileDataVisLink"
|
||||
title={link.title}
|
||||
description={link.description}
|
||||
href={generatedLinks[link.id]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -372,6 +372,7 @@ export class FileDataVisualizerView extends Component {
|
|||
hideBottomBar={this.hideBottomBar}
|
||||
savedObjectsClient={this.savedObjectsClient}
|
||||
fileUpload={this.props.fileUpload}
|
||||
resultsLinks={this.props.resultsLinks}
|
||||
/>
|
||||
|
||||
{bottomBarVisible && (
|
||||
|
|
|
@ -591,6 +591,7 @@ export class ImportView extends Component {
|
|||
timeFieldName={timeFieldName}
|
||||
createIndexPattern={createIndexPattern}
|
||||
showFilebeatFlyout={this.showFilebeatFlyout}
|
||||
additionalLinks={this.props.resultsLinks ?? []}
|
||||
/>
|
||||
|
||||
{isFilebeatFlyoutVisible && (
|
||||
|
|
|
@ -11,9 +11,14 @@ import { getCoreStart, getPluginsStart } from '../../kibana_services';
|
|||
|
||||
// @ts-ignore
|
||||
import { FileDataVisualizerView } from './components/file_data_visualizer_view/index';
|
||||
import { ResultLink } from '../common/components/results_links';
|
||||
|
||||
interface Props {
|
||||
additionalLinks?: ResultLink[];
|
||||
}
|
||||
|
||||
export type FileDataVisualizerSpec = typeof FileDataVisualizer;
|
||||
export const FileDataVisualizer: FC = () => {
|
||||
export const FileDataVisualizer: FC<Props> = ({ additionalLinks }) => {
|
||||
const coreStart = getCoreStart();
|
||||
const { data, maps, embeddable, share, security, fileUpload } = getPluginsStart();
|
||||
const services = {
|
||||
|
@ -33,6 +38,7 @@ export const FileDataVisualizer: FC = () => {
|
|||
savedObjectsClient={coreStart.savedObjects.client}
|
||||
http={coreStart.http}
|
||||
fileUpload={fileUpload}
|
||||
resultsLinks={additionalLinks}
|
||||
/>
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
|
|
|
@ -18,18 +18,26 @@ import type { IndexPattern } from '../../../../../../../../src/plugins/data/comm
|
|||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||
import { useUrlState } from '../../../common/util/url_state';
|
||||
import { LinkCard } from '../../../common/components/link_card';
|
||||
import { ResultLink } from '../../../common/components/results_links';
|
||||
|
||||
interface Props {
|
||||
indexPattern: IndexPattern;
|
||||
searchString?: string | { [key: string]: any };
|
||||
searchQueryLanguage?: string;
|
||||
additionalLinks: ResultLink[];
|
||||
}
|
||||
|
||||
// @todo: Add back create job card in a follow up PR
|
||||
export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQueryLanguage }) => {
|
||||
export const ActionsPanel: FC<Props> = ({
|
||||
indexPattern,
|
||||
searchString,
|
||||
searchQueryLanguage,
|
||||
additionalLinks,
|
||||
}) => {
|
||||
const [globalState] = useUrlState('_g');
|
||||
|
||||
const [discoverLink, setDiscoverLink] = useState('');
|
||||
const [generatedLinks, setGeneratedLinks] = useState<Record<string, string>>({});
|
||||
|
||||
const {
|
||||
services: {
|
||||
application: { capabilities },
|
||||
|
@ -76,17 +84,56 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
|
|||
}
|
||||
};
|
||||
|
||||
Promise.all(
|
||||
additionalLinks.map(async ({ canDisplay, getUrl }) => {
|
||||
if ((await canDisplay({ indexPatternId })) === false) {
|
||||
return null;
|
||||
}
|
||||
return getUrl({ globalState, indexPatternId });
|
||||
})
|
||||
).then((urls) => {
|
||||
const linksById = urls.reduce((acc, url, i) => {
|
||||
if (url !== null) {
|
||||
acc[additionalLinks[i].id] = url;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
setGeneratedLinks(linksById);
|
||||
});
|
||||
|
||||
getDiscoverUrl();
|
||||
return () => {
|
||||
unmounted = true;
|
||||
};
|
||||
}, [indexPattern, searchString, searchQueryLanguage, globalState, capabilities, getUrlGenerator]);
|
||||
}, [
|
||||
indexPattern,
|
||||
searchString,
|
||||
searchQueryLanguage,
|
||||
globalState,
|
||||
capabilities,
|
||||
getUrlGenerator,
|
||||
additionalLinks,
|
||||
]);
|
||||
|
||||
// Note we use display:none for the DataRecognizer section as it needs to be
|
||||
// passed the recognizerResults object, and then run the recognizer check which
|
||||
// controls whether the recognizer section is ultimately displayed.
|
||||
return (
|
||||
<div data-test-subj="dataVisualizerActionsPanel">
|
||||
{additionalLinks
|
||||
.filter(({ id }) => generatedLinks[id] !== undefined)
|
||||
.map((link) => (
|
||||
<>
|
||||
<LinkCard
|
||||
href={generatedLinks[link.id]}
|
||||
icon={link.icon}
|
||||
description={link.description}
|
||||
title={link.title}
|
||||
data-test-subj={link.dataTestSubj}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
))}
|
||||
{discoverLink && (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
|
|
|
@ -67,6 +67,7 @@ import { HelpMenu } from '../../../common/components/help_menu';
|
|||
import { TimeBuckets } from '../../services/time_buckets';
|
||||
import { extractSearchData } from '../../utils/saved_search_utils';
|
||||
import { DataVisualizerIndexPatternManagement } from '../index_pattern_management';
|
||||
import { ResultLink } from '../../../common/components/results_links';
|
||||
|
||||
interface DataVisualizerPageState {
|
||||
overallStats: OverallStats;
|
||||
|
@ -120,6 +121,7 @@ export const getDefaultDataVisualizerListState = (): Required<DataVisualizerInde
|
|||
export interface IndexDataVisualizerViewProps {
|
||||
currentIndexPattern: IndexPattern;
|
||||
currentSavedSearch: SavedSearchSavedObject | null;
|
||||
additionalLinks?: ResultLink[];
|
||||
}
|
||||
const restorableDefaults = getDefaultDataVisualizerListState();
|
||||
|
||||
|
@ -138,7 +140,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
|
|||
dataVisualizerProps.currentSavedSearch
|
||||
);
|
||||
|
||||
const { currentIndexPattern } = dataVisualizerProps;
|
||||
const { currentIndexPattern, additionalLinks } = dataVisualizerProps;
|
||||
|
||||
useEffect(() => {
|
||||
if (dataVisualizerProps?.currentSavedSearch !== undefined) {
|
||||
|
@ -886,6 +888,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
|
|||
indexPattern={currentIndexPattern}
|
||||
searchQueryLanguage={searchQueryLanguage}
|
||||
searchString={searchString}
|
||||
additionalLinks={additionalLinks ?? []}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -30,15 +30,18 @@ import {
|
|||
} from '../common/util/url_state';
|
||||
import { useDataVisualizerKibana } from '../kibana_context';
|
||||
import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns';
|
||||
import { ResultLink } from '../common/components/results_links';
|
||||
|
||||
export type IndexDataVisualizerSpec = typeof IndexDataVisualizer;
|
||||
|
||||
export interface DataVisualizerUrlStateContextProviderProps {
|
||||
IndexDataVisualizerComponent: FC<IndexDataVisualizerViewProps>;
|
||||
additionalLinks: ResultLink[];
|
||||
}
|
||||
|
||||
export const DataVisualizerUrlStateContextProvider: FC<DataVisualizerUrlStateContextProviderProps> = ({
|
||||
IndexDataVisualizerComponent,
|
||||
additionalLinks,
|
||||
}) => {
|
||||
const {
|
||||
services: {
|
||||
|
@ -168,6 +171,7 @@ export const DataVisualizerUrlStateContextProvider: FC<DataVisualizerUrlStateCon
|
|||
<IndexDataVisualizerComponent
|
||||
currentIndexPattern={currentIndexPattern}
|
||||
currentSavedSearch={currentSavedSearch}
|
||||
additionalLinks={additionalLinks}
|
||||
/>
|
||||
) : (
|
||||
<div />
|
||||
|
@ -176,7 +180,7 @@ export const DataVisualizerUrlStateContextProvider: FC<DataVisualizerUrlStateCon
|
|||
);
|
||||
};
|
||||
|
||||
export const IndexDataVisualizer: FC = () => {
|
||||
export const IndexDataVisualizer: FC<{ additionalLinks: ResultLink[] }> = ({ additionalLinks }) => {
|
||||
const coreStart = getCoreStart();
|
||||
const {
|
||||
data,
|
||||
|
@ -204,6 +208,7 @@ export const IndexDataVisualizer: FC = () => {
|
|||
<KibanaContextProvider services={{ ...services }}>
|
||||
<DataVisualizerUrlStateContextProvider
|
||||
IndexDataVisualizerComponent={IndexDataVisualizerView}
|
||||
additionalLinks={additionalLinks}
|
||||
/>
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
|
|
|
@ -13,4 +13,9 @@ export function plugin() {
|
|||
|
||||
export { DataVisualizerPluginStart } from './plugin';
|
||||
|
||||
export type { IndexDataVisualizerViewProps } from './application';
|
||||
export type {
|
||||
FileDataVisualizerSpec,
|
||||
IndexDataVisualizerSpec,
|
||||
IndexDataVisualizerViewProps,
|
||||
} from './application';
|
||||
export type { ResultLink } from './application/common/components/results_links';
|
||||
|
|
|
@ -5,22 +5,99 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FC, Fragment, useState, useEffect } from 'react';
|
||||
|
||||
import React, { FC, Fragment, useState, useEffect, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useTimefilter } from '../../contexts/kibana';
|
||||
import { NavigationMenu } from '../../components/navigation_menu';
|
||||
import { HelpMenu } from '../../components/help_menu';
|
||||
import { useMlKibana } from '../../contexts/kibana';
|
||||
import { useMlKibana, useMlUrlGenerator } from '../../contexts/kibana';
|
||||
|
||||
import { ML_PAGES } from '../../../../common/constants/ml_url_generator';
|
||||
import { isFullLicense } from '../../license';
|
||||
import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
import type { ResultLink, FileDataVisualizerSpec } from '../../../../../data_visualizer/public';
|
||||
|
||||
interface GetUrlParams {
|
||||
indexPatternId: string;
|
||||
globalState: any;
|
||||
}
|
||||
|
||||
export const FileDataVisualizerPage: FC = () => {
|
||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||
const {
|
||||
services: { docLinks, dataVisualizer },
|
||||
services: {
|
||||
docLinks,
|
||||
dataVisualizer,
|
||||
data: {
|
||||
indexPatterns: { get: getIndexPattern },
|
||||
},
|
||||
},
|
||||
} = useMlKibana();
|
||||
const [FileDataVisualizer, setFileDataVisualizer] = useState<FC<{}> | null>(null);
|
||||
const mlUrlGenerator = useMlUrlGenerator();
|
||||
getMlNodeCount();
|
||||
|
||||
const [FileDataVisualizer, setFileDataVisualizer] = useState<FileDataVisualizerSpec | null>(null);
|
||||
|
||||
const links: ResultLink[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'create_ml_job',
|
||||
title: i18n.translate('xpack.ml.fileDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
||||
defaultMessage: 'Create new ML job',
|
||||
}),
|
||||
description: '',
|
||||
icon: 'machineLearningApp',
|
||||
type: 'file',
|
||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
||||
return await mlUrlGenerator.createUrl({
|
||||
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE,
|
||||
pageState: {
|
||||
index: indexPatternId,
|
||||
globalState,
|
||||
},
|
||||
});
|
||||
},
|
||||
canDisplay: async ({ indexPatternId }) => {
|
||||
try {
|
||||
const { timeFieldName } = await getIndexPattern(indexPatternId);
|
||||
return (
|
||||
isFullLicense() &&
|
||||
timeFieldName !== undefined &&
|
||||
checkPermission('canCreateJob') &&
|
||||
mlNodesAvailable()
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'open_in_data_viz',
|
||||
title: i18n.translate('xpack.ml.fileDatavisualizer.actionsPanel.dataframeTitle', {
|
||||
defaultMessage: 'Open in Data Visualizer',
|
||||
}),
|
||||
description: '',
|
||||
icon: 'dataVisualizer',
|
||||
type: 'file',
|
||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
||||
return await mlUrlGenerator.createUrl({
|
||||
page: ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER,
|
||||
pageState: {
|
||||
index: indexPatternId,
|
||||
globalState,
|
||||
},
|
||||
});
|
||||
},
|
||||
canDisplay: async () => true,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (dataVisualizer !== undefined) {
|
||||
getMlNodeCount();
|
||||
const { getFileDataVisualizerComponent } = dataVisualizer;
|
||||
getFileDataVisualizerComponent().then(setFileDataVisualizer);
|
||||
}
|
||||
|
@ -29,7 +106,7 @@ export const FileDataVisualizerPage: FC = () => {
|
|||
return (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
{FileDataVisualizer}
|
||||
{FileDataVisualizer !== null && <FileDataVisualizer additionalLinks={links} />}
|
||||
<HelpMenu docLink={docLinks.links.ml.guide} />
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -5,20 +5,40 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FC, Fragment, useEffect, useState } from 'react';
|
||||
import { useMlKibana, useTimefilter } from '../../contexts/kibana';
|
||||
import React, { FC, Fragment, useEffect, useState, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useMlKibana, useTimefilter, useMlUrlGenerator } from '../../contexts/kibana';
|
||||
import { NavigationMenu } from '../../components/navigation_menu';
|
||||
import { HelpMenu } from '../../components/help_menu';
|
||||
import type { IndexDataVisualizerViewProps } from '../../../../../data_visualizer/public';
|
||||
import { ML_PAGES } from '../../../../common/constants/ml_url_generator';
|
||||
import { isFullLicense } from '../../license';
|
||||
import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||
|
||||
import type { ResultLink, IndexDataVisualizerSpec } from '../../../../../data_visualizer/public';
|
||||
|
||||
interface GetUrlParams {
|
||||
indexPatternId: string;
|
||||
globalState: any;
|
||||
}
|
||||
|
||||
export const IndexDataVisualizerPage: FC = () => {
|
||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||
const {
|
||||
services: { docLinks, dataVisualizer },
|
||||
services: {
|
||||
docLinks,
|
||||
dataVisualizer,
|
||||
data: {
|
||||
indexPatterns: { get: getIndexPattern },
|
||||
},
|
||||
},
|
||||
} = useMlKibana();
|
||||
const [
|
||||
IndexDataVisualizer,
|
||||
setIndexDataVisualizer,
|
||||
] = useState<FC<IndexDataVisualizerViewProps> | null>(null);
|
||||
const mlUrlGenerator = useMlUrlGenerator();
|
||||
getMlNodeCount();
|
||||
|
||||
const [IndexDataVisualizer, setIndexDataVisualizer] = useState<IndexDataVisualizerSpec | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (dataVisualizer !== undefined) {
|
||||
|
@ -26,10 +46,84 @@ export const IndexDataVisualizerPage: FC = () => {
|
|||
getIndexDataVisualizerComponent().then(setIndexDataVisualizer);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const links: ResultLink[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'create_ml_ad_job',
|
||||
title: i18n.translate('xpack.ml.indexDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
||||
defaultMessage: 'Advanced anomaly detection',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.ml.indexDatavisualizer.actionsPanel.anomalyDetectionDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Create a job with the full range of options for more advanced use cases.',
|
||||
}
|
||||
),
|
||||
icon: 'createAdvancedJob',
|
||||
type: 'file',
|
||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
||||
return await mlUrlGenerator.createUrl({
|
||||
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED,
|
||||
pageState: {
|
||||
index: indexPatternId,
|
||||
globalState,
|
||||
},
|
||||
});
|
||||
},
|
||||
canDisplay: async ({ indexPatternId }) => {
|
||||
try {
|
||||
const { timeFieldName } = await getIndexPattern(indexPatternId);
|
||||
return (
|
||||
isFullLicense() &&
|
||||
timeFieldName !== undefined &&
|
||||
checkPermission('canCreateJob') &&
|
||||
mlNodesAvailable()
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
dataTestSubj: 'dataVisualizerCreateAdvancedJobCard',
|
||||
},
|
||||
{
|
||||
id: 'create_ml_dfa_job',
|
||||
title: i18n.translate('xpack.ml.indexDatavisualizer.actionsPanel.dataframeTitle', {
|
||||
defaultMessage: 'Data frame analytics',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.ml.indexDatavisualizer.actionsPanel.dataframeDescription',
|
||||
{
|
||||
defaultMessage: 'Create outlier detection, regression, or classification analytics.',
|
||||
}
|
||||
),
|
||||
icon: 'classificationJob',
|
||||
type: 'file',
|
||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
||||
return await mlUrlGenerator.createUrl({
|
||||
page: ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB,
|
||||
pageState: {
|
||||
index: indexPatternId,
|
||||
globalState,
|
||||
},
|
||||
});
|
||||
},
|
||||
canDisplay: async () => {
|
||||
return (
|
||||
isFullLicense() && checkPermission('canCreateDataFrameAnalytics') && mlNodesAvailable()
|
||||
);
|
||||
},
|
||||
dataTestSubj: 'dataVisualizerCreateDataFrameAnalyticsCard',
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return IndexDataVisualizer ? (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
{IndexDataVisualizer}
|
||||
{IndexDataVisualizer !== null && <IndexDataVisualizer additionalLinks={links} />}
|
||||
<HelpMenu docLink={docLinks.links.ml.guide} />
|
||||
</Fragment>
|
||||
) : (
|
||||
|
|
|
@ -273,6 +273,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
await ml.testExecution.logTestStep('creates filebeat config');
|
||||
await ml.dataVisualizerFileBased.selectCreateFilebeatConfig();
|
||||
|
||||
await ml.testExecution.logTestStep('closes filebeat config');
|
||||
await ml.dataVisualizerFileBased.closeCreateFilebeatConfig();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,16 +15,21 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
this.tags(['mlqa']);
|
||||
|
||||
const indexPatternName = 'ft_farequote';
|
||||
// @TODO: Re-enable in follow up
|
||||
// const advancedJobWizardDatafeedQuery = `{
|
||||
// "bool": {
|
||||
// "must": [
|
||||
// {
|
||||
// "match_all": {}
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }`; // Note query is not currently passed to the wizard
|
||||
|
||||
const advancedJobWizardDatafeedQuery = JSON.stringify(
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
match_all: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
// Note query is not currently passed to the wizard
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote');
|
||||
|
@ -48,20 +53,19 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(indexPatternName);
|
||||
});
|
||||
|
||||
// @TODO: Re-enable in follow up
|
||||
// it('opens the advanced job wizard', async () => {
|
||||
// await ml.testExecution.logTestStep('displays the actions panel with advanced job card');
|
||||
// await ml.dataVisualizerIndexBased.assertActionsPanelExists();
|
||||
// await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardExists();
|
||||
// await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardExists();
|
||||
//
|
||||
// // Note the search is not currently passed to the wizard, just the index.
|
||||
// await ml.testExecution.logTestStep('displays the actions panel with advanced job card');
|
||||
// await ml.dataVisualizerIndexBased.clickCreateAdvancedJobButton();
|
||||
// await ml.jobTypeSelection.assertAdvancedJobWizardOpen();
|
||||
// await ml.jobWizardAdvanced.assertDatafeedQueryEditorExists();
|
||||
// await ml.jobWizardAdvanced.assertDatafeedQueryEditorValue(advancedJobWizardDatafeedQuery);
|
||||
// });
|
||||
it('opens the advanced job wizard', async () => {
|
||||
await ml.testExecution.logTestStep('displays the actions panel with advanced job card');
|
||||
await ml.dataVisualizerIndexBased.assertActionsPanelExists();
|
||||
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardExists();
|
||||
await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardExists();
|
||||
|
||||
// Note the search is not currently passed to the wizard, just the index.
|
||||
await ml.testExecution.logTestStep('displays the actions panel with advanced job card');
|
||||
await ml.dataVisualizerIndexBased.clickCreateAdvancedJobButton();
|
||||
await ml.jobTypeSelection.assertAdvancedJobWizardOpen();
|
||||
await ml.jobWizardAdvanced.assertDatafeedQueryEditorExists();
|
||||
await ml.jobWizardAdvanced.assertDatafeedQueryEditorValue(advancedJobWizardDatafeedQuery);
|
||||
});
|
||||
});
|
||||
|
||||
describe('view in discover page action', function () {
|
||||
|
|
|
@ -93,8 +93,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
const ecIndexPattern = 'ft_module_sample_ecommerce';
|
||||
const ecExpectedTotalCount = '287';
|
||||
// @TODO: Re-enable in follow up
|
||||
// const ecExpectedModuleId = 'sample_data_ecommerce';
|
||||
|
||||
const ecExpectedModuleId = 'sample_data_ecommerce';
|
||||
|
||||
const uploadFilePath = path.join(
|
||||
__dirname,
|
||||
|
@ -365,11 +365,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
|
||||
|
||||
// @TODO: Re-enable in follow up
|
||||
// await ml.testExecution.logTestStep('should display job cards');
|
||||
// await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardExists();
|
||||
// await ml.dataVisualizerIndexBased.assertRecognizerCardExists(ecExpectedModuleId);
|
||||
// await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardExists();
|
||||
await ml.testExecution.logTestStep('should display job cards');
|
||||
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardExists();
|
||||
await ml.dataVisualizerIndexBased.assertRecognizerCardExists(ecExpectedModuleId);
|
||||
await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardExists();
|
||||
});
|
||||
|
||||
it('should display elements on File Data Visualizer page correctly', async () => {
|
||||
|
|
|
@ -94,7 +94,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
const ecIndexPattern = 'ft_module_sample_ecommerce';
|
||||
const ecExpectedTotalCount = '287';
|
||||
// const ecExpectedModuleId = 'sample_data_ecommerce';
|
||||
|
||||
const uploadFilePath = path.join(
|
||||
__dirname,
|
||||
|
@ -357,11 +356,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
|
||||
|
||||
// @TODO: Re-enable in follow up
|
||||
// await ml.testExecution.logTestStep('should not display job cards');
|
||||
// await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
// await ml.dataVisualizerIndexBased.assertRecognizerCardNotExists(ecExpectedModuleId);
|
||||
// await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
await ml.testExecution.logTestStep('should not display job cards');
|
||||
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
});
|
||||
|
||||
it('should display elements on File Data Visualizer page correctly', async () => {
|
||||
|
|
|
@ -139,5 +139,10 @@ export function MachineLearningDataVisualizerFileBasedProvider(
|
|||
await testSubjects.click('fileDataVisFilebeatConfigLink');
|
||||
await testSubjects.existOrFail('fileDataVisFilebeatConfigPanel');
|
||||
},
|
||||
|
||||
async closeCreateFilebeatConfig() {
|
||||
await testSubjects.click('fileBeatConfigFlyoutCloseButton');
|
||||
await testSubjects.missingOrFail('fileDataVisFilebeatConfigPanel');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
describe(`(${testUser.user})`, function () {
|
||||
const ecIndexPattern = 'ft_module_sample_ecommerce';
|
||||
const ecExpectedTotalCount = '287';
|
||||
// const ecExpectedModuleId = 'sample_data_ecommerce';
|
||||
|
||||
const uploadFilePath = path.join(
|
||||
__dirname,
|
||||
|
@ -134,11 +133,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
|
||||
|
||||
// @TODO: Re-enable in follow up
|
||||
// await ml.testExecution.logTestStep('should not display job cards');
|
||||
// await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
// await ml.dataVisualizerIndexBased.assertRecognizerCardNotExists(ecExpectedModuleId);
|
||||
// await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
await ml.testExecution.logTestStep('should not display job cards');
|
||||
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
});
|
||||
|
||||
it('should display elements on File Data Visualizer page correctly', async () => {
|
||||
|
|
|
@ -25,8 +25,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
describe(`(${testUser.user})`, function () {
|
||||
const ecIndexPattern = 'ft_module_sample_ecommerce';
|
||||
const ecExpectedTotalCount = '287';
|
||||
// @TODO: Re-enable in follow up
|
||||
// const ecExpectedModuleId = 'sample_data_ecommerce';
|
||||
|
||||
const uploadFilePath = path.join(
|
||||
__dirname,
|
||||
|
@ -135,11 +133,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
|
||||
|
||||
// @TODO: Re-enable in follow up
|
||||
// await ml.testExecution.logTestStep('should not display job cards');
|
||||
// await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
// await ml.dataVisualizerIndexBased.assertRecognizerCardNotExists(ecExpectedModuleId);
|
||||
// await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
await ml.testExecution.logTestStep('should not display job cards');
|
||||
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();
|
||||
await ml.dataVisualizerIndexBased.assertCreateDataFrameAnalyticsCardNotExists();
|
||||
});
|
||||
|
||||
it('should display elements on File Data Visualizer page correctly', async () => {
|
||||
|
|
Loading…
Reference in a new issue