mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[ML] Add recognized modules links for Index data visualizer (#131342)
* [ML] Add dynamic registration of links for both index and file * [ML] Consolidate type imports * [ML] Revert uptime changes * [ML] Fix cards visible when canDisplay is false * [ML] Shorten create job text * [ML] Remove as assertions * [ML] Rename to GetAdditionalLinks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
fe76adbc3a
commit
a632484214
17 changed files with 277 additions and 165 deletions
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, ReactElement } from 'react';
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EuiIcon,
|
EuiIcon,
|
||||||
|
@ -18,8 +18,8 @@ import {
|
||||||
EuiLink,
|
EuiLink,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
|
|
||||||
interface Props {
|
export interface LinkCardProps {
|
||||||
icon: IconType | ReactElement;
|
icon: IconType;
|
||||||
iconAreaLabel?: string;
|
iconAreaLabel?: string;
|
||||||
title: any;
|
title: any;
|
||||||
description: any;
|
description: any;
|
||||||
|
@ -31,7 +31,7 @@ interface Props {
|
||||||
|
|
||||||
// Component for rendering a card which links to the Create Job page, displaying an
|
// Component for rendering a card which links to the Create Job page, displaying an
|
||||||
// icon, card title, description and link.
|
// icon, card title, description and link.
|
||||||
export const LinkCard: FC<Props> = ({
|
export const LinkCard: FC<LinkCardProps> = ({
|
||||||
icon,
|
icon,
|
||||||
iconAreaLabel,
|
iconAreaLabel,
|
||||||
title,
|
title,
|
||||||
|
@ -39,7 +39,7 @@ export const LinkCard: FC<Props> = ({
|
||||||
onClick,
|
onClick,
|
||||||
href,
|
href,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
'data-test-subj': dateTestSubj,
|
'data-test-subj': dataTestSubj,
|
||||||
}) => {
|
}) => {
|
||||||
const linkHrefAndOnClickProps = {
|
const linkHrefAndOnClickProps = {
|
||||||
...(href ? { href } : {}),
|
...(href ? { href } : {}),
|
||||||
|
@ -58,7 +58,7 @@ export const LinkCard: FC<Props> = ({
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
}}
|
}}
|
||||||
data-test-subj={dateTestSubj}
|
data-test-subj={dataTestSubj}
|
||||||
color="subdued"
|
color="subdued"
|
||||||
{...linkHrefAndOnClickProps}
|
{...linkHrefAndOnClickProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type { ResultLink } from './results_links';
|
export type { ResultLink, GetAdditionalLinks, GetAdditionalLinksParams } from './results_links';
|
||||||
export { ResultsLinks } from './results_links';
|
export { ResultsLinks } from './results_links';
|
||||||
|
|
|
@ -12,10 +12,23 @@ import { EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui';
|
||||||
import { TimeRange, RefreshInterval } from '@kbn/data-plugin/public';
|
import { TimeRange, RefreshInterval } from '@kbn/data-plugin/public';
|
||||||
import { FindFileStructureResponse } from '@kbn/file-upload-plugin/common';
|
import { FindFileStructureResponse } from '@kbn/file-upload-plugin/common';
|
||||||
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
||||||
|
import { flatten } from 'lodash';
|
||||||
|
import { LinkCardProps } from '../link_card/link_card';
|
||||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||||
|
import { isDefined } from '../../util/is_defined';
|
||||||
|
|
||||||
type LinkType = 'file' | 'index';
|
type LinkType = 'file' | 'index';
|
||||||
|
|
||||||
|
export interface GetAdditionalLinksParams {
|
||||||
|
dataViewId: string;
|
||||||
|
dataViewTitle?: string;
|
||||||
|
globalState?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetAdditionalLinks = Array<
|
||||||
|
(params: GetAdditionalLinksParams) => Promise<ResultLink[] | undefined>
|
||||||
|
>;
|
||||||
|
|
||||||
export interface ResultLink {
|
export interface ResultLink {
|
||||||
id: string;
|
id: string;
|
||||||
type: LinkType;
|
type: LinkType;
|
||||||
|
@ -24,7 +37,7 @@ export interface ResultLink {
|
||||||
description: string;
|
description: string;
|
||||||
getUrl(params?: any): Promise<string>;
|
getUrl(params?: any): Promise<string>;
|
||||||
canDisplay(params?: any): Promise<boolean>;
|
canDisplay(params?: any): Promise<boolean>;
|
||||||
dataTestSubj?: string;
|
'data-test-subj'?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -34,7 +47,7 @@ interface Props {
|
||||||
timeFieldName?: string;
|
timeFieldName?: string;
|
||||||
createDataView: boolean;
|
createDataView: boolean;
|
||||||
showFilebeatFlyout(): void;
|
showFilebeatFlyout(): void;
|
||||||
additionalLinks: ResultLink[];
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GlobalState {
|
interface GlobalState {
|
||||||
|
@ -51,7 +64,7 @@ export const ResultsLinks: FC<Props> = ({
|
||||||
timeFieldName,
|
timeFieldName,
|
||||||
createDataView,
|
createDataView,
|
||||||
showFilebeatFlyout,
|
showFilebeatFlyout,
|
||||||
additionalLinks,
|
getAdditionalLinks,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
services: {
|
services: {
|
||||||
|
@ -70,7 +83,7 @@ export const ResultsLinks: FC<Props> = ({
|
||||||
const [discoverLink, setDiscoverLink] = useState('');
|
const [discoverLink, setDiscoverLink] = useState('');
|
||||||
const [indexManagementLink, setIndexManagementLink] = useState('');
|
const [indexManagementLink, setIndexManagementLink] = useState('');
|
||||||
const [dataViewsManagementLink, setDataViewsManagementLink] = useState('');
|
const [dataViewsManagementLink, setDataViewsManagementLink] = useState('');
|
||||||
const [generatedLinks, setGeneratedLinks] = useState<Record<string, string>>({});
|
const [asyncHrefCards, setAsyncHrefCards] = useState<LinkCardProps[]>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unmounted = false;
|
let unmounted = false;
|
||||||
|
@ -93,22 +106,30 @@ export const ResultsLinks: FC<Props> = ({
|
||||||
|
|
||||||
getDiscoverUrl();
|
getDiscoverUrl();
|
||||||
|
|
||||||
Promise.all(
|
if (Array.isArray(getAdditionalLinks)) {
|
||||||
additionalLinks.map(async ({ canDisplay, getUrl }) => {
|
Promise.all(
|
||||||
if ((await canDisplay({ indexPatternId: dataViewId })) === false) {
|
getAdditionalLinks.map(async (asyncCardGetter) => {
|
||||||
return null;
|
const results = await asyncCardGetter({
|
||||||
}
|
dataViewId,
|
||||||
return getUrl({ globalState, indexPatternId: dataViewId });
|
});
|
||||||
})
|
if (Array.isArray(results)) {
|
||||||
).then((urls) => {
|
return await Promise.all(
|
||||||
const linksById = urls.reduce((acc, url, i) => {
|
results.map(async (c) => ({
|
||||||
if (url !== null) {
|
...c,
|
||||||
acc[additionalLinks[i].id] = url;
|
canDisplay: await c.canDisplay(),
|
||||||
}
|
href: await c.getUrl(),
|
||||||
return acc;
|
}))
|
||||||
}, {} as Record<string, string>);
|
);
|
||||||
setGeneratedLinks(linksById);
|
}
|
||||||
});
|
})
|
||||||
|
).then((cards) => {
|
||||||
|
setAsyncHrefCards(
|
||||||
|
flatten(cards)
|
||||||
|
.filter(isDefined)
|
||||||
|
.filter((d) => d.canDisplay === true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!unmounted) {
|
if (!unmounted) {
|
||||||
setIndexManagementLink(
|
setIndexManagementLink(
|
||||||
|
@ -244,16 +265,15 @@ export const ResultsLinks: FC<Props> = ({
|
||||||
onClick={showFilebeatFlyout}
|
onClick={showFilebeatFlyout}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
{additionalLinks
|
{Array.isArray(asyncHrefCards) &&
|
||||||
.filter(({ id }) => generatedLinks[id] !== undefined)
|
asyncHrefCards.map((link) => (
|
||||||
.map((link) => (
|
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiCard
|
<EuiCard
|
||||||
icon={<EuiIcon size="xxl" type={link.icon} />}
|
icon={<EuiIcon size="xxl" type={link.icon} />}
|
||||||
data-test-subj="fileDataVisLink"
|
data-test-subj="fileDataVisLink"
|
||||||
title={link.title}
|
title={link.title}
|
||||||
description={link.description}
|
description={link.description}
|
||||||
href={generatedLinks[link.id]}
|
href={link.href}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function isDefined<T>(argument: T | undefined | null): argument is T {
|
||||||
|
return argument !== undefined && argument !== null;
|
||||||
|
}
|
|
@ -369,7 +369,7 @@ export class FileDataVisualizerView extends Component {
|
||||||
hideBottomBar={this.hideBottomBar}
|
hideBottomBar={this.hideBottomBar}
|
||||||
savedObjectsClient={this.savedObjectsClient}
|
savedObjectsClient={this.savedObjectsClient}
|
||||||
fileUpload={this.props.fileUpload}
|
fileUpload={this.props.fileUpload}
|
||||||
resultsLinks={this.props.resultsLinks}
|
getAdditionalLinks={this.props.getAdditionalLinks}
|
||||||
capabilities={this.props.capabilities}
|
capabilities={this.props.capabilities}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -585,7 +585,7 @@ export class ImportView extends Component {
|
||||||
timeFieldName={timeFieldName}
|
timeFieldName={timeFieldName}
|
||||||
createDataView={createDataView}
|
createDataView={createDataView}
|
||||||
showFilebeatFlyout={this.showFilebeatFlyout}
|
showFilebeatFlyout={this.showFilebeatFlyout}
|
||||||
additionalLinks={this.props.resultsLinks ?? []}
|
getAdditionalLinks={this.props.getAdditionalLinks ?? []}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isFilebeatFlyoutVisible && (
|
{isFilebeatFlyoutVisible && (
|
||||||
|
|
|
@ -11,14 +11,14 @@ import { getCoreStart, getPluginsStart } from '../../kibana_services';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { FileDataVisualizerView } from './components/file_data_visualizer_view';
|
import { FileDataVisualizerView } from './components/file_data_visualizer_view';
|
||||||
import { ResultLink } from '../common/components/results_links';
|
import { GetAdditionalLinks } from '../common/components/results_links';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
additionalLinks?: ResultLink[];
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FileDataVisualizerSpec = typeof FileDataVisualizer;
|
export type FileDataVisualizerSpec = typeof FileDataVisualizer;
|
||||||
export const FileDataVisualizer: FC<Props> = ({ additionalLinks }) => {
|
export const FileDataVisualizer: FC<Props> = ({ getAdditionalLinks }) => {
|
||||||
const coreStart = getCoreStart();
|
const coreStart = getCoreStart();
|
||||||
const { data, maps, embeddable, discover, share, security, fileUpload, cloud } =
|
const { data, maps, embeddable, discover, share, security, fileUpload, cloud } =
|
||||||
getPluginsStart();
|
getPluginsStart();
|
||||||
|
@ -45,7 +45,7 @@ export const FileDataVisualizer: FC<Props> = ({ additionalLinks }) => {
|
||||||
savedObjectsClient={coreStart.savedObjects.client}
|
savedObjectsClient={coreStart.savedObjects.client}
|
||||||
http={coreStart.http}
|
http={coreStart.http}
|
||||||
fileUpload={fileUpload}
|
fileUpload={fileUpload}
|
||||||
resultsLinks={additionalLinks}
|
getAdditionalLinks={getAdditionalLinks}
|
||||||
capabilities={coreStart.application.capabilities}
|
capabilities={coreStart.application.capabilities}
|
||||||
/>
|
/>
|
||||||
</CloudContext>
|
</CloudContext>
|
||||||
|
|
|
@ -11,28 +11,31 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { EuiSpacer, EuiTitle } from '@elastic/eui';
|
import { EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||||
import { DataView } from '@kbn/data-views-plugin/public';
|
import { DataView } from '@kbn/data-views-plugin/public';
|
||||||
|
import { flatten } from 'lodash';
|
||||||
|
import { LinkCardProps } from '../../../common/components/link_card/link_card';
|
||||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||||
import { useUrlState } from '../../../common/util/url_state';
|
import { useUrlState } from '../../../common/util/url_state';
|
||||||
import { LinkCard } from '../../../common/components/link_card';
|
import { LinkCard } from '../../../common/components/link_card';
|
||||||
import { ResultLink } from '../../../common/components/results_links';
|
import { GetAdditionalLinks } from '../../../common/components/results_links';
|
||||||
|
import { isDefined } from '../../../common/util/is_defined';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dataView: DataView;
|
dataView: DataView;
|
||||||
searchString?: string | { [key: string]: any };
|
searchString?: string | { [key: string]: any };
|
||||||
searchQueryLanguage?: string;
|
searchQueryLanguage?: string;
|
||||||
additionalLinks: ResultLink[];
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionsPanel: FC<Props> = ({
|
export const ActionsPanel: FC<Props> = ({
|
||||||
dataView,
|
dataView,
|
||||||
searchString,
|
searchString,
|
||||||
searchQueryLanguage,
|
searchQueryLanguage,
|
||||||
additionalLinks,
|
getAdditionalLinks,
|
||||||
}) => {
|
}) => {
|
||||||
const [globalState] = useUrlState('_g');
|
const [globalState] = useUrlState('_g');
|
||||||
|
|
||||||
const [discoverLink, setDiscoverLink] = useState('');
|
const [discoverLink, setDiscoverLink] = useState('');
|
||||||
const [generatedLinks, setGeneratedLinks] = useState<Record<string, string>>({});
|
const [asyncHrefCards, setAsyncHrefCards] = useState<LinkCardProps[]>();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
services: {
|
services: {
|
||||||
|
@ -46,6 +49,7 @@ export const ActionsPanel: FC<Props> = ({
|
||||||
let unmounted = false;
|
let unmounted = false;
|
||||||
|
|
||||||
const indexPatternId = dataView.id;
|
const indexPatternId = dataView.id;
|
||||||
|
const indexPatternTitle = dataView.title;
|
||||||
const getDiscoverUrl = async (): Promise<void> => {
|
const getDiscoverUrl = async (): Promise<void> => {
|
||||||
const isDiscoverAvailable = capabilities.discover?.show ?? false;
|
const isDiscoverAvailable = capabilities.discover?.show ?? false;
|
||||||
if (!isDiscoverAvailable) return;
|
if (!isDiscoverAvailable) return;
|
||||||
|
@ -68,24 +72,33 @@ export const ActionsPanel: FC<Props> = ({
|
||||||
setDiscoverLink(discoverUrl);
|
setDiscoverLink(discoverUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
Promise.all(
|
if (Array.isArray(getAdditionalLinks) && indexPatternId !== undefined) {
|
||||||
additionalLinks.map(async ({ canDisplay, getUrl }) => {
|
Promise.all(
|
||||||
if ((await canDisplay({ indexPatternId })) === false) {
|
getAdditionalLinks.map(async (asyncCardGetter) => {
|
||||||
return null;
|
const results = await asyncCardGetter({
|
||||||
}
|
dataViewId: indexPatternId,
|
||||||
return getUrl({ globalState, indexPatternId });
|
dataViewTitle: indexPatternTitle,
|
||||||
})
|
});
|
||||||
).then((urls) => {
|
if (Array.isArray(results)) {
|
||||||
const linksById = urls.reduce((acc, url, i) => {
|
return await Promise.all(
|
||||||
if (url !== null) {
|
results.map(async (c) => ({
|
||||||
acc[additionalLinks[i].id] = url;
|
...c,
|
||||||
}
|
canDisplay: await c.canDisplay(),
|
||||||
return acc;
|
href: await c.getUrl(),
|
||||||
}, {} as Record<string, string>);
|
}))
|
||||||
setGeneratedLinks(linksById);
|
);
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
).then((cards) => {
|
||||||
|
setAsyncHrefCards(
|
||||||
|
flatten(cards)
|
||||||
|
.filter(isDefined)
|
||||||
|
.filter((d) => d.canDisplay === true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
getDiscoverUrl();
|
getDiscoverUrl();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unmounted = true;
|
unmounted = true;
|
||||||
};
|
};
|
||||||
|
@ -96,8 +109,8 @@ export const ActionsPanel: FC<Props> = ({
|
||||||
globalState,
|
globalState,
|
||||||
capabilities,
|
capabilities,
|
||||||
discover,
|
discover,
|
||||||
additionalLinks,
|
|
||||||
data.query,
|
data.query,
|
||||||
|
getAdditionalLinks,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Note we use display:none for the DataRecognizer section as it needs to be
|
// Note we use display:none for the DataRecognizer section as it needs to be
|
||||||
|
@ -105,20 +118,6 @@ export const ActionsPanel: FC<Props> = ({
|
||||||
// controls whether the recognizer section is ultimately displayed.
|
// controls whether the recognizer section is ultimately displayed.
|
||||||
return (
|
return (
|
||||||
<div data-test-subj="dataVisualizerActionsPanel">
|
<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 && (
|
{discoverLink && (
|
||||||
<>
|
<>
|
||||||
<EuiTitle size="s">
|
<EuiTitle size="s">
|
||||||
|
@ -147,8 +146,23 @@ export const ActionsPanel: FC<Props> = ({
|
||||||
}
|
}
|
||||||
data-test-subj="dataVisualizerViewInDiscoverCard"
|
data-test-subj="dataVisualizerViewInDiscoverCard"
|
||||||
/>
|
/>
|
||||||
|
<EuiSpacer size="m" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{Array.isArray(asyncHrefCards) &&
|
||||||
|
asyncHrefCards.map((link) => (
|
||||||
|
<>
|
||||||
|
<LinkCard
|
||||||
|
href={link.href}
|
||||||
|
icon={link.icon}
|
||||||
|
description={link.description}
|
||||||
|
title={link.title}
|
||||||
|
data-test-subj={link['data-test-subj']}
|
||||||
|
/>
|
||||||
|
<EuiSpacer size="m" />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,7 +48,7 @@ import { DatePickerWrapper } from '../../../common/components/date_picker_wrappe
|
||||||
import { HelpMenu } from '../../../common/components/help_menu';
|
import { HelpMenu } from '../../../common/components/help_menu';
|
||||||
import { createMergedEsQuery } from '../../utils/saved_search_utils';
|
import { createMergedEsQuery } from '../../utils/saved_search_utils';
|
||||||
import { DataVisualizerDataViewManagement } from '../data_view_management';
|
import { DataVisualizerDataViewManagement } from '../data_view_management';
|
||||||
import { ResultLink } from '../../../common/components/results_links';
|
import { GetAdditionalLinks } from '../../../common/components/results_links';
|
||||||
import { useDataVisualizerGridData } from '../../hooks/use_data_visualizer_grid_data';
|
import { useDataVisualizerGridData } from '../../hooks/use_data_visualizer_grid_data';
|
||||||
import { DataVisualizerGridInput } from '../../embeddables/grid_embeddable/grid_embeddable';
|
import { DataVisualizerGridInput } from '../../embeddables/grid_embeddable/grid_embeddable';
|
||||||
import './_index.scss';
|
import './_index.scss';
|
||||||
|
@ -110,7 +110,7 @@ export interface IndexDataVisualizerViewProps {
|
||||||
currentDataView: DataView;
|
currentDataView: DataView;
|
||||||
currentSavedSearch: SavedSearchSavedObject | null;
|
currentSavedSearch: SavedSearchSavedObject | null;
|
||||||
currentSessionId?: string;
|
currentSessionId?: string;
|
||||||
additionalLinks?: ResultLink[];
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
}
|
}
|
||||||
const restorableDefaults = getDefaultDataVisualizerListState();
|
const restorableDefaults = getDefaultDataVisualizerListState();
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
|
||||||
dataVisualizerProps.currentSavedSearch
|
dataVisualizerProps.currentSavedSearch
|
||||||
);
|
);
|
||||||
|
|
||||||
const { currentDataView, additionalLinks, currentSessionId } = dataVisualizerProps;
|
const { currentDataView, currentSessionId, getAdditionalLinks } = dataVisualizerProps;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dataVisualizerProps?.currentSavedSearch !== undefined) {
|
if (dataVisualizerProps?.currentSavedSearch !== undefined) {
|
||||||
|
@ -487,7 +487,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
|
||||||
dataView={currentDataView}
|
dataView={currentDataView}
|
||||||
searchQueryLanguage={searchQueryLanguage}
|
searchQueryLanguage={searchQueryLanguage}
|
||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
additionalLinks={additionalLinks ?? []}
|
getAdditionalLinks={getAdditionalLinks}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
|
|
|
@ -29,17 +29,16 @@ import {
|
||||||
isRisonSerializationRequired,
|
isRisonSerializationRequired,
|
||||||
} from '../common/util/url_state';
|
} from '../common/util/url_state';
|
||||||
import { useDataVisualizerKibana } from '../kibana_context';
|
import { useDataVisualizerKibana } from '../kibana_context';
|
||||||
import { ResultLink } from '../common/components/results_links';
|
import { GetAdditionalLinks } from '../common/components/results_links';
|
||||||
import { DATA_VISUALIZER_APP_LOCATOR, IndexDataVisualizerLocatorParams } from './locator';
|
import { DATA_VISUALIZER_APP_LOCATOR, IndexDataVisualizerLocatorParams } from './locator';
|
||||||
import { DATA_VISUALIZER_INDEX_VIEWER } from './constants/index_data_visualizer_viewer';
|
import { DATA_VISUALIZER_INDEX_VIEWER } from './constants/index_data_visualizer_viewer';
|
||||||
import { INDEX_DATA_VISUALIZER_NAME } from '../common/constants';
|
import { INDEX_DATA_VISUALIZER_NAME } from '../common/constants';
|
||||||
|
|
||||||
export type IndexDataVisualizerSpec = typeof IndexDataVisualizer;
|
|
||||||
|
|
||||||
export interface DataVisualizerUrlStateContextProviderProps {
|
export interface DataVisualizerUrlStateContextProviderProps {
|
||||||
IndexDataVisualizerComponent: FC<IndexDataVisualizerViewProps>;
|
IndexDataVisualizerComponent: FC<IndexDataVisualizerViewProps>;
|
||||||
additionalLinks: ResultLink[];
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
}
|
}
|
||||||
|
export type IndexDataVisualizerSpec = typeof IndexDataVisualizer;
|
||||||
|
|
||||||
export const getLocatorParams = (params: {
|
export const getLocatorParams = (params: {
|
||||||
dataViewId?: string;
|
dataViewId?: string;
|
||||||
|
@ -73,7 +72,7 @@ export const getLocatorParams = (params: {
|
||||||
|
|
||||||
export const DataVisualizerUrlStateContextProvider: FC<
|
export const DataVisualizerUrlStateContextProvider: FC<
|
||||||
DataVisualizerUrlStateContextProviderProps
|
DataVisualizerUrlStateContextProviderProps
|
||||||
> = ({ IndexDataVisualizerComponent, additionalLinks }) => {
|
> = ({ IndexDataVisualizerComponent, getAdditionalLinks }) => {
|
||||||
const { services } = useDataVisualizerKibana();
|
const { services } = useDataVisualizerKibana();
|
||||||
const {
|
const {
|
||||||
data: { dataViews, search },
|
data: { dataViews, search },
|
||||||
|
@ -247,8 +246,8 @@ export const DataVisualizerUrlStateContextProvider: FC<
|
||||||
<IndexDataVisualizerComponent
|
<IndexDataVisualizerComponent
|
||||||
currentDataView={currentDataView}
|
currentDataView={currentDataView}
|
||||||
currentSavedSearch={currentSavedSearch}
|
currentSavedSearch={currentSavedSearch}
|
||||||
additionalLinks={additionalLinks}
|
|
||||||
currentSessionId={currentSessionId}
|
currentSessionId={currentSessionId}
|
||||||
|
getAdditionalLinks={getAdditionalLinks}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div />
|
<div />
|
||||||
|
@ -257,7 +256,9 @@ export const DataVisualizerUrlStateContextProvider: FC<
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IndexDataVisualizer: FC<{ additionalLinks: ResultLink[] }> = ({ additionalLinks }) => {
|
export const IndexDataVisualizer: FC<{
|
||||||
|
getAdditionalLinks?: GetAdditionalLinks;
|
||||||
|
}> = ({ getAdditionalLinks }) => {
|
||||||
const coreStart = getCoreStart();
|
const coreStart = getCoreStart();
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
|
@ -294,7 +295,7 @@ export const IndexDataVisualizer: FC<{ additionalLinks: ResultLink[] }> = ({ add
|
||||||
<KibanaContextProvider services={{ ...services }}>
|
<KibanaContextProvider services={{ ...services }}>
|
||||||
<DataVisualizerUrlStateContextProvider
|
<DataVisualizerUrlStateContextProvider
|
||||||
IndexDataVisualizerComponent={IndexDataVisualizerView}
|
IndexDataVisualizerComponent={IndexDataVisualizerView}
|
||||||
additionalLinks={additionalLinks}
|
getAdditionalLinks={getAdditionalLinks}
|
||||||
/>
|
/>
|
||||||
</KibanaContextProvider>
|
</KibanaContextProvider>
|
||||||
</KibanaThemeProvider>
|
</KibanaThemeProvider>
|
||||||
|
|
|
@ -18,4 +18,8 @@ export type {
|
||||||
IndexDataVisualizerSpec,
|
IndexDataVisualizerSpec,
|
||||||
IndexDataVisualizerViewProps,
|
IndexDataVisualizerViewProps,
|
||||||
} from './application';
|
} from './application';
|
||||||
export type { ResultLink } from './application/common/components/results_links';
|
export type {
|
||||||
|
GetAdditionalLinksParams,
|
||||||
|
ResultLink,
|
||||||
|
GetAdditionalLinks,
|
||||||
|
} from './application/common/components/results_links';
|
||||||
|
|
|
@ -38,6 +38,7 @@ export const ML_PAGES = {
|
||||||
*/
|
*/
|
||||||
DATA_VISUALIZER_INDEX_VIEWER: 'jobs/new_job/datavisualizer',
|
DATA_VISUALIZER_INDEX_VIEWER: 'jobs/new_job/datavisualizer',
|
||||||
ANOMALY_DETECTION_CREATE_JOB: `jobs/new_job`,
|
ANOMALY_DETECTION_CREATE_JOB: `jobs/new_job`,
|
||||||
|
ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER: `jobs/new_job/recognize`,
|
||||||
ANOMALY_DETECTION_CREATE_JOB_ADVANCED: `jobs/new_job/advanced`,
|
ANOMALY_DETECTION_CREATE_JOB_ADVANCED: `jobs/new_job/advanced`,
|
||||||
ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: `jobs/new_job/step/job_type`,
|
ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: `jobs/new_job/step/job_type`,
|
||||||
ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: `jobs/new_job/step/index_or_search`,
|
ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: `jobs/new_job/step/index_or_search`,
|
||||||
|
|
|
@ -46,6 +46,7 @@ export interface MlGenericUrlPageState extends MlIndexBasedSearchState {
|
||||||
export type MlGenericUrlState = MLPageState<
|
export type MlGenericUrlState = MLPageState<
|
||||||
| typeof ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER
|
| typeof ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER
|
||||||
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB
|
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB
|
||||||
|
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER
|
||||||
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED
|
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED
|
||||||
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE
|
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE
|
||||||
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX
|
| typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX
|
||||||
|
|
|
@ -39,7 +39,7 @@ export const LinkCard: FC<Props> = ({
|
||||||
onClick,
|
onClick,
|
||||||
href,
|
href,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
'data-test-subj': dateTestSubj,
|
'data-test-subj': dataTestSubj,
|
||||||
}) => {
|
}) => {
|
||||||
const linkHrefAndOnClickProps = {
|
const linkHrefAndOnClickProps = {
|
||||||
...(href ? { href } : {}),
|
...(href ? { href } : {}),
|
||||||
|
@ -58,7 +58,7 @@ export const LinkCard: FC<Props> = ({
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
}}
|
}}
|
||||||
data-test-subj={dateTestSubj}
|
data-test-subj={dataTestSubj}
|
||||||
color="subdued"
|
color="subdued"
|
||||||
{...linkHrefAndOnClickProps}
|
{...linkHrefAndOnClickProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
import React, { FC, Fragment, useState, useEffect, useMemo } from 'react';
|
import React, { FC, Fragment, useState, useEffect, useMemo } from 'react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import type { ResultLink, FileDataVisualizerSpec } from '@kbn/data-visualizer-plugin/public';
|
import type {
|
||||||
|
FileDataVisualizerSpec,
|
||||||
|
GetAdditionalLinksParams,
|
||||||
|
GetAdditionalLinks,
|
||||||
|
} from '@kbn/data-visualizer-plugin/public';
|
||||||
import { useTimefilter } from '../../contexts/kibana';
|
import { useTimefilter } from '../../contexts/kibana';
|
||||||
import { HelpMenu } from '../../components/help_menu';
|
import { HelpMenu } from '../../components/help_menu';
|
||||||
import { useMlKibana, useMlLocator } from '../../contexts/kibana';
|
import { useMlKibana, useMlLocator } from '../../contexts/kibana';
|
||||||
|
@ -19,11 +23,6 @@ import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_
|
||||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||||
import { MlPageHeader } from '../../components/page_header';
|
import { MlPageHeader } from '../../components/page_header';
|
||||||
|
|
||||||
interface GetUrlParams {
|
|
||||||
indexPatternId: string;
|
|
||||||
globalState: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FileDataVisualizerPage: FC = () => {
|
export const FileDataVisualizerPage: FC = () => {
|
||||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||||
const {
|
const {
|
||||||
|
@ -40,60 +39,62 @@ export const FileDataVisualizerPage: FC = () => {
|
||||||
|
|
||||||
const [FileDataVisualizer, setFileDataVisualizer] = useState<FileDataVisualizerSpec | null>(null);
|
const [FileDataVisualizer, setFileDataVisualizer] = useState<FileDataVisualizerSpec | null>(null);
|
||||||
|
|
||||||
const links: ResultLink[] = useMemo(
|
const getAdditionalLinks: GetAdditionalLinks = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
async ({ dataViewId, globalState }: GetAdditionalLinksParams) => [
|
||||||
id: 'create_ml_job',
|
{
|
||||||
title: i18n.translate('xpack.ml.fileDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
id: 'create_ml_job',
|
||||||
defaultMessage: 'Create new ML job',
|
title: i18n.translate('xpack.ml.fileDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
||||||
}),
|
defaultMessage: 'Create ML job',
|
||||||
description: '',
|
}),
|
||||||
icon: 'machineLearningApp',
|
description: '',
|
||||||
type: 'file',
|
icon: 'machineLearningApp',
|
||||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
type: 'file',
|
||||||
return await mlLocator.getUrl({
|
getUrl: async () => {
|
||||||
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE,
|
return await mlLocator.getUrl({
|
||||||
pageState: {
|
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE,
|
||||||
index: indexPatternId,
|
pageState: {
|
||||||
globalState,
|
index: dataViewId,
|
||||||
},
|
globalState,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
canDisplay: async () => {
|
||||||
|
try {
|
||||||
|
const { timeFieldName } = await getDataView(dataViewId);
|
||||||
|
return (
|
||||||
|
isFullLicense() &&
|
||||||
|
timeFieldName !== undefined &&
|
||||||
|
checkPermission('canCreateJob') &&
|
||||||
|
mlNodesAvailable()
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
canDisplay: async ({ indexPatternId }) => {
|
{
|
||||||
try {
|
id: 'open_in_data_viz',
|
||||||
const { timeFieldName } = await getDataView(indexPatternId);
|
title: i18n.translate('xpack.ml.fileDatavisualizer.actionsPanel.dataframeTitle', {
|
||||||
return (
|
defaultMessage: 'Open in Data Visualizer',
|
||||||
isFullLicense() &&
|
}),
|
||||||
timeFieldName !== undefined &&
|
description: '',
|
||||||
checkPermission('canCreateJob') &&
|
icon: 'dataVisualizer',
|
||||||
mlNodesAvailable()
|
type: 'file',
|
||||||
);
|
getUrl: async () => {
|
||||||
} catch (error) {
|
return await mlLocator.getUrl({
|
||||||
return false;
|
page: ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER,
|
||||||
}
|
pageState: {
|
||||||
|
index: dataViewId,
|
||||||
|
globalState,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
canDisplay: async () => dataViewId !== '',
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
{
|
|
||||||
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 mlLocator.getUrl({
|
|
||||||
page: ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER,
|
|
||||||
pageState: {
|
|
||||||
index: indexPatternId,
|
|
||||||
globalState,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
canDisplay: async ({ indexPatternId }) => indexPatternId !== '',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
[]
|
[mlLocator]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -114,7 +115,7 @@ export const FileDataVisualizerPage: FC = () => {
|
||||||
defaultMessage="Data Visualizer"
|
defaultMessage="Data Visualizer"
|
||||||
/>
|
/>
|
||||||
</MlPageHeader>
|
</MlPageHeader>
|
||||||
<FileDataVisualizer additionalLinks={links} />
|
<FileDataVisualizer getAdditionalLinks={getAdditionalLinks} />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<HelpMenu docLink={docLinks.links.ml.guide} />
|
<HelpMenu docLink={docLinks.links.ml.guide} />
|
||||||
|
|
|
@ -5,28 +5,38 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, Fragment, useEffect, useState, useMemo } from 'react';
|
import React, { FC, Fragment, useEffect, useMemo, useState } from 'react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import type { ResultLink, IndexDataVisualizerSpec } from '@kbn/data-visualizer-plugin/public';
|
import type {
|
||||||
|
IndexDataVisualizerSpec,
|
||||||
|
ResultLink,
|
||||||
|
GetAdditionalLinks,
|
||||||
|
GetAdditionalLinksParams,
|
||||||
|
} from '@kbn/data-visualizer-plugin/public';
|
||||||
import { useMlKibana, useTimefilter, useMlLocator } from '../../contexts/kibana';
|
import { useMlKibana, useTimefilter, useMlLocator } from '../../contexts/kibana';
|
||||||
import { HelpMenu } from '../../components/help_menu';
|
import { HelpMenu } from '../../components/help_menu';
|
||||||
import { ML_PAGES } from '../../../../common/constants/locator';
|
import { ML_PAGES } from '../../../../common/constants/locator';
|
||||||
import { isFullLicense } from '../../license';
|
import { isFullLicense } from '../../license';
|
||||||
import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||||
import { checkPermission } from '../../capabilities/check_capabilities';
|
import { checkPermission } from '../../capabilities/check_capabilities';
|
||||||
|
|
||||||
import { MlPageHeader } from '../../components/page_header';
|
import { MlPageHeader } from '../../components/page_header';
|
||||||
|
|
||||||
interface GetUrlParams {
|
interface RecognizerModule {
|
||||||
indexPatternId: string;
|
id: string;
|
||||||
globalState: any;
|
title: string;
|
||||||
|
query: Record<string, object>;
|
||||||
|
description: string;
|
||||||
|
logo: {
|
||||||
|
icon: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IndexDataVisualizerPage: FC = () => {
|
export const IndexDataVisualizerPage: FC = () => {
|
||||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||||
const {
|
const {
|
||||||
services: {
|
services: {
|
||||||
|
http,
|
||||||
docLinks,
|
docLinks,
|
||||||
dataVisualizer,
|
dataVisualizer,
|
||||||
data: {
|
data: {
|
||||||
|
@ -48,8 +58,12 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const links: ResultLink[] = useMemo(
|
const getAsyncMLCards = async ({
|
||||||
() => [
|
dataViewId,
|
||||||
|
dataViewTitle,
|
||||||
|
globalState,
|
||||||
|
}: GetAdditionalLinksParams): Promise<ResultLink[]> => {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
id: 'create_ml_ad_job',
|
id: 'create_ml_ad_job',
|
||||||
title: i18n.translate('xpack.ml.indexDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
title: i18n.translate('xpack.ml.indexDatavisualizer.actionsPanel.anomalyDetectionTitle', {
|
||||||
|
@ -64,18 +78,18 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
),
|
),
|
||||||
icon: 'createAdvancedJob',
|
icon: 'createAdvancedJob',
|
||||||
type: 'file',
|
type: 'file',
|
||||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
getUrl: async () => {
|
||||||
return await mlLocator.getUrl({
|
return await mlLocator.getUrl({
|
||||||
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED,
|
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED,
|
||||||
pageState: {
|
pageState: {
|
||||||
index: indexPatternId,
|
index: dataViewId,
|
||||||
globalState,
|
globalState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
canDisplay: async ({ indexPatternId }) => {
|
canDisplay: async () => {
|
||||||
try {
|
try {
|
||||||
const { timeFieldName } = await getDataView(indexPatternId);
|
const { timeFieldName } = await getDataView(dataViewId);
|
||||||
return (
|
return (
|
||||||
isFullLicense() &&
|
isFullLicense() &&
|
||||||
timeFieldName !== undefined &&
|
timeFieldName !== undefined &&
|
||||||
|
@ -86,7 +100,7 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataTestSubj: 'dataVisualizerCreateAdvancedJobCard',
|
'data-test-subj': 'dataVisualizerCreateAdvancedJobCard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'create_ml_dfa_job',
|
id: 'create_ml_dfa_job',
|
||||||
|
@ -101,11 +115,11 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
),
|
),
|
||||||
icon: 'classificationJob',
|
icon: 'classificationJob',
|
||||||
type: 'file',
|
type: 'file',
|
||||||
getUrl: async ({ indexPatternId, globalState }: GetUrlParams) => {
|
getUrl: async () => {
|
||||||
return await mlLocator.getUrl({
|
return await mlLocator.getUrl({
|
||||||
page: ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB,
|
page: ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB,
|
||||||
pageState: {
|
pageState: {
|
||||||
index: indexPatternId,
|
index: dataViewId,
|
||||||
globalState,
|
globalState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -115,12 +129,57 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
isFullLicense() && checkPermission('canCreateDataFrameAnalytics') && mlNodesAvailable()
|
isFullLicense() && checkPermission('canCreateDataFrameAnalytics') && mlNodesAvailable()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
dataTestSubj: 'dataVisualizerCreateDataFrameAnalyticsCard',
|
'data-test-subj': 'dataVisualizerCreateDataFrameAnalyticsCard',
|
||||||
},
|
},
|
||||||
],
|
];
|
||||||
[]
|
};
|
||||||
);
|
|
||||||
|
|
||||||
|
const getAsyncRecognizedModuleCards = async (params: GetAdditionalLinksParams) => {
|
||||||
|
const { dataViewId, dataViewTitle } = params;
|
||||||
|
const modules = await http.fetch<RecognizerModule[]>(
|
||||||
|
`/api/ml/modules/recognize/${dataViewTitle}`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return modules?.map(
|
||||||
|
(m): ResultLink => ({
|
||||||
|
id: m.id,
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
icon: m.logo.icon,
|
||||||
|
type: 'index',
|
||||||
|
getUrl: async () => {
|
||||||
|
return await mlLocator.getUrl({
|
||||||
|
page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER,
|
||||||
|
pageState: {
|
||||||
|
id: m.id,
|
||||||
|
index: dataViewId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
canDisplay: async () => {
|
||||||
|
try {
|
||||||
|
const { timeFieldName } = await getDataView(dataViewId);
|
||||||
|
return (
|
||||||
|
isFullLicense() &&
|
||||||
|
timeFieldName !== undefined &&
|
||||||
|
checkPermission('canCreateJob') &&
|
||||||
|
mlNodesAvailable()
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'data-test-subj': m.id,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAdditionalLinks: GetAdditionalLinks = useMemo(
|
||||||
|
() => [getAsyncRecognizedModuleCards, getAsyncMLCards],
|
||||||
|
[mlLocator]
|
||||||
|
);
|
||||||
return IndexDataVisualizer ? (
|
return IndexDataVisualizer ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{IndexDataVisualizer !== null ? (
|
{IndexDataVisualizer !== null ? (
|
||||||
|
@ -131,7 +190,7 @@ export const IndexDataVisualizerPage: FC = () => {
|
||||||
defaultMessage="Data Visualizer"
|
defaultMessage="Data Visualizer"
|
||||||
/>
|
/>
|
||||||
</MlPageHeader>
|
</MlPageHeader>
|
||||||
<IndexDataVisualizer additionalLinks={links} />
|
<IndexDataVisualizer getAdditionalLinks={getAdditionalLinks} />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<HelpMenu docLink={docLinks.links.ml.guide} />
|
<HelpMenu docLink={docLinks.links.ml.guide} />
|
||||||
|
|
|
@ -77,6 +77,7 @@ export class MlLocatorDefinition implements LocatorDefinition<MlLocatorParams> {
|
||||||
path = formatTrainedModelsNodesManagementUrl('', params.pageState);
|
path = formatTrainedModelsNodesManagementUrl('', params.pageState);
|
||||||
break;
|
break;
|
||||||
case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB:
|
case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB:
|
||||||
|
case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER:
|
||||||
case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED:
|
case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED:
|
||||||
case ML_PAGES.DATA_VISUALIZER:
|
case ML_PAGES.DATA_VISUALIZER:
|
||||||
case ML_PAGES.DATA_VISUALIZER_FILE:
|
case ML_PAGES.DATA_VISUALIZER_FILE:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue