Skip to content

Commit

Permalink
[Logs UI] Improve Analysis onboarding experience (#44188)
Browse files Browse the repository at this point in the history
* Improve the initial first use / first render of results screen

* Sets the x-axis domain to the time range rather than the min and max of the data points provided
  • Loading branch information
Kerry350 committed Aug 28, 2019
1 parent 769bb65 commit 1f98213
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export const timeRangeRT = rt.type({
startTime: rt.number,
endTime: rt.number,
});

export type TimeRange = rt.TypeOf<typeof timeRangeRT>;
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const useLogAnalysisJobs = ({
timeField: string;
}) => {
const [jobStatus, setJobStatus] = useState<AllJobStatuses>(getInitialJobStatuses());
const [hasCompletedSetup, setHasCompletedSetup] = useState<boolean>(false);

const [setupMlModuleRequest, setupMlModule] = useTrackedPromise(
{
Expand Down Expand Up @@ -78,6 +79,8 @@ export const useLogAnalysisJobs = ({
: 'failed'
: 'failed',
}));

setHasCompletedSetup(true);
},
},
[indexPattern, spaceId, sourceId]
Expand Down Expand Up @@ -139,6 +142,7 @@ export const useLogAnalysisJobs = ({
setupMlModuleRequest,
isSettingUpMlModule,
didSetupFail,
hasCompletedSetup,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiSpacer } from '@elastic/eui';

export const FirstUseCallout = () => {
return (
<>
<EuiCallOut
color="success"
title={i18n.translate('xpack.infra.logs.logsAnalysisResults.onboardingSuccessTitle', {
defaultMessage: 'Success!',
})}
>
<p>
{i18n.translate('xpack.infra.logs.logsAnalysisResults.onboardingSuccessContent', {
defaultMessage:
'Please allow a few minutes for our machine learning robots to begin collecting data.',
})}
</p>
</EuiCallOut>
<EuiSpacer />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const AnalysisPage = () => {
setupMlModule,
isSettingUpMlModule,
didSetupFail,
hasCompletedSetup,
} = useLogAnalysisJobs({
indexPattern: source ? source.configuration.logAlias : '',
sourceId,
Expand Down Expand Up @@ -56,7 +57,7 @@ export const AnalysisPage = () => {
indexPattern={source ? source.configuration.logAlias : ''}
/>
) : (
<AnalysisResultsContent sourceId={sourceId} />
<AnalysisResultsContent sourceId={sourceId} isFirstUse={hasCompletedSetup} />
)}
</ColumnarPage>
</AnalysisPageProviders>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useLogAnalysisResults } from '../../../containers/logs/log_analysis';
import { useLogAnalysisResultsUrlState } from '../../../containers/logs/log_analysis';
import { LoadingPage } from '../../../components/loading_page';
import { LogRateResults } from './sections/log_rate';
import { FirstUseCallout } from './first_use';

const DATE_PICKER_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSZ';

Expand All @@ -40,7 +41,13 @@ const getLoadingState = () => {
);
};

export const AnalysisResultsContent = ({ sourceId }: { sourceId: string }) => {
export const AnalysisResultsContent = ({
sourceId,
isFirstUse,
}: {
sourceId: string;
isFirstUse: boolean;
}) => {
useTrackPageview({ app: 'infra_logs', path: 'analysis_results' });
useTrackPageview({ app: 'infra_logs', path: 'analysis_results', delay: 15000 });

Expand Down Expand Up @@ -87,6 +94,9 @@ export const AnalysisResultsContent = ({ sourceId }: { sourceId: string }) => {
endTime: timeRange.endTime,
bucketDuration,
});
const hasResults = useMemo(() => logEntryRate && logEntryRate.histogramBuckets.length > 0, [
logEntryRate,
]);
const handleTimeRangeChange = useCallback(
({ start, end }: { start: string; end: string }) => {
const parsedStart = dateMath.parse(start);
Expand Down Expand Up @@ -180,7 +190,12 @@ export const AnalysisResultsContent = ({ sourceId }: { sourceId: string }) => {
<EuiPageBody>
<EuiPageContent>
<EuiPageContentBody>
<LogRateResults isLoading={isLoading} results={logEntryRate} />
{isFirstUse && !hasResults ? <FirstUseCallout /> : null}
<LogRateResults
isLoading={isLoading}
results={logEntryRate}
timeRange={timeRange}
/>
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import React, { useMemo, useCallback, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { first, last } from 'lodash';
import moment from 'moment';
import {
Axis,
Expand All @@ -24,15 +23,17 @@ import { getColorsMap, isDarkMode, getChartTheme } from '../../chart_helpers';
import { GetLogEntryRateSuccessResponsePayload } from '../../../../../../common/http_api/log_analysis/results/log_entry_rate';
import { useLogEntryRateGraphData } from '../../../../../containers/logs/log_analysis/log_analysis_graph_data/log_entry_rate';
import { useKibanaUiSetting } from '../../../../../utils/use_kibana_ui_setting';
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';

const areaSeriesColour = 'rgb(224, 237, 255)';
const lineSeriesColour = 'rgb(49, 133, 252)';

interface Props {
data: GetLogEntryRateSuccessResponsePayload['data'] | null;
timeRange: TimeRange;
}

export const ChartView = ({ data }: Props) => {
export const ChartView = ({ data, timeRange }: Props) => {
const showModelBoundsLabel = i18n.translate(
'xpack.infra.logs.analysis.logRateSectionModelBoundsCheckboxLabel',
{ defaultMessage: 'Show model bounds' }
Expand All @@ -43,9 +44,9 @@ export const ChartView = ({ data }: Props) => {
const dateFormatter = useMemo(
() =>
lineSeries.length > 0
? niceTimeFormatter([first(lineSeries)[0], last(lineSeries)[0]])
? niceTimeFormatter([timeRange.startTime, timeRange.endTime])
: (value: number) => `${value}`,
[lineSeries]
[lineSeries, timeRange]
);

const areaSpecId = getSpecId('modelBounds');
Expand All @@ -63,7 +64,6 @@ export const ChartView = ({ data }: Props) => {
};

const [isShowingModelBounds, setIsShowingModelBounds] = useState<boolean>(true);

return (
<>
<EuiFlexGroup justifyContent="flexEnd">
Expand Down Expand Up @@ -171,7 +171,11 @@ export const ChartView = ({ data }: Props) => {
}
customSeriesColors={!isDarkMode() ? getColorsMap('red', anomalySpecId) : undefined}
/>
<Settings tooltip={tooltipProps} theme={getChartTheme()} />
<Settings
tooltip={tooltipProps}
theme={getChartTheme()}
xDomain={{ min: timeRange.startTime, max: timeRange.endTime }}
/>
</Chart>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ import { GetLogEntryRateSuccessResponsePayload } from '../../../../../../common/
import { ChartView } from './chart';
import { isValidLogRateView, LogRateView, LogRateViewSwitcher } from './log_rate_view_switcher';
import { TableView } from './table';
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';

export const LogRateResults = ({
isLoading,
results,
timeRange,
}: {
isLoading: boolean;
results: GetLogEntryRateSuccessResponsePayload['data'] | null;
timeRange: TimeRange;
}) => {
const title = i18n.translate('xpack.infra.logs.analysis.logRateSectionTitle', {
defaultMessage: 'Log rate',
Expand Down Expand Up @@ -63,8 +66,7 @@ export const LogRateResults = ({
body={
<p>
{i18n.translate('xpack.infra.logs.analysis.logRateSectionNoDataBody', {
defaultMessage:
'Please allow a few minutes for our machine learning robots to begin collecting data. If you expect data to be here already, you may want to adjust your time range.',
defaultMessage: 'You may want to adjust your time range.',
})}
</p>
}
Expand All @@ -80,7 +82,11 @@ export const LogRateResults = ({
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="l" />
{viewMode === 'chart' ? <ChartView data={results} /> : <TableView data={results} />}
{viewMode === 'chart' ? (
<ChartView data={results} timeRange={timeRange} />
) : (
<TableView data={results} />
)}
</>
)}
</>
Expand Down

0 comments on commit 1f98213

Please sign in to comment.