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 @@ -17,7 +17,6 @@ import {
} from '../../state_management/simulation_state_machine/selectors';
import { useSimulatorSelector } from '../../state_management/stream_enrichment_state_machine';
import { simulateProcessing } from '../../state_management/simulation_state_machine/simulation_runner_actor';
import { SimulationContext } from '../../state_management/simulation_state_machine';

export interface GrokPatternSuggestionParams {
streamName: string;
Expand Down Expand Up @@ -73,7 +72,7 @@ export function useGrokPatternSuggestion() {
samples: originalSamples,
previewDocsFilter,
simulation,
} as SimulationContext);
});
}

const finishTrackingAndReport = telemetryClient.startTrackingAIGrokSuggestionLatency({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import { getFilterSimulationDocumentsFn } from './utils';
*/
export const selectPreviewRecords = createSelector(
[
(context: SimulationContext) => context.samples,
(context: SimulationContext) => context.previewDocsFilter,
(context: SimulationContext) => context.simulation?.documents,
(context: Pick<SimulationContext, 'samples'>) => context.samples,
(context: Pick<SimulationContext, 'previewDocsFilter'>) => context.previewDocsFilter,
(context: Pick<SimulationContext, 'simulation'>) => context.simulation?.documents,
],
(samples, previewDocsFilter, documents) => {
if (!previewDocsFilter || !documents) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { StreamsAppSearchBar } from '../../streams_app_search_bar';
import { PreviewTable } from '../preview_table';
import { PreviewMatches } from './preview_matches';
import {
selectPreviewDocuments,
useStreamSamplesSelector,
useStreamsRoutingSelector,
} from './state_management/stream_routing_state_machine';
Expand Down Expand Up @@ -117,18 +118,18 @@ const RuleCreationPanel = () => {
const isUpdating =
samplesSnapshot.matches('debouncingCondition') ||
samplesSnapshot.matches({ fetching: { documents: 'loading' } });
const {
documents,
documentsError,
approximateMatchingPercentage,
approximateMatchingPercentageError,
} = samplesSnapshot.context;
const hasDocuments = !isEmpty(documents);
const isLoadingDocumentCounts = samplesSnapshot.matches({
fetching: { documentCounts: 'loading' },
});
const { documentsError, approximateMatchingPercentage, approximateMatchingPercentageError } =
samplesSnapshot.context;

const documents = useStreamSamplesSelector((snapshot) =>
selectPreviewDocuments(snapshot.context)
);
const hasDocuments = !isEmpty(documents);

let content = null;
let content: React.ReactNode | null = null;

if (isLoadingDocuments && !hasDocuments) {
content = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
*/

import { createSelector } from 'reselect';
import { flattenObject } from '@kbn/object-utils';
import { FlattenRecord } from '@kbn/streams-schema';
import { StreamRoutingContext } from './types';
import { RoutingSamplesContext } from './routing_samples_state_machine';

/**
* Selects the set of dotted fields that are not supported by the current simulation.
Expand All @@ -26,3 +29,13 @@ export const selectCurrentRule = createSelector(
return currentRoutingRule;
}
);

/**
* Selects the documents used for the data preview table.
*/
export const selectPreviewDocuments = createSelector(
[(context: RoutingSamplesContext) => context.documents],
(documents) => {
return documents.map((doc) => flattenObject(doc)) as FlattenRecord[];
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -40,52 +40,10 @@ export function DocumentsColumn({
indexPattern: string;
numDataPoints: number;
}) {
const {
dependencies: {
start: {
streams: { streamsRepositoryClient },
},
},
} = useKibana();
const { streamsRepositoryClient } = useKibana().dependencies.start.streams;
const chartBaseTheme = useElasticChartsTheme();
const { euiTheme } = useEuiTheme();

const LoadingPlaceholder: React.FC = React.useCallback(
() => (
<EuiFlexGroup
alignItems="center"
justifyContent="flexEnd"
gutterSize="m"
className={css`
height: ${euiTheme.size.xl};
white-space: nowrap;
padding-right: ${euiTheme.size.xl};
`}
>
<EuiFlexGroup>
<EuiFlexItem
className={css`
text-align: center;
`}
>
-
</EuiFlexItem>
<EuiFlexItem
grow={false}
className={css`
display: flex;
padding-right: ${euiTheme.size.xl};
justify-content: center;
`}
>
<EuiLoadingChart size="m" />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
),
[euiTheme]
);

const { timeState } = useTimefilter();

const minInterval = Math.floor((timeState.end - timeState.start) / numDataPoints);
Expand Down Expand Up @@ -211,3 +169,39 @@ export function DocumentsColumn({
</EuiFlexGroup>
);
}

const LoadingPlaceholder = () => {
const { euiTheme } = useEuiTheme();
return (
<EuiFlexGroup
alignItems="center"
justifyContent="flexEnd"
gutterSize="m"
className={css`
height: ${euiTheme.size.xl};
white-space: nowrap;
padding-right: ${euiTheme.size.xl};
`}
>
<EuiFlexGroup>
<EuiFlexItem
className={css`
text-align: center;
`}
>
-
</EuiFlexItem>
<EuiFlexItem
grow={false}
className={css`
display: flex;
padding-right: ${euiTheme.size.xl};
justify-content: center;
`}
>
<EuiLoadingChart size="m" />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexGroup, EuiBetaBadge, EuiLink, EuiPageHeader, useEuiTheme } from '@elastic/eui';
import {
EuiFlexGroup,
EuiBetaBadge,
EuiLink,
useEuiTheme,
EuiEmptyPrompt,
EuiLoadingLogo,
} from '@elastic/eui';
import { css } from '@emotion/react';
import {
OBSERVABILITY_ONBOARDING_LOCATOR,
ObservabilityOnboardingLocatorParams,
} from '@kbn/deeplinks-observability';
import { isEmpty } from 'lodash';
import { useKibana } from '../../hooks/use_kibana';
import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch';
import { StreamsTreeTable } from './tree_table';
Expand All @@ -21,6 +29,7 @@ import { StreamsListEmptyPrompt } from './streams_list_empty_prompt';
import { useTimefilter } from '../../hooks/use_timefilter';

export function StreamListView() {
const { euiTheme } = useEuiTheme();
const {
dependencies: {
start: {
Expand All @@ -30,12 +39,15 @@ export function StreamListView() {
},
core: { docLinks },
} = useKibana();
const onboardingLocator = share?.url.locators.get<ObservabilityOnboardingLocatorParams>(
const onboardingLocator = share.url.locators.get<ObservabilityOnboardingLocatorParams>(
OBSERVABILITY_ONBOARDING_LOCATOR
);
const handleAddData = () => {
onboardingLocator?.navigate({});
};
const handleAddData = onboardingLocator
? () => {
onboardingLocator.navigate({});
}
: undefined;

const { timeState } = useTimefilter();
const streamsListFetch = useStreamsAppFetch(
async ({ signal }) => {
Expand All @@ -51,25 +63,15 @@ export function StreamListView() {
[streamsRepositoryClient, timeState.start, timeState.end]
);

const { euiTheme } = useEuiTheme();
return (
<>
<EuiPageHeader
paddingSize="l"
<StreamsAppPageTemplate.Header
bottomBorder="extended"
css={css`
background: ${euiTheme.colors.backgroundBasePlain};
.euiSpacer--l {
display: none !important;
}
`}
pageTitle={
<EuiFlexGroup
alignItems="center"
gutterSize="m"
css={css`
margin-bottom: ${euiTheme.size.s};
`}
>
<EuiFlexGroup alignItems="center" gutterSize="m">
{i18n.translate('xpack.streams.streamsListView.pageHeaderTitle', {
defaultMessage: 'Streams',
})}
Expand All @@ -86,29 +88,33 @@ export function StreamListView() {
/>
</EuiFlexGroup>
}
>
<p
css={css`
margin: 0 0 ${euiTheme.size.s} 0;
font-size: ${euiTheme.font.scale.s};
color: ${euiTheme.colors.textSubdued};
line-height: ${euiTheme.size.l};
`}
>
{i18n.translate('xpack.streams.streamsListView.pageHeaderDescription', {
defaultMessage:
'Use Streams to organize and process your data into clear structured flows, and simplify routing, field extraction, and retention management.',
})}{' '}
<EuiLink target="_blank" href={docLinks.links.observability.logsStreams}>
{i18n.translate('xpack.streams.streamsListView.pageHeaderDocsLink', {
defaultMessage: 'See docs',
})}
</EuiLink>
</p>
</EuiPageHeader>

description={
<>
{i18n.translate('xpack.streams.streamsListView.pageHeaderDescription', {
defaultMessage:
'Use Streams to organize and process your data into clear structured flows, and simplify routing, field extraction, and retention management.',
})}{' '}
<EuiLink target="_blank" href={docLinks.links.observability.logsStreams}>
{i18n.translate('xpack.streams.streamsListView.pageHeaderDocsLink', {
defaultMessage: 'See docs',
})}
</EuiLink>
</>
}
/>
<StreamsAppPageTemplate.Body grow>
{!streamsListFetch.loading && !streamsListFetch.value?.length ? (
{streamsListFetch.loading && streamsListFetch.value === undefined ? (
<EuiEmptyPrompt
icon={<EuiLoadingLogo logo="logoObservability" size="xl" />}
title={
<h2>
{i18n.translate('xpack.streams.streamsListView.loadingStreams', {
defaultMessage: 'Loading Streams',
})}
</h2>
}
/>
) : !streamsListFetch.loading && isEmpty(streamsListFetch.value) ? (
<StreamsListEmptyPrompt onAddData={handleAddData} />
) : (
<StreamsTreeTable loading={streamsListFetch.loading} streams={streamsListFetch.value} />
Expand Down
Loading