Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import {
import { Sample } from '@kbn/grok-ui';
import { i18n } from '@kbn/i18n';
import { GrokProcessorDefinition } from '@kbn/streams-schema';
import { isEmpty } from 'lodash';
import React, { useMemo } from 'react';
import { isEmpty } from 'lodash';
import { getPercentageFormatter } from '../../../util/formatters';
import { PreviewTable } from '../preview_table';
import {
PreviewDocsFilterOption,
Expand Down Expand Up @@ -104,10 +105,7 @@ export const ProcessorOutcomePreview = () => {
);
};

const formatter = new Intl.NumberFormat('en-US', {
style: 'percent',
maximumFractionDigits: 1,
});
const formatter = getPercentageFormatter();

const formatRateToPercentage = (rate?: number) =>
(rate ? formatter.format(rate) : undefined) as any; // This is a workaround for the type error, since the numFilters & numActiveFilters props are defined as number | undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import useToggle from 'react-use/lib/useToggle';
import { css } from '@emotion/react';
import { getPercentageFormatter } from '../../../../util/formatters';
import { ProcessorMetrics } from '../state_management/simulation_state_machine';

type ProcessorMetricBadgesProps = ProcessorMetrics;

const formatter = new Intl.NumberFormat('en-US', {
style: 'percent',
maximumFractionDigits: 1,
});
const formatter = getPercentageFormatter();

export const ProcessorMetricBadges = ({
detected_fields,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import {
EuiButton,
EuiFlexGroup,
Expand All @@ -14,11 +15,11 @@ import {
} from '@elastic/eui';
import { css } from '@emotion/css';
import { Streams } from '@kbn/streams-schema';
import React from 'react';
import { useUnsavedChangesPrompt } from '@kbn/unsaved-changes-prompt';
import { i18n } from '@kbn/i18n';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { CoreStart } from '@kbn/core/public';
import { useTimefilter } from '../../../hooks/use_timefilter';
import { useKibana } from '../../../hooks/use_kibana';
import { useStreamsAppFetch } from '../../../hooks/use_streams_app_fetch';
import { ChildStreamList } from './child_stream_list';
Expand Down Expand Up @@ -47,12 +48,15 @@ export function StreamDetailRouting(props: StreamDetailRoutingProps) {
streams: { streamsRepositoryClient },
} = dependencies.start;

const { timeState$ } = useTimefilter();

return (
<StreamRoutingContextProvider
definition={props.definition}
refreshDefinition={props.refreshDefinition}
core={core}
data={data}
timeState$={timeState$}
streamsRepositoryClient={streamsRepositoryClient}
forkSuccessNofitier={createForkSuccessNofitier({ core, router })}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { EuiText, EuiLoadingSpinner, EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { AsyncSample } from '../../../hooks/queries/use_async_sample';
import { RoutingSamplesContext } from './state_management/stream_routing_state_machine/routing_samples_state_machine';

const matchText = i18n.translate('xpack.streams.streamRouting.previewMatchesText', {
defaultMessage: 'Approximate match rate',
Expand All @@ -23,9 +23,9 @@ export const PreviewMatches = ({
error,
isLoading,
}: {
approximateMatchingPercentage: AsyncSample['approximateMatchingPercentage'];
error: AsyncSample['documentCountsError'];
isLoading: AsyncSample['isLoadingDocumentCounts'];
approximateMatchingPercentage: RoutingSamplesContext['approximateMatchingPercentage'];
error?: RoutingSamplesContext['approximateMatchingPercentageError'];
isLoading: boolean;
}) => {
if (isLoading) {
return (
Expand All @@ -39,17 +39,15 @@ export const PreviewMatches = ({
if (error) {
return (
<EuiText size="xs" textAlign="center">
{`${matchText}: `}
{errorText}
{`${matchText}: ${errorText}`}
</EuiText>
);
}

if (approximateMatchingPercentage) {
return (
<EuiText size="xs" textAlign="center">
{`${matchText}: `}
{`${approximateMatchingPercentage}%`}
{`${matchText}: ${approximateMatchingPercentage}`}
<InfoTooltip />
</EuiText>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,119 +16,121 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isEmpty } from 'lodash';
import React, { useEffect } from 'react';
import { useAsyncSample } from '../../../hooks/queries/use_async_sample';
import { useTimefilter } from '../../../hooks/use_timefilter';
import { useDebounced } from '../../../util/use_debounce';
import React from 'react';
import { AssetImage } from '../../asset_image';
import { StreamsAppSearchBar } from '../../streams_app_search_bar';
import { PreviewTable } from '../preview_table';
import { PreviewMatches } from './preview_matches';
import {
selectCurrentRule,
useStreamSamplesSelector,
useStreamsRoutingSelector,
} from './state_management/stream_routing_state_machine';

export function PreviewPanel() {
const routingSnapshot = useStreamsRoutingSelector((snapshot) => snapshot);

const isIdle = routingSnapshot.matches({ ready: 'idle' });
const isCreatingNewRule = routingSnapshot.matches({ ready: 'creatingNewRule' });
const isEditingRule = routingSnapshot.matches({ ready: 'editingRule' });
const isReorideringRules = routingSnapshot.matches({ ready: 'reorderingRules' });
let content;

const condition = isCreatingNewRule ? selectCurrentRule(routingSnapshot.context).if : undefined;
const definition = routingSnapshot.context.definition;
if (routingSnapshot.matches({ ready: 'idle' })) {
content = <IdlePanel />;
} else if (
routingSnapshot.matches({ ready: 'editingRule' }) ||
routingSnapshot.matches({ ready: 'reorderingRules' })
) {
content = <EditingPanel />;
} else if (routingSnapshot.matches({ ready: 'creatingNewRule' })) {
content = <RuleCreationPanel />;
}

const debouncedCondition = useDebounced(condition, 300);
return (
<>
<EuiFlexItem grow={false}>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center" wrap>
<EuiFlexGroup component="span" gutterSize="s" alignItems="center">
<EuiIcon type="inspect" />
<strong>
{i18n.translate('xpack.streams.streamDetail.preview.header', {
defaultMessage: 'Data Preview',
})}
</strong>
</EuiFlexGroup>
<StreamsAppSearchBar showDatePicker />
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="s" />
<EuiFlexItem grow>{content}</EuiFlexItem>
</>
);
}

const { timeState, timeState$ } = useTimefilter();
const IdlePanel = () => (
<EuiEmptyPrompt
icon={<AssetImage type="yourPreviewWillAppearHere" />}
titleSize="s"
title={
<h2>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessageEmpty', {
defaultMessage: 'Your preview will appear here',
})}
</h2>
}
body={i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessageEmptyDescription', {
defaultMessage:
'Create a new child stream to see what will be routed to it based on the conditions',
})}
/>
);

const EditingPanel = () => (
<EuiEmptyPrompt
icon={<AssetImage />}
titleSize="s"
title={
<h2>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessage', {
defaultMessage: 'Preview is not available while editing or reordering streams',
})}
</h2>
}
body={
<>
<p>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessageBody', {
defaultMessage:
'Once you save your changes, the results of your conditions will appear here.',
})}
</p>
<p>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewReorderingWarning', {
defaultMessage:
'Additionally, you will not be able to edit existing streams while reordering them, you should save or cancel your changes first.',
})}
</p>
</>
}
/>
);

const RuleCreationPanel = () => {
const samplesSnapshot = useStreamSamplesSelector((snapshot) => snapshot);
const isLoadingDocuments = samplesSnapshot.matches({ fetching: { documents: 'loading' } });
const isUpdating =
samplesSnapshot.matches('debouncingCondition') ||
samplesSnapshot.matches({ fetching: { documents: 'loading' } });
const {
isLoadingDocuments,
documents,
documentsError,
refresh,
approximateMatchingPercentage,
isLoadingDocumentCounts,
documentCountsError,
} = useAsyncSample({
condition: debouncedCondition,
start: timeState.start,
end: timeState.end,
size: 100,
streamDefinition: definition,
});

approximateMatchingPercentageError,
} = samplesSnapshot.context;
const hasDocuments = !isEmpty(documents);
const isLoadingDocumentCounts = samplesSnapshot.matches({
fetching: { documentCounts: 'loading' },
});

useEffect(() => {
const subscription = timeState$.subscribe({
next: ({ kind }) => {
if (kind === 'override') {
refresh();
}
},
});
return () => {
subscription.unsubscribe();
};
}, [timeState$, refresh]);

let content;
let content = null;

if (isIdle) {
content = (
<EuiEmptyPrompt
icon={<AssetImage type="yourPreviewWillAppearHere" />}
titleSize="s"
title={
<h2>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessageEmpty', {
defaultMessage: 'Your preview will appear here',
})}
</h2>
}
body={i18n.translate(
'xpack.streams.streamDetail.preview.editPreviewMessageEmptyDescription',
{
defaultMessage:
'Create a new child stream to see what will be routed to it based on the conditions',
}
)}
/>
);
} else if (isEditingRule || isReorideringRules) {
content = (
<EuiEmptyPrompt
icon={<AssetImage />}
titleSize="s"
title={
<h2>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessage', {
defaultMessage: 'Preview is not available while editing or reordering streams',
})}
</h2>
}
body={
<>
<p>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewMessageBody', {
defaultMessage:
'You will find here the result from the conditions you have made once you save the changes',
})}
</p>
<p>
{i18n.translate('xpack.streams.streamDetail.preview.editPreviewReorderingWarning', {
defaultMessage:
'Additionally, you will not be able to edit existing streams while reordering them, you should save or cancel your changes first.',
})}
</p>
</>
}
/>
);
} else if (isCreatingNewRule && isLoadingDocuments && !hasDocuments) {
if (isLoadingDocuments && !hasDocuments) {
content = (
<EuiEmptyPrompt
icon={<EuiLoadingLogo logo="logoLogging" size="xl" />}
Expand All @@ -146,7 +148,7 @@ export function PreviewPanel() {
})}
/>
);
} else if (isCreatingNewRule && documentsError) {
} else if (documentsError) {
content = (
<EuiEmptyPrompt
icon={<AssetImage type="noResults" />}
Expand All @@ -162,7 +164,7 @@ export function PreviewPanel() {
body={documentsError.message}
/>
);
} else if (isCreatingNewRule && !hasDocuments) {
} else if (!hasDocuments) {
content = (
<EuiEmptyPrompt
icon={<AssetImage type="noResults" />}
Expand All @@ -176,41 +178,27 @@ export function PreviewPanel() {
}
/>
);
} else if (isCreatingNewRule && hasDocuments) {
} else if (hasDocuments) {
content = (
<EuiFlexItem grow>
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<PreviewMatches
approximateMatchingPercentage={approximateMatchingPercentage}
error={documentCountsError}
error={approximateMatchingPercentageError}
isLoading={isLoadingDocumentCounts}
/>
</EuiFlexItem>
<PreviewTable documents={documents ?? []} />
<PreviewTable documents={documents} />
</EuiFlexGroup>
</EuiFlexItem>
);
}

return (
<>
<EuiFlexItem grow={false}>
{isLoadingDocuments && <EuiProgress size="xs" color="accent" position="absolute" />}
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center" wrap>
<EuiFlexGroup component="span" gutterSize="s" alignItems="center">
<EuiIcon type="inspect" />
<strong>
{i18n.translate('xpack.streams.streamDetail.preview.header', {
defaultMessage: 'Data Preview',
})}
</strong>
</EuiFlexGroup>
<StreamsAppSearchBar showDatePicker />
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="s" />
<EuiFlexItem grow>{content}</EuiFlexItem>
{isUpdating && <EuiProgress size="xs" color="accent" position="absolute" />}
{content}
</>
);
}
};
Loading