[ML] Fix import missing range for File Data Visualizer, Discover card visible when disabled, texts (#91352)

This PR fixes several issues related to the Data Visualizer
This commit is contained in:
Quynh Nguyen 2021-02-16 09:05:01 -06:00 committed by GitHub
parent f4714d1667
commit bb653a40ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 118 additions and 76 deletions

View file

@ -582,6 +582,7 @@ export class ImportView extends Component {
<EuiSpacer size="l" />
<ResultsLinks
fieldStats={this.props.results?.field_stats}
index={index}
indexPatternId={indexPatternId}
timeFieldName={timeFieldName}

View file

@ -20,10 +20,12 @@ import {
DISCOVER_APP_URL_GENERATOR,
DiscoverUrlGeneratorState,
} from '../../../../../../../../../src/plugins/discover/public';
import { FindFileStructureResponse } from '../../../../../../common/types/file_datavisualizer';
const RECHECK_DELAY_MS = 3000;
interface Props {
fieldStats: FindFileStructureResponse['field_stats'];
index: string;
indexPatternId: string;
timeFieldName?: string;
@ -32,6 +34,7 @@ interface Props {
}
export const ResultsLinks: FC<Props> = ({
fieldStats,
index,
indexPatternId,
timeFieldName,
@ -55,7 +58,7 @@ export const ResultsLinks: FC<Props> = ({
const {
services: {
application: { getUrlForApp },
application: { getUrlForApp, capabilities },
share: {
urlGenerators: { getUrlGenerator },
},
@ -66,6 +69,11 @@ export const ResultsLinks: FC<Props> = ({
let unmounted = false;
const getDiscoverUrl = async (): Promise<void> => {
const isDiscoverAvailable = capabilities.discover?.show ?? false;
if (!isDiscoverAvailable) {
return;
}
const state: DiscoverUrlGeneratorState = {
indexPatternId,
};
@ -133,7 +141,7 @@ export const ResultsLinks: FC<Props> = ({
return () => {
unmounted = true;
};
}, [indexPatternId, getUrlGenerator]);
}, [indexPatternId, getUrlGenerator, JSON.stringify(globalState)]);
useEffect(() => {
setShowCreateJobLink(checkPermission('canCreateJob') && mlNodesAvailable());
@ -150,6 +158,22 @@ export const ResultsLinks: FC<Props> = ({
setGlobalState(_globalState);
}, [duration]);
useEffect(() => {
// Update the global time range from known timeFieldName if stats is available
if (
fieldStats &&
typeof fieldStats === 'object' &&
timeFieldName !== undefined &&
fieldStats.hasOwnProperty(timeFieldName) &&
fieldStats[timeFieldName].earliest !== undefined &&
fieldStats[timeFieldName].latest !== undefined
) {
setGlobalState({
time: { from: fieldStats[timeFieldName].earliest!, to: fieldStats[timeFieldName].latest! },
});
}
}, [timeFieldName, fieldStats]);
async function updateTimeValues(recheck = true) {
if (timeFieldName !== undefined) {
const { from, to } = await getFullTimeRange(index, timeFieldName);

View file

@ -9,7 +9,7 @@ import React, { FC, useState, useEffect } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { EuiSpacer, EuiText, EuiTitle, EuiFlexGroup } from '@elastic/eui';
import { EuiSpacer, EuiTitle, EuiFlexGroup } from '@elastic/eui';
import { LinkCard } from '../../../../components/link_card';
import { DataRecognizer } from '../../../../components/data_recognizer';
import { ML_PAGES } from '../../../../../../common/constants/ml_url_generator';
@ -35,6 +35,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
const [discoverLink, setDiscoverLink] = useState('');
const {
services: {
application: { capabilities },
share: {
urlGenerators: { getUrlGenerator },
},
@ -66,6 +67,11 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
const indexPatternId = indexPattern.id;
const getDiscoverUrl = async (): Promise<void> => {
const isDiscoverAvailable = capabilities.discover?.show ?? false;
if (!isDiscoverAvailable) {
return;
}
const state: DiscoverUrlGeneratorState = {
indexPatternId,
};
@ -110,7 +116,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
<h2>
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.createJobTitle"
defaultMessage="Create Job"
defaultMessage="Create job"
/>
</h2>
</EuiTitle>
@ -118,14 +124,6 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
{showCreateAnomalyDetectionJob && (
<>
<div hidden={recognizerResultsCount === 0}>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription"
defaultMessage="Select known configurations for recognized data:"
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="l" responsive={true} wrap={true}>
<DataRecognizer
@ -136,26 +134,18 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
</EuiFlexGroup>
<EuiSpacer size="l" />
</div>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.createJobDescription"
defaultMessage="Use the Advanced job wizard to create a job to find anomalies in this data:"
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<LinkCard
href={createJobLink}
icon="createAdvancedJob"
title={i18n.translate('xpack.ml.datavisualizer.actionsPanel.advancedTitle', {
defaultMessage: 'Advanced',
defaultMessage: 'Advanced anomaly detection',
})}
description={i18n.translate(
'xpack.ml.datavisualizer.actionsPanel.advancedDescription',
{
defaultMessage:
'Create a job with the full range of options for more advanced use cases',
'Create a job with the full range of options for more advanced use cases.',
}
)}
data-test-subj="mlDataVisualizerCreateAdvancedJobCard"
@ -167,14 +157,6 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
)}
{mlAvailable && indexPattern.id !== undefined && createDataFrameAnalyticsLink && (
<>
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.createDataFrameAnalyticsDescription"
defaultMessage="Use the Data Frame Analytics wizard to perform analyses of your data:"
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<LinkCard
href={createDataFrameAnalyticsLink}
@ -182,13 +164,14 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
description={i18n.translate(
'xpack.ml.datavisualizer.actionsPanel.dataframeTypesDescription',
{
defaultMessage: 'Create outlier detection, regression, or classification analytics',
defaultMessage:
'Create outlier detection, regression, or classification analytics.',
}
)}
title={
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.dataframeAnalyticsTitle"
defaultMessage="Data Frame Analytics"
defaultMessage="Data frame analytics"
/>
}
data-test-subj="mlDataVisualizerCreateDataFrameAnalyticsCard"
@ -203,7 +186,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
<h2>
<FormattedMessage
id="xpack.ml.datavisualizer.actionsPanel.exploreTitle"
defaultMessage="Explore"
defaultMessage="Explore your data"
/>
</h2>
</EuiTitle>
@ -214,7 +197,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern, searchString, searchQuer
description={i18n.translate(
'xpack.ml.datavisualizer.actionsPanel.viewIndexInDiscoverDescription',
{
defaultMessage: 'Explore index in Discover',
defaultMessage: 'Explore the documents in your index.',
}
)}
title={

View file

@ -12872,9 +12872,7 @@
"xpack.ml.dataGridChart.topCategoriesLegend": "上位 {maxChartColumns}/{cardinality} カテゴリ",
"xpack.ml.datavisualizer.actionsPanel.advancedDescription": "より高度なユースケースでは、ジョブの作成にすべてのオプションを使用します",
"xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高度な設定",
"xpack.ml.datavisualizer.actionsPanel.createJobDescription": "高度なジョブウィザードでジョブを作成し、このデータの異常を検出します:",
"xpack.ml.datavisualizer.actionsPanel.createJobTitle": "ジョブの作成",
"xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription": "認識されたデータの既知の構成を選択します:",
"xpack.ml.datavisualizer.dataGrid.collapseDetailsForAllAriaLabel": "すべてのフィールドの詳細を折りたたむ",
"xpack.ml.datavisualizer.dataGrid.distinctValuesColumnName": "固有の値",
"xpack.ml.datavisualizer.dataGrid.distributionsColumnName": "分布",

View file

@ -12901,9 +12901,7 @@
"xpack.ml.dataGridChart.topCategoriesLegend": "{cardinality} 个类别中的排名前 {maxChartColumns} 个",
"xpack.ml.datavisualizer.actionsPanel.advancedDescription": "使用全部选项为更高级的用例创建作业",
"xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高级",
"xpack.ml.datavisualizer.actionsPanel.createJobDescription": "使用“高级作业”向导创建作业,以查找此数据中的异常:",
"xpack.ml.datavisualizer.actionsPanel.createJobTitle": "创建作业",
"xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription": "选择已识别数据的已知配置:",
"xpack.ml.datavisualizer.dataGrid.collapseDetailsForAllAriaLabel": "收起所有字段的详细信息",
"xpack.ml.datavisualizer.dataGrid.distinctValuesColumnName": "不同值",
"xpack.ml.datavisualizer.dataGrid.distributionsColumnName": "分布",

View file

@ -15,16 +15,19 @@ export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const ml = getService('ml');
const testUsers = [USER.ML_POWERUSER, USER.ML_POWERUSER_SPACES];
const testUsers = [
{ user: USER.ML_POWERUSER, discoverAvailable: true },
{ user: USER.ML_POWERUSER_SPACES, discoverAvailable: false },
];
describe('for user with full ML access', function () {
this.tags(['skipFirefox', 'mlqa']);
describe('with no data loaded', function () {
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
await ml.api.cleanMlIndices();
});
@ -153,10 +156,10 @@ export default function ({ getService }: FtrProviderContext) {
await ml.api.deleteFilter(filterId);
});
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {
@ -358,10 +361,12 @@ export default function ({ getService }: FtrProviderContext) {
await ml.dataVisualizerIndexBased.assertDataVisualizerTableExist();
await ml.testExecution.logTestStep(
'should display the actions panel with Discover card'
`should display the actions panel ${
testUser.discoverAvailable ? 'with' : 'without'
} Discover card`
);
await ml.dataVisualizerIndexBased.assertActionsPanelExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCardExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
await ml.testExecution.logTestStep('should display job cards');
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardExists();

View file

@ -13,15 +13,18 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'error']);
const ml = getService('ml');
const testUsers = [USER.ML_UNAUTHORIZED, USER.ML_UNAUTHORIZED_SPACES];
const testUsers = [
{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true },
{ user: USER.ML_UNAUTHORIZED_SPACES, discoverAvailable: true },
];
describe('for user with no ML access', function () {
this.tags(['skipFirefox', 'mlqa']);
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {

View file

@ -15,16 +15,19 @@ export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const ml = getService('ml');
const testUsers = [USER.ML_VIEWER, USER.ML_VIEWER_SPACES];
const testUsers = [
{ user: USER.ML_VIEWER, discoverAvailable: true },
{ user: USER.ML_VIEWER_SPACES, discoverAvailable: false },
];
describe('for user with read ML access', function () {
this.tags(['skipFirefox', 'mlqa']);
describe('with no data loaded', function () {
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
await ml.api.cleanMlIndices();
});
@ -154,10 +157,10 @@ export default function ({ getService }: FtrProviderContext) {
await ml.api.deleteFilter(filterId);
});
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {
@ -351,10 +354,12 @@ export default function ({ getService }: FtrProviderContext) {
await ml.dataVisualizerIndexBased.assertDataVisualizerTableExist();
await ml.testExecution.logTestStep(
'should display the actions panel with Discover card'
`should display the actions panel ${
testUser.discoverAvailable ? 'with' : 'without'
} Discover card`
);
await ml.dataVisualizerIndexBased.assertActionsPanelExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCardExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
await ml.testExecution.logTestStep('should not display job cards');
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();

View file

@ -161,6 +161,14 @@ export function MachineLearningDataVisualizerIndexBasedProvider({
await testSubjects.missingOrFail('mlDataVisualizerCreateDataFrameAnalyticsCard');
},
async assertViewInDiscoverCard(shouldExist: boolean) {
if (shouldExist) {
await this.assertViewInDiscoverCardExists();
} else {
await this.assertViewInDiscoverCardNotExists();
}
},
async assertViewInDiscoverCardExists() {
await testSubjects.existOrFail('mlDataVisualizerViewInDiscoverCard');
},

View file

@ -15,11 +15,14 @@ export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const ml = getService('ml');
const testUsers = [USER.ML_POWERUSER, USER.ML_POWERUSER_SPACES];
const testUsers = [
{ user: USER.ML_POWERUSER, discoverAvailable: true },
{ user: USER.ML_POWERUSER_SPACES, discoverAvailable: false },
];
describe('for user with full ML access', function () {
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
const ecIndexPattern = 'ft_module_sample_ecommerce';
const ecExpectedTotalCount = '287';
const ecExpectedModuleId = 'sample_data_ecommerce';
@ -45,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) {
await esArchiver.loadIfNeeded('ml/module_sample_ecommerce');
await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date');
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {
@ -127,9 +130,13 @@ export default function ({ getService }: FtrProviderContext) {
await ml.testExecution.logTestStep('should display the data visualizer table');
await ml.dataVisualizerIndexBased.assertDataVisualizerTableExist();
await ml.testExecution.logTestStep('should display the actions panel with Discover card');
await ml.testExecution.logTestStep(
`should display the actions panel ${
testUser.discoverAvailable ? 'with' : 'without'
} Discover card`
);
await ml.dataVisualizerIndexBased.assertActionsPanelExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCardExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
await ml.testExecution.logTestStep('should not display job cards');
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();

View file

@ -13,13 +13,16 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'error']);
const ml = getService('ml');
const testUsers = [USER.ML_UNAUTHORIZED, USER.ML_UNAUTHORIZED_SPACES];
const testUsers = [
{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true },
{ user: USER.ML_UNAUTHORIZED_SPACES, discoverAvailable: true },
];
describe('for user with no ML access', function () {
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
before(async () => {
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {

View file

@ -15,11 +15,14 @@ export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const ml = getService('ml');
const testUsers = [USER.ML_VIEWER, USER.ML_VIEWER_SPACES];
const testUsers = [
{ user: USER.ML_VIEWER, discoverAvailable: true },
{ user: USER.ML_VIEWER_SPACES, discoverAvailable: false },
];
describe('for user with read ML access', function () {
for (const user of testUsers) {
describe(`(${user})`, function () {
for (const testUser of testUsers) {
describe(`(${testUser.user})`, function () {
const ecIndexPattern = 'ft_module_sample_ecommerce';
const ecExpectedTotalCount = '287';
const ecExpectedModuleId = 'sample_data_ecommerce';
@ -45,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) {
await esArchiver.loadIfNeeded('ml/module_sample_ecommerce');
await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date');
await ml.securityUI.loginAs(user);
await ml.securityUI.loginAs(testUser.user);
});
after(async () => {
@ -127,9 +130,13 @@ export default function ({ getService }: FtrProviderContext) {
await ml.testExecution.logTestStep('should display the data visualizer table');
await ml.dataVisualizerIndexBased.assertDataVisualizerTableExist();
await ml.testExecution.logTestStep('should display the actions panel with Discover card');
await ml.testExecution.logTestStep(
`should display the actions panel ${
testUser.discoverAvailable ? 'with' : 'without'
} Discover card`
);
await ml.dataVisualizerIndexBased.assertActionsPanelExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCardExists();
await ml.dataVisualizerIndexBased.assertViewInDiscoverCard(testUser.discoverAvailable);
await ml.testExecution.logTestStep('should not display job cards');
await ml.dataVisualizerIndexBased.assertCreateAdvancedJobCardNotExists();