x-pack/platform/packages/shared/kbn-classic-stream-flyout/README.md
A reusable React component package that provides a multi-step flyout interface for creating classic streams in Kibana.
The Create Classic Stream Flyout is a wizard-based interface that guides users through:
This package is part of the Kibana monorepo and is available as a shared browser package.
import { CreateClassicStreamFlyout } from '@kbn/classic-stream-flyout';
import React, { useState } from 'react';
import { CreateClassicStreamFlyout } from '@kbn/classic-stream-flyout';
import type { TemplateListItem } from '@kbn/index-management-shared-types';
const MyComponent = () => {
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
const [templates, setTemplates] = useState<TemplateListItem[]>([]);
const handleCreate = async (streamName: string) => {
// Handle the stream creation
await createClassicStream(streamName);
setIsFlyoutVisible(false);
};
const handleClose = () => {
setIsFlyoutVisible(false);
};
return (
<>
<button onClick={() => setIsFlyoutVisible(true)}>Create Classic Stream</button>
{isFlyoutVisible && (
<CreateClassicStreamFlyout
onClose={handleClose}
onCreate={handleCreate}
onCreateTemplate={() => {
/* Navigate to template creation */
}}
templates={templates}
onRetryLoadTemplates={() => {
/* Retry loading templates */
}}
/>
)}
</>
);
};
<CreateClassicStreamFlyout
onClose={handleClose}
onCreate={handleCreate}
onCreateTemplate={handleCreateTemplate}
templates={templates}
onRetryLoadTemplates={handleRetry}
onValidate={async (streamName, template, signal) => {
// Check for duplicate stream names or higher priority template conflicts
const isDuplicate = await checkDuplicate(streamName, signal);
if (isDuplicate) {
return { errorType: 'duplicate' };
}
const conflict = await checkTemplatePriority(streamName, template, signal);
if (conflict) {
return {
errorType: 'higherPriority',
conflictingIndexPattern: conflict.pattern,
};
}
return { errorType: null };
}}
/>
The flyout can display detailed template information by fetching simulated template data (to show resolved index mode and ILM policy) and ILM policy details (to show lifecycle phases):
<CreateClassicStreamFlyout
onClose={handleClose}
onCreate={handleCreate}
onCreateTemplate={handleCreateTemplate}
templates={templates}
onRetryLoadTemplates={handleRetry}
getSimulatedTemplate={async (templateName, signal) => {
// Fetch simulated template to get resolved index mode and ILM policy name
return await simulateTemplate(templateName, signal);
}}
getIlmPolicy={async (policyName, signal) => {
// Fetch ILM policy details for phase display
return await fetchIlmPolicy(policyName, signal);
}}
/>
<CreateClassicStreamFlyout
onClose={handleClose}
onCreate={handleCreate}
onCreateTemplate={handleCreateTemplate}
templates={templates}
hasErrorLoadingTemplates={true}
onRetryLoadTemplates={handleRetry}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
onClose | () => void | ✓ | Callback when the flyout is closed |
onCreate | (streamName: string) => Promise<void> | ✓ | Callback when the stream is created with the final stream name |
onCreateTemplate | () => void | ✓ | Callback to navigate to create template flow (shown when no templates exist) |
templates | TemplateListItem[] | ✓ | Available index templates to select from |
isLoadingTemplates | boolean | ✗ | Whether templates are currently being loaded (defaults to false) |
onRetryLoadTemplates | () => void | ✓ | Callback to retry loading templates after an error |
hasErrorLoadingTemplates | boolean | ✗ | Whether there was an error loading templates (defaults to false) |
onValidate | StreamNameValidator | ✗ | Async callback to validate the stream name for duplicates and priority conflicts |
getSimulatedTemplate | SimulatedTemplateFetcher | ✗ | Async callback to fetch simulated template data for resolved index mode and ILM policy |
getIlmPolicy | IlmPolicyFetcher | ✗ | Async callback to fetch ILM policy details by name for phase display |
type StreamNameValidator = (
streamName: string,
selectedTemplate: IndexTemplate,
signal?: AbortSignal
) => Promise<{
errorType: 'duplicate' | 'higherPriority' | null;
conflictingIndexPattern?: string;
}>;
type SimulatedTemplateFetcher = (
templateName: string,
signal?: AbortSignal
) => Promise<SimulateIndexTemplateResponse | null>;
This fetcher calls the index management API to get the resolved template configuration, which includes:
standard, logsdb, time_series, lookup)type IlmPolicyFetcher = (policyName: string, signal?: AbortSignal) => Promise<PolicyFromES | null>;
| Error Type | Description |
|---|---|
'empty' | Stream name has unfilled wildcards or is empty |
'invalidFormat' | Stream name contains invalid characters or format |
'duplicate' | Stream name already exists (from onValidate) |
'higherPriority' | Stream name conflicts with a higher priority template (from onValidate) |
null | No error, validation passed |
Stream names follow Elasticsearch data stream naming rules:
Cannot include:
\, /, *, ?, ", <, >, |, ,, #, :, or space charactersCannot start with:
-, _, +, or .ds-Cannot be:
. or ..The flyout implements a validation state machine with three modes:
| Mode | Description | Behavior |
|---|---|---|
| IDLE | Initial state, no active validation | Typing does not trigger validation |
| CREATE | User clicked Create button | Validation in progress, typing aborts and returns to IDLE |
| LIVE | Has validation error, validates on keystroke | Debounced validation on every change (300ms default) |
When getSimulatedTemplate is provided, the confirmation step displays:
standard, logsdb, time_series, or lookup)getIlmPolicy) or from the template's data stream lifecycleIf the simulated template fetch fails, a warning message is displayed and only basic template information is shown.
The validation and data fetching systems use AbortController to handle race conditions:
The package includes comprehensive test coverage:
# Run tests
yarn jest --config x-pack/platform/packages/shared/kbn-classic-stream-flyout/jest.config.js
View and develop the component in Storybook:
yarn storybook classic_stream_flyout