* Index Patterns Management - use `/_resolve` endpoint for data streams support
This commit is contained in:
parent
eff820bd69
commit
7423de8b77
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "indexPatternManagement",
|
||||
"version": "kibana",
|
||||
"server": false,
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["management", "data", "kibanaLegacy"]
|
||||
}
|
||||
|
|
|
@ -1,41 +1,33 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CreateIndexPatternWizard defaults to the loading state 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Header
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<LoadingState />
|
||||
</div>
|
||||
<Fragment>
|
||||
<LoadingState />
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CreateIndexPatternWizard renders index pattern step when there are indices 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Fragment>
|
||||
<EuiPageContent>
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
"scriptedFields": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<StepIndexPattern
|
||||
allIndices={
|
||||
Array [
|
||||
|
@ -55,56 +47,48 @@ exports[`CreateIndexPatternWizard renders index pattern step when there are indi
|
|||
"type": "default",
|
||||
}
|
||||
}
|
||||
isIncludingSystemIndices={false}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
</div>
|
||||
</EuiPageContent>
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CreateIndexPatternWizard renders the empty state when there are no indices 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Header
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<EmptyState
|
||||
onRefresh={[Function]}
|
||||
prependBasePath={[Function]}
|
||||
/>
|
||||
</div>
|
||||
<Fragment>
|
||||
<EmptyState
|
||||
onRefresh={[Function]}
|
||||
prependBasePath={[Function]}
|
||||
/>
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CreateIndexPatternWizard renders time field step when step is set to 2 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Fragment>
|
||||
<EuiPageContent>
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
"scriptedFields": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<StepTimeField
|
||||
createIndexPattern={[Function]}
|
||||
goToPreviousStep={[Function]}
|
||||
|
@ -120,28 +104,32 @@ exports[`CreateIndexPatternWizard renders time field step when step is set to 2
|
|||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</EuiPageContent>
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CreateIndexPatternWizard renders when there are no indices but there are remote clusters 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Fragment>
|
||||
<EuiPageContent>
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
"scriptedFields": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<StepIndexPattern
|
||||
allIndices={Array []}
|
||||
goToNextStep={[Function]}
|
||||
|
@ -155,56 +143,27 @@ exports[`CreateIndexPatternWizard renders when there are no indices but there ar
|
|||
"type": "default",
|
||||
}
|
||||
}
|
||||
isIncludingSystemIndices={false}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
</div>
|
||||
</EuiPageContent>
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CreateIndexPatternWizard shows system indices even if there are no other indices if the include system indices is toggled 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<div>
|
||||
<Header
|
||||
indexPatternName="name"
|
||||
isBeta={false}
|
||||
isIncludingSystemIndices={true}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={null}
|
||||
showSystemIndices={true}
|
||||
/>
|
||||
<StepIndexPattern
|
||||
allIndices={
|
||||
Array [
|
||||
Object {
|
||||
"name": ".kibana ",
|
||||
},
|
||||
]
|
||||
}
|
||||
goToNextStep={[Function]}
|
||||
indexPatternCreationType={
|
||||
IndexPatternCreationConfig {
|
||||
"httpClient": null,
|
||||
"isBeta": false,
|
||||
"key": "default",
|
||||
"name": "name",
|
||||
"showSystemIndices": true,
|
||||
"type": "default",
|
||||
}
|
||||
}
|
||||
isIncludingSystemIndices={true}
|
||||
/>
|
||||
</div>
|
||||
<Fragment>
|
||||
<EmptyState
|
||||
onRefresh={[Function]}
|
||||
prependBasePath={[Function]}
|
||||
/>
|
||||
<EuiGlobalToastList
|
||||
dismissToast={[Function]}
|
||||
toastLifeTimeMs={6000}
|
||||
toasts={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -2,10 +2,15 @@
|
|||
|
||||
exports[`Header should render a different name, prompt, and beta tag if provided 1`] = `
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="test index pattern"
|
||||
isBeta={true}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
prompt={
|
||||
<div>
|
||||
Test prompt
|
||||
|
@ -31,50 +36,6 @@ exports[`Header should render a different name, prompt, and beta tag if provided
|
|||
</EuiBetaBadge>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup
|
||||
alignItems="flexEnd"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexEnd euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<EuiText
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<p>
|
||||
<EuiTextColor
|
||||
color="subdued"
|
||||
>
|
||||
<span
|
||||
className="euiTextColor euiTextColor--subdued"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations."
|
||||
id="indexPatternManagement.createIndexPatternLabel"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
>
|
||||
|
@ -82,9 +43,83 @@ exports[`Header should render a different name, prompt, and beta tag if provided
|
|||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<div>
|
||||
Test prompt
|
||||
</div>
|
||||
<EuiText>
|
||||
<div
|
||||
className="euiText euiText--medium"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data souces, {star}."
|
||||
id="indexPatternManagement.createIndexPattern.description"
|
||||
values={
|
||||
Object {
|
||||
"multiple": <strong>
|
||||
multiple
|
||||
</strong>,
|
||||
"single": <EuiCode>
|
||||
filebeat-4-3-22
|
||||
</EuiCode>,
|
||||
"star": <EuiCode>
|
||||
filebeat-*
|
||||
</EuiCode>,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
An index pattern can match a single source, for example,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-4-3-22
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
, or
|
||||
<strong>
|
||||
multiple
|
||||
</strong>
|
||||
data souces,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-*
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
<br />
|
||||
<EuiLink
|
||||
external={true}
|
||||
target="_blank"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read documentation"
|
||||
id="indexPatternManagement.createIndexPattern.documentation"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Read documentation
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</button>
|
||||
</EuiLink>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
>
|
||||
|
@ -92,15 +127,23 @@ exports[`Header should render a different name, prompt, and beta tag if provided
|
|||
className="euiSpacer euiSpacer--m"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<div>
|
||||
Test prompt
|
||||
</div>
|
||||
</div>
|
||||
</Header>
|
||||
`;
|
||||
|
||||
exports[`Header should render normally 1`] = `
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="test index pattern"
|
||||
isIncludingSystemIndices={true}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
>
|
||||
<div>
|
||||
<EuiTitle>
|
||||
|
@ -110,66 +153,104 @@ exports[`Header should render normally 1`] = `
|
|||
Create test index pattern
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup
|
||||
alignItems="flexEnd"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexEnd euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<EuiText
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<p>
|
||||
<EuiTextColor
|
||||
color="subdued"
|
||||
>
|
||||
<span
|
||||
className="euiTextColor euiTextColor--subdued"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations."
|
||||
id="indexPatternManagement.createIndexPatternLabel"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiSpacer euiSpacer--m"
|
||||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<EuiText>
|
||||
<div
|
||||
className="euiText euiText--medium"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data souces, {star}."
|
||||
id="indexPatternManagement.createIndexPattern.description"
|
||||
values={
|
||||
Object {
|
||||
"multiple": <strong>
|
||||
multiple
|
||||
</strong>,
|
||||
"single": <EuiCode>
|
||||
filebeat-4-3-22
|
||||
</EuiCode>,
|
||||
"star": <EuiCode>
|
||||
filebeat-*
|
||||
</EuiCode>,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
An index pattern can match a single source, for example,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-4-3-22
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
, or
|
||||
<strong>
|
||||
multiple
|
||||
</strong>
|
||||
data souces,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-*
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
<br />
|
||||
<EuiLink
|
||||
external={true}
|
||||
target="_blank"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read documentation"
|
||||
id="indexPatternManagement.createIndexPattern.documentation"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Read documentation
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</button>
|
||||
</EuiLink>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</Header>
|
||||
`;
|
||||
|
||||
exports[`Header should render without including system indices 1`] = `
|
||||
<Header
|
||||
docLinks={
|
||||
Object {
|
||||
"links": Object {
|
||||
"indexPatterns": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPatternName="test index pattern"
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
>
|
||||
<div>
|
||||
<EuiTitle>
|
||||
|
@ -179,57 +260,90 @@ exports[`Header should render without including system indices 1`] = `
|
|||
Create test index pattern
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup
|
||||
alignItems="flexEnd"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsFlexEnd euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<EuiText
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<p>
|
||||
<EuiTextColor
|
||||
color="subdued"
|
||||
>
|
||||
<span
|
||||
className="euiTextColor euiTextColor--subdued"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations."
|
||||
id="indexPatternManagement.createIndexPatternLabel"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiSpacer euiSpacer--m"
|
||||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<EuiText>
|
||||
<div
|
||||
className="euiText euiText--medium"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data souces, {star}."
|
||||
id="indexPatternManagement.createIndexPattern.description"
|
||||
values={
|
||||
Object {
|
||||
"multiple": <strong>
|
||||
multiple
|
||||
</strong>,
|
||||
"single": <EuiCode>
|
||||
filebeat-4-3-22
|
||||
</EuiCode>,
|
||||
"star": <EuiCode>
|
||||
filebeat-*
|
||||
</EuiCode>,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
An index pattern can match a single source, for example,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-4-3-22
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
, or
|
||||
<strong>
|
||||
multiple
|
||||
</strong>
|
||||
data souces,
|
||||
<EuiCode>
|
||||
<EuiCodeBlockImpl
|
||||
inline={true}
|
||||
>
|
||||
<span>
|
||||
<code>
|
||||
filebeat-*
|
||||
</code>
|
||||
</span>
|
||||
</EuiCodeBlockImpl>
|
||||
</EuiCode>
|
||||
.
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
<br />
|
||||
<EuiLink
|
||||
external={true}
|
||||
target="_blank"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read documentation"
|
||||
id="indexPatternManagement.createIndexPattern.documentation"
|
||||
values={Object {}}
|
||||
>
|
||||
<span>
|
||||
Read documentation
|
||||
</span>
|
||||
</FormattedMessage>
|
||||
</button>
|
||||
</EuiLink>
|
||||
</p>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</Header>
|
||||
`;
|
||||
|
|
|
@ -22,18 +22,20 @@ import { Header } from '../header';
|
|||
import { mount } from 'enzyme';
|
||||
import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
|
||||
import { mockManagementPlugin } from '../../../../mocks';
|
||||
import { DocLinksStart } from 'kibana/public';
|
||||
|
||||
describe('Header', () => {
|
||||
const indexPatternName = 'test index pattern';
|
||||
const mockedContext = mockManagementPlugin.createIndexPatternManagmentContext();
|
||||
const mockedDocLinks = {
|
||||
links: {
|
||||
indexPatterns: {},
|
||||
},
|
||||
} as DocLinksStart;
|
||||
|
||||
it('should render normally', () => {
|
||||
const component = mount(
|
||||
<Header
|
||||
indexPatternName={indexPatternName}
|
||||
isIncludingSystemIndices={true}
|
||||
onChangeIncludingSystemIndices={() => {}}
|
||||
/>,
|
||||
<Header indexPatternName={indexPatternName} docLinks={mockedDocLinks} />,
|
||||
{
|
||||
wrappingComponent: KibanaContextProvider,
|
||||
wrappingComponentProps: {
|
||||
|
@ -47,11 +49,7 @@ describe('Header', () => {
|
|||
|
||||
it('should render without including system indices', () => {
|
||||
const component = mount(
|
||||
<Header
|
||||
indexPatternName={indexPatternName}
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={() => {}}
|
||||
/>,
|
||||
<Header indexPatternName={indexPatternName} docLinks={mockedDocLinks} />,
|
||||
{
|
||||
wrappingComponent: KibanaContextProvider,
|
||||
wrappingComponentProps: {
|
||||
|
@ -66,11 +64,10 @@ describe('Header', () => {
|
|||
it('should render a different name, prompt, and beta tag if provided', () => {
|
||||
const component = mount(
|
||||
<Header
|
||||
isIncludingSystemIndices={false}
|
||||
onChangeIncludingSystemIndices={() => {}}
|
||||
prompt={<div>Test prompt</div>}
|
||||
indexPatternName={indexPatternName}
|
||||
isBeta={true}
|
||||
docLinks={mockedDocLinks}
|
||||
/>,
|
||||
{
|
||||
wrappingComponent: KibanaContextProvider,
|
||||
|
|
|
@ -17,38 +17,26 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
EuiBetaBadge,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
import { EuiBetaBadge, EuiSpacer, EuiTitle, EuiText, EuiCode, EuiLink } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { DocLinksStart } from 'kibana/public';
|
||||
import { useKibana } from '../../../../../../../plugins/kibana_react/public';
|
||||
import { IndexPatternManagmentContext } from '../../../../types';
|
||||
|
||||
export const Header = ({
|
||||
prompt,
|
||||
indexPatternName,
|
||||
showSystemIndices = false,
|
||||
isIncludingSystemIndices,
|
||||
onChangeIncludingSystemIndices,
|
||||
isBeta = false,
|
||||
docLinks,
|
||||
}: {
|
||||
prompt?: React.ReactNode;
|
||||
indexPatternName: string;
|
||||
showSystemIndices?: boolean;
|
||||
isIncludingSystemIndices: boolean;
|
||||
onChangeIncludingSystemIndices: () => void;
|
||||
isBeta?: boolean;
|
||||
docLinks: DocLinksStart;
|
||||
}) => {
|
||||
const changeTitle = useKibana<IndexPatternManagmentContext>().services.chrome.docTitle.change;
|
||||
const createIndexPatternHeader = i18n.translate(
|
||||
|
@ -67,53 +55,44 @@ export const Header = ({
|
|||
<h1>
|
||||
{createIndexPatternHeader}
|
||||
{isBeta ? (
|
||||
<Fragment>
|
||||
<>
|
||||
{' '}
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('indexPatternManagement.createIndexPattern.betaLabel', {
|
||||
defaultMessage: 'Beta',
|
||||
})}
|
||||
/>
|
||||
</Fragment>
|
||||
</>
|
||||
) : null}
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<EuiTextColor color="subdued">
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPatternLabel"
|
||||
defaultMessage="Kibana uses index patterns to retrieve data from Elasticsearch indices for things like visualizations."
|
||||
/>
|
||||
</EuiTextColor>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
{showSystemIndices ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.includeSystemIndicesToggleSwitchLabel"
|
||||
defaultMessage="Include system indices"
|
||||
/>
|
||||
}
|
||||
id="checkboxShowSystemIndices"
|
||||
checked={isIncludingSystemIndices}
|
||||
onChange={onChangeIncludingSystemIndices}
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.description"
|
||||
defaultMessage="An index pattern can match a single source, for example, {single}, or {multiple} data souces, {star}."
|
||||
values={{
|
||||
multiple: <strong>multiple</strong>,
|
||||
single: <EuiCode>filebeat-4-3-22</EuiCode>,
|
||||
star: <EuiCode>filebeat-*</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
<EuiLink href={docLinks.links.indexPatterns.introduction} target="_blank" external>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.documentation"
|
||||
defaultMessage="Read documentation"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
</EuiLink>
|
||||
</p>
|
||||
</EuiText>
|
||||
{prompt ? (
|
||||
<Fragment>
|
||||
<EuiSpacer size="s" />
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
{prompt}
|
||||
</Fragment>
|
||||
</>
|
||||
) : null}
|
||||
<EuiSpacer size="m" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,8 +11,10 @@ Object {
|
|||
]
|
||||
}
|
||||
goToNextStep={[Function]}
|
||||
isIncludingSystemIndices={false}
|
||||
isInputInvalid={true}
|
||||
isNextStepDisabled={true}
|
||||
onChangeIncludingSystemIndices={[Function]}
|
||||
onQueryChanged={[Function]}
|
||||
query="?"
|
||||
/>,
|
||||
|
@ -25,6 +27,7 @@ exports[`StepIndexPattern renders indices which match the initial query 1`] = `
|
|||
indices={
|
||||
Array [
|
||||
Object {
|
||||
"item": Object {},
|
||||
"name": "kibana",
|
||||
},
|
||||
]
|
||||
|
@ -39,6 +42,7 @@ exports[`StepIndexPattern renders matching indices when input is valid 1`] = `
|
|||
indices={
|
||||
Array [
|
||||
Object {
|
||||
"item": Object {},
|
||||
"name": "kibana",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -16,13 +16,8 @@ exports[`Header should mark the input as invalid 1`] = `
|
|||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="flexEnd"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiForm
|
||||
isInvalid={true}
|
||||
>
|
||||
|
@ -34,43 +29,40 @@ exports[`Header should mark the input as invalid 1`] = `
|
|||
"Input is invalid",
|
||||
]
|
||||
}
|
||||
fullWidth={false}
|
||||
fullWidth={true}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can use a {asterisk} as a wildcard in your index pattern."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
values={
|
||||
Object {
|
||||
"asterisk": <strong>
|
||||
*
|
||||
</strong>,
|
||||
}
|
||||
<React.Fragment>
|
||||
<FormattedMessage
|
||||
defaultMessage="Use an asterisk ({asterisk}) to match multiple indices."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
values={
|
||||
Object {
|
||||
"asterisk": <strong>
|
||||
*
|
||||
</strong>,
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can't use spaces or the characters {characterList}."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
values={
|
||||
Object {
|
||||
"characterList": <strong>
|
||||
%
|
||||
</strong>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Spaces and the characters {characterList} are not allowed."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
values={
|
||||
Object {
|
||||
"characterList": <strong>
|
||||
%
|
||||
</strong>,
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
isInvalid={true}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Index pattern"
|
||||
defaultMessage="Index pattern name"
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPatternLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
|
@ -79,6 +71,7 @@ exports[`Header should mark the input as invalid 1`] = `
|
|||
>
|
||||
<EuiFieldText
|
||||
data-test-subj="createIndexPatternNameInput"
|
||||
fullWidth={true}
|
||||
isInvalid={true}
|
||||
name="indexPattern"
|
||||
onChange={[Function]}
|
||||
|
@ -91,18 +84,29 @@ exports[`Header should mark the input as invalid 1`] = `
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
iconType="arrowRight"
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={true}
|
||||
labelType="label"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Next step"
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>
|
||||
<EuiButton
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
fill={true}
|
||||
iconSide="right"
|
||||
iconType="arrowRight"
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Next step"
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
|
@ -124,13 +128,8 @@ exports[`Header should render normally 1`] = `
|
|||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="flexEnd"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiForm
|
||||
isInvalid={false}
|
||||
>
|
||||
|
@ -138,43 +137,40 @@ exports[`Header should render normally 1`] = `
|
|||
describedByIds={Array []}
|
||||
display="row"
|
||||
error={Array []}
|
||||
fullWidth={false}
|
||||
fullWidth={true}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can use a {asterisk} as a wildcard in your index pattern."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
values={
|
||||
Object {
|
||||
"asterisk": <strong>
|
||||
*
|
||||
</strong>,
|
||||
}
|
||||
<React.Fragment>
|
||||
<FormattedMessage
|
||||
defaultMessage="Use an asterisk ({asterisk}) to match multiple indices."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
values={
|
||||
Object {
|
||||
"asterisk": <strong>
|
||||
*
|
||||
</strong>,
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can't use spaces or the characters {characterList}."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
values={
|
||||
Object {
|
||||
"characterList": <strong>
|
||||
%
|
||||
</strong>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Spaces and the characters {characterList} are not allowed."
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
values={
|
||||
Object {
|
||||
"characterList": <strong>
|
||||
%
|
||||
</strong>,
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
isInvalid={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Index pattern"
|
||||
defaultMessage="Index pattern name"
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPatternLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
|
@ -183,6 +179,7 @@ exports[`Header should render normally 1`] = `
|
|||
>
|
||||
<EuiFieldText
|
||||
data-test-subj="createIndexPatternNameInput"
|
||||
fullWidth={true}
|
||||
isInvalid={false}
|
||||
name="indexPattern"
|
||||
onChange={[Function]}
|
||||
|
@ -195,18 +192,29 @@ exports[`Header should render normally 1`] = `
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
iconType="arrowRight"
|
||||
isDisabled={false}
|
||||
onClick={[Function]}
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={true}
|
||||
labelType="label"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Next step"
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>
|
||||
<EuiButton
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
fill={true}
|
||||
iconSide="right"
|
||||
iconType="arrowRight"
|
||||
isDisabled={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Next step"
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,8 @@ describe('Header', () => {
|
|||
onQueryChanged={() => {}}
|
||||
goToNextStep={() => {}}
|
||||
isNextStepDisabled={false}
|
||||
onChangeIncludingSystemIndices={() => {}}
|
||||
isIncludingSystemIndices={false}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -48,6 +50,8 @@ describe('Header', () => {
|
|||
onQueryChanged={() => {}}
|
||||
goToNextStep={() => {}}
|
||||
isNextStepDisabled={true}
|
||||
onChangeIncludingSystemIndices={() => {}}
|
||||
isIncludingSystemIndices={false}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ import {
|
|||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiFieldText,
|
||||
EuiSwitchEvent,
|
||||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -41,6 +43,9 @@ interface HeaderProps {
|
|||
onQueryChanged: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
goToNextStep: (query: string) => void;
|
||||
isNextStepDisabled: boolean;
|
||||
showSystemIndices?: boolean;
|
||||
onChangeIncludingSystemIndices: (event: EuiSwitchEvent) => void;
|
||||
isIncludingSystemIndices: boolean;
|
||||
}
|
||||
|
||||
export const Header: React.FC<HeaderProps> = ({
|
||||
|
@ -51,6 +56,9 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
onQueryChanged,
|
||||
goToNextStep,
|
||||
isNextStepDisabled,
|
||||
showSystemIndices = false,
|
||||
onChangeIncludingSystemIndices,
|
||||
isIncludingSystemIndices,
|
||||
...rest
|
||||
}) => (
|
||||
<div {...rest}>
|
||||
|
@ -63,35 +71,32 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiForm isInvalid={isInputInvalid}>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPatternLabel"
|
||||
defaultMessage="Index pattern"
|
||||
defaultMessage="Index pattern name"
|
||||
/>
|
||||
}
|
||||
isInvalid={isInputInvalid}
|
||||
error={errors}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
defaultMessage="You can use a {asterisk} as a wildcard in your index pattern."
|
||||
values={{ asterisk: <strong>*</strong> }}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
defaultMessage="You can't use spaces or the characters {characterList}."
|
||||
values={{ characterList: <strong>{characterList}</strong> }}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.allowLabel"
|
||||
defaultMessage="Use an asterisk ({asterisk}) to match multiple indices."
|
||||
values={{ asterisk: <strong>*</strong> }}
|
||||
/>{' '}
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.indexPattern.disallowLabel"
|
||||
defaultMessage="Spaces and the characters {characterList} are not allowed."
|
||||
values={{ characterList: <strong>{characterList}</strong> }}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
|
@ -106,22 +111,43 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
isInvalid={isInputInvalid}
|
||||
onChange={onQueryChanged}
|
||||
data-test-subj="createIndexPatternNameInput"
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{showSystemIndices ? (
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.includeSystemIndicesToggleSwitchLabel"
|
||||
defaultMessage="Include system and hidden indices"
|
||||
/>
|
||||
}
|
||||
id="checkboxShowSystemIndices"
|
||||
checked={isIncludingSystemIndices}
|
||||
onChange={onChangeIncludingSystemIndices}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
) : null}
|
||||
</EuiForm>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
iconType="arrowRight"
|
||||
onClick={() => goToNextStep(query)}
|
||||
isDisabled={isNextStepDisabled}
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
defaultMessage="Next step"
|
||||
/>
|
||||
</EuiButton>
|
||||
<EuiFormRow hasEmptyLabelSpace>
|
||||
<EuiButton
|
||||
fill
|
||||
iconSide="right"
|
||||
iconType="arrowRight"
|
||||
onClick={() => goToNextStep(query)}
|
||||
isDisabled={isNextStepDisabled}
|
||||
data-test-subj="createIndexPatternGoToStep2Button"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.nextStepButton"
|
||||
defaultMessage="Next step"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
import React from 'react';
|
||||
import { IndicesList } from '../indices_list';
|
||||
import { shallow } from 'enzyme';
|
||||
import { MatchedItem } from '../../../../types';
|
||||
|
||||
const indices = [
|
||||
const indices = ([
|
||||
{ name: 'kibana', tags: [] },
|
||||
{ name: 'es', tags: [] },
|
||||
];
|
||||
] as unknown) as MatchedItem[];
|
||||
|
||||
describe('IndicesList', () => {
|
||||
it('should render normally', () => {
|
||||
|
|
|
@ -39,10 +39,10 @@ import { Pager } from '@elastic/eui';
|
|||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { PER_PAGE_INCREMENTS } from '../../../../constants';
|
||||
import { MatchedIndex, Tag } from '../../../../types';
|
||||
import { MatchedItem, Tag } from '../../../../types';
|
||||
|
||||
interface IndicesListProps {
|
||||
indices: MatchedIndex[];
|
||||
indices: MatchedItem[];
|
||||
query: string;
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ export class IndicesList extends React.Component<IndicesListProps, IndicesListSt
|
|||
<EuiTableRowCell>
|
||||
{index.tags.map((tag: Tag) => {
|
||||
return (
|
||||
<EuiBadge key={`index_${key}_tag_${tag.key}`} color="primary">
|
||||
<EuiBadge key={`index_${key}_tag_${tag.key}`} color={tag.color}>
|
||||
{tag.name}
|
||||
</EuiBadge>
|
||||
);
|
||||
|
|
|
@ -1,67 +1,44 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`StatusMessage should render with exact matches 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="success"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
iconType="check"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="secondary"
|
||||
>
|
||||
<EuiIcon
|
||||
type="check"
|
||||
/>
|
||||
title={
|
||||
<span>
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="{strongSuccess} Your index pattern matches {strongIndices}."
|
||||
defaultMessage="Your index pattern matches {sourceCount} {sourceCount, plural, one {source} other {sources} }."
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.successDetail"
|
||||
values={
|
||||
Object {
|
||||
"strongIndices": <strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{indicesLength, plural, one {# index} other {# indices}}"
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.strongIndicesLabel"
|
||||
values={
|
||||
Object {
|
||||
"indicesLength": 1,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</strong>,
|
||||
"strongSuccess": <strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="Success!"
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.strongSuccessLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</strong>,
|
||||
"sourceCount": 1,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`StatusMessage should render with no partial matches 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
>
|
||||
title={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="The index pattern you've entered doesn't match any indices. You can match {indicesLength, plural, one {your} other {any of your}} {strongIndices}, below."
|
||||
defaultMessage="The index pattern you've entered doesn't match any indices. You can match {indicesLength, plural, one {your} other {any of your} } {strongIndices}, below."
|
||||
id="indexPatternManagement.createIndexPattern.step.status.notMatchLabel.notMatchDetail"
|
||||
values={
|
||||
Object {
|
||||
"indicesLength": 2,
|
||||
"strongIndices": <strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{indicesLength, plural, one {# index} other {# indices}}"
|
||||
defaultMessage="{indicesLength, plural, one {# index} other {# indices} }"
|
||||
id="indexPatternManagement.createIndexPattern.step.status.notMatchLabel.allIndicesLabel"
|
||||
values={
|
||||
Object {
|
||||
|
@ -74,28 +51,26 @@ exports[`StatusMessage should render with no partial matches 1`] = `
|
|||
}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`StatusMessage should render with partial matches 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="primary"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
>
|
||||
title={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your index pattern doesn't match any indices, but you have {strongIndices} which {matchedIndicesLength, plural, one {looks} other {look}} similar."
|
||||
defaultMessage="Your index pattern doesn't match any indices, but you have {strongIndices} which {matchedIndicesLength, plural, one {looks} other {look} } similar."
|
||||
id="indexPatternManagement.createIndexPattern.step.status.partialMatchLabel.partialMatchDetail"
|
||||
values={
|
||||
Object {
|
||||
"matchedIndicesLength": 1,
|
||||
"strongIndices": <strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{matchedIndicesLength, plural, one {# index} other {# indices}}"
|
||||
defaultMessage="{matchedIndicesLength, plural, one {index} other {# indices} }"
|
||||
id="indexPatternManagement.createIndexPattern.step.status.partialMatchLabel.strongIndicesLabel"
|
||||
values={
|
||||
Object {
|
||||
|
@ -108,44 +83,37 @@ exports[`StatusMessage should render with partial matches 1`] = `
|
|||
}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`StatusMessage should render without a query 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="primary"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
>
|
||||
title={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your index pattern can match any of your {strongIndices}, below."
|
||||
defaultMessage="Your index pattern can match {sourceCount, plural, one {your # source} other {any of your # sources} }."
|
||||
id="indexPatternManagement.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail"
|
||||
values={
|
||||
Object {
|
||||
"strongIndices": <strong>
|
||||
2
|
||||
indices
|
||||
</strong>,
|
||||
"sourceCount": 2,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`StatusMessage should show that no indices exist 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="primary"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
>
|
||||
title={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="No Elasticsearch indices match your pattern."
|
||||
|
@ -153,18 +121,16 @@ exports[`StatusMessage should show that no indices exist 1`] = `
|
|||
values={Object {}}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`StatusMessage should show that system indices exist 1`] = `
|
||||
<EuiText
|
||||
<EuiCallOut
|
||||
color="primary"
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
size="s"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
>
|
||||
title={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="No Elasticsearch indices match your pattern."
|
||||
|
@ -172,6 +138,6 @@ exports[`StatusMessage should show that system indices exist 1`] = `
|
|||
values={Object {}}
|
||||
/>
|
||||
</span>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -20,18 +20,19 @@
|
|||
import React from 'react';
|
||||
import { StatusMessage } from '../status_message';
|
||||
import { shallow } from 'enzyme';
|
||||
import { MatchedItem } from '../../../../types';
|
||||
|
||||
const tagsPartial = {
|
||||
tags: [],
|
||||
};
|
||||
|
||||
const matchedIndices = {
|
||||
allIndices: [
|
||||
allIndices: ([
|
||||
{ name: 'kibana', ...tagsPartial },
|
||||
{ name: 'es', ...tagsPartial },
|
||||
],
|
||||
exactMatchedIndices: [],
|
||||
partialMatchedIndices: [{ name: 'kibana', ...tagsPartial }],
|
||||
] as unknown) as MatchedItem[],
|
||||
exactMatchedIndices: [] as MatchedItem[],
|
||||
partialMatchedIndices: ([{ name: 'kibana', ...tagsPartial }] as unknown) as MatchedItem[],
|
||||
};
|
||||
|
||||
describe('StatusMessage', () => {
|
||||
|
@ -51,7 +52,7 @@ describe('StatusMessage', () => {
|
|||
it('should render with exact matches', () => {
|
||||
const localMatchedIndices = {
|
||||
...matchedIndices,
|
||||
exactMatchedIndices: [{ name: 'kibana', ...tagsPartial }],
|
||||
exactMatchedIndices: ([{ name: 'kibana', ...tagsPartial }] as unknown) as MatchedItem[],
|
||||
};
|
||||
|
||||
const component = shallow(
|
||||
|
|
|
@ -19,16 +19,17 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiText, EuiTextColor, EuiIcon } from '@elastic/eui';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { EuiIconType } from '@elastic/eui/src/components/icon/icon';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { MatchedIndex } from '../../../../types';
|
||||
import { MatchedItem } from '../../../../types';
|
||||
|
||||
interface StatusMessageProps {
|
||||
matchedIndices: {
|
||||
allIndices: MatchedIndex[];
|
||||
exactMatchedIndices: MatchedIndex[];
|
||||
partialMatchedIndices: MatchedIndex[];
|
||||
allIndices: MatchedItem[];
|
||||
exactMatchedIndices: MatchedItem[];
|
||||
partialMatchedIndices: MatchedItem[];
|
||||
};
|
||||
isIncludingSystemIndices: boolean;
|
||||
query: string;
|
||||
|
@ -41,23 +42,26 @@ export const StatusMessage: React.FC<StatusMessageProps> = ({
|
|||
query,
|
||||
showSystemIndices,
|
||||
}) => {
|
||||
let statusIcon;
|
||||
let statusIcon: EuiIconType | undefined;
|
||||
let statusMessage;
|
||||
let statusColor: 'default' | 'secondary' | undefined;
|
||||
let statusColor: 'primary' | 'success' | 'warning' | undefined;
|
||||
|
||||
const allIndicesLength = allIndices.length;
|
||||
|
||||
if (query.length === 0) {
|
||||
statusIcon = null;
|
||||
statusColor = 'default';
|
||||
statusIcon = undefined;
|
||||
statusColor = 'primary';
|
||||
|
||||
if (allIndicesLength > 1) {
|
||||
if (allIndicesLength >= 1) {
|
||||
statusMessage = (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail"
|
||||
defaultMessage="Your index pattern can match any of your {strongIndices}, below."
|
||||
values={{ strongIndices: <strong>{allIndicesLength} indices</strong> }}
|
||||
defaultMessage="Your index pattern can match {sourceCount, plural,
|
||||
one {your # source}
|
||||
other {any of your # sources}
|
||||
}."
|
||||
values={{ sourceCount: allIndicesLength }}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
|
@ -66,8 +70,7 @@ export const StatusMessage: React.FC<StatusMessageProps> = ({
|
|||
<span>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.noSystemIndicesWithPromptLabel"
|
||||
defaultMessage="No Elasticsearch indices match your pattern. To view the matching system indices, toggle the switch in
|
||||
the upper right."
|
||||
defaultMessage="No Elasticsearch indices match your pattern. To view the matching system indices, toggle the switch above."
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
|
@ -83,51 +86,44 @@ export const StatusMessage: React.FC<StatusMessageProps> = ({
|
|||
}
|
||||
} else if (exactMatchedIndices.length) {
|
||||
statusIcon = 'check';
|
||||
statusColor = 'secondary';
|
||||
statusColor = 'success';
|
||||
statusMessage = (
|
||||
<span>
|
||||
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.successDetail"
|
||||
defaultMessage="{strongSuccess} Your index pattern matches {strongIndices}."
|
||||
defaultMessage="Your index pattern matches {sourceCount} {sourceCount, plural,
|
||||
one {source}
|
||||
other {sources}
|
||||
}."
|
||||
values={{
|
||||
strongSuccess: (
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.strongSuccessLabel"
|
||||
defaultMessage="Success!"
|
||||
/>
|
||||
</strong>
|
||||
),
|
||||
strongIndices: (
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.successLabel.strongIndicesLabel"
|
||||
defaultMessage="{indicesLength, plural, one {# index} other {# indices}}"
|
||||
values={{ indicesLength: exactMatchedIndices.length }}
|
||||
/>
|
||||
</strong>
|
||||
),
|
||||
sourceCount: exactMatchedIndices.length,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
} else if (partialMatchedIndices.length) {
|
||||
statusIcon = null;
|
||||
statusColor = 'default';
|
||||
statusIcon = undefined;
|
||||
statusColor = 'primary';
|
||||
statusMessage = (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.partialMatchLabel.partialMatchDetail"
|
||||
defaultMessage="Your index pattern doesn't match any indices, but you have {strongIndices} which
|
||||
{matchedIndicesLength, plural, one {looks} other {look}} similar."
|
||||
{matchedIndicesLength, plural,
|
||||
one {looks}
|
||||
other {look}
|
||||
} similar."
|
||||
values={{
|
||||
matchedIndicesLength: partialMatchedIndices.length,
|
||||
strongIndices: (
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.partialMatchLabel.strongIndicesLabel"
|
||||
defaultMessage="{matchedIndicesLength, plural, one {# index} other {# indices}}"
|
||||
defaultMessage="{matchedIndicesLength, plural,
|
||||
one {index}
|
||||
other {# indices}
|
||||
}"
|
||||
values={{ matchedIndicesLength: partialMatchedIndices.length }}
|
||||
/>
|
||||
</strong>
|
||||
|
@ -137,20 +133,26 @@ export const StatusMessage: React.FC<StatusMessageProps> = ({
|
|||
</span>
|
||||
);
|
||||
} else if (allIndicesLength) {
|
||||
statusIcon = null;
|
||||
statusColor = 'default';
|
||||
statusIcon = undefined;
|
||||
statusColor = 'warning';
|
||||
statusMessage = (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.notMatchLabel.notMatchDetail"
|
||||
defaultMessage="The index pattern you've entered doesn't match any indices.
|
||||
You can match {indicesLength, plural, one {your} other {any of your}} {strongIndices}, below."
|
||||
You can match {indicesLength, plural,
|
||||
one {your}
|
||||
other {any of your}
|
||||
} {strongIndices}, below."
|
||||
values={{
|
||||
strongIndices: (
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.step.status.notMatchLabel.allIndicesLabel"
|
||||
defaultMessage="{indicesLength, plural, one {# index} other {# indices}}"
|
||||
defaultMessage="{indicesLength, plural,
|
||||
one {# index}
|
||||
other {# indices}
|
||||
}"
|
||||
values={{ indicesLength: allIndicesLength }}
|
||||
/>
|
||||
</strong>
|
||||
|
@ -163,11 +165,12 @@ export const StatusMessage: React.FC<StatusMessageProps> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiText size="s" data-test-subj="createIndexPatternStatusMessage">
|
||||
<EuiTextColor color={statusColor}>
|
||||
{statusIcon ? <EuiIcon type={statusIcon} /> : null}
|
||||
{statusMessage}
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
<EuiCallOut
|
||||
size="s"
|
||||
color={statusColor}
|
||||
data-test-subj="createIndexPatternStatusMessage"
|
||||
iconType={statusIcon}
|
||||
title={statusMessage}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { SavedObjectsFindResponsePublic } from 'kibana/public';
|
||||
import { StepIndexPattern } from '../step_index_pattern';
|
||||
import { StepIndexPattern, canPreselectTimeField } from './step_index_pattern';
|
||||
import { Header } from './components/header';
|
||||
import { IndexPatternCreationConfig } from '../../../../../../../plugins/index_pattern_management/public';
|
||||
import { mockManagementPlugin } from '../../../../mocks';
|
||||
|
@ -38,16 +38,16 @@ const mockIndexPatternCreationType = new IndexPatternCreationConfig({
|
|||
jest.mock('../../lib/get_indices', () => ({
|
||||
getIndices: ({}, {}, query: string) => {
|
||||
if (query.startsWith('e')) {
|
||||
return [{ name: 'es' }];
|
||||
return [{ name: 'es', item: {} }];
|
||||
}
|
||||
|
||||
return [{ name: 'kibana' }];
|
||||
return [{ name: 'kibana', item: {} }];
|
||||
},
|
||||
}));
|
||||
|
||||
const allIndices = [
|
||||
{ name: 'kibana', tags: [] },
|
||||
{ name: 'es', tags: [] },
|
||||
{ name: 'kibana', tags: [], item: {} },
|
||||
{ name: 'es', tags: [], item: {} },
|
||||
];
|
||||
|
||||
const goToNextStep = () => {};
|
||||
|
@ -205,4 +205,53 @@ describe('StepIndexPattern', () => {
|
|||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
expect(component.state('exactMatchedIndices')).toEqual([]);
|
||||
});
|
||||
|
||||
it('it can preselect time field', async () => {
|
||||
const dataStream1 = {
|
||||
name: 'data stream 1',
|
||||
tags: [],
|
||||
item: { name: 'data stream 1', backing_indices: [], timestamp_field: 'timestamp_field' },
|
||||
};
|
||||
|
||||
const dataStream2 = {
|
||||
name: 'data stream 2',
|
||||
tags: [],
|
||||
item: { name: 'data stream 2', backing_indices: [], timestamp_field: 'timestamp_field' },
|
||||
};
|
||||
|
||||
const differentDataStream = {
|
||||
name: 'different data stream',
|
||||
tags: [],
|
||||
item: { name: 'different data stream 2', backing_indices: [], timestamp_field: 'x' },
|
||||
};
|
||||
|
||||
const index = {
|
||||
name: 'index',
|
||||
tags: [],
|
||||
item: {
|
||||
name: 'index',
|
||||
},
|
||||
};
|
||||
|
||||
const alias = {
|
||||
name: 'alias',
|
||||
tags: [],
|
||||
item: {
|
||||
name: 'alias',
|
||||
indices: [],
|
||||
},
|
||||
};
|
||||
|
||||
expect(canPreselectTimeField([index])).toEqual(undefined);
|
||||
expect(canPreselectTimeField([alias])).toEqual(undefined);
|
||||
expect(canPreselectTimeField([index, alias, dataStream1])).toEqual(undefined);
|
||||
|
||||
expect(canPreselectTimeField([dataStream1])).toEqual('timestamp_field');
|
||||
|
||||
expect(canPreselectTimeField([dataStream1, dataStream2])).toEqual('timestamp_field');
|
||||
|
||||
expect(canPreselectTimeField([dataStream1, dataStream2, differentDataStream])).toEqual(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { EuiPanel, EuiSpacer, EuiCallOut } from '@elastic/eui';
|
||||
import { EuiSpacer, EuiCallOut, EuiSwitchEvent } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
|
@ -26,7 +26,6 @@ import {
|
|||
IndexPatternAttributes,
|
||||
UI_SETTINGS,
|
||||
} from '../../../../../../../plugins/data/public';
|
||||
import { MAX_SEARCH_SIZE } from '../../constants';
|
||||
import {
|
||||
getIndices,
|
||||
containsIllegalCharacters,
|
||||
|
@ -40,20 +39,20 @@ import { IndicesList } from './components/indices_list';
|
|||
import { Header } from './components/header';
|
||||
import { context as contextType } from '../../../../../../kibana_react/public';
|
||||
import { IndexPatternCreationConfig } from '../../../../../../../plugins/index_pattern_management/public';
|
||||
import { MatchedIndex } from '../../types';
|
||||
import { MatchedItem } from '../../types';
|
||||
import { IndexPatternManagmentContextValue } from '../../../../types';
|
||||
|
||||
interface StepIndexPatternProps {
|
||||
allIndices: MatchedIndex[];
|
||||
isIncludingSystemIndices: boolean;
|
||||
allIndices: MatchedItem[];
|
||||
indexPatternCreationType: IndexPatternCreationConfig;
|
||||
goToNextStep: (query: string) => void;
|
||||
goToNextStep: (query: string, timestampField?: string) => void;
|
||||
initialQuery?: string;
|
||||
showSystemIndices: boolean;
|
||||
}
|
||||
|
||||
interface StepIndexPatternState {
|
||||
partialMatchedIndices: MatchedIndex[];
|
||||
exactMatchedIndices: MatchedIndex[];
|
||||
partialMatchedIndices: MatchedItem[];
|
||||
exactMatchedIndices: MatchedItem[];
|
||||
isLoadingIndices: boolean;
|
||||
existingIndexPatterns: string[];
|
||||
indexPatternExists: boolean;
|
||||
|
@ -61,8 +60,35 @@ interface StepIndexPatternState {
|
|||
appendedWildcard: boolean;
|
||||
showingIndexPatternQueryErrors: boolean;
|
||||
indexPatternName: string;
|
||||
isIncludingSystemIndices: boolean;
|
||||
}
|
||||
|
||||
export const canPreselectTimeField = (indices: MatchedItem[]) => {
|
||||
const preselectStatus = indices.reduce(
|
||||
(
|
||||
{ canPreselect, timeFieldName }: { canPreselect: boolean; timeFieldName?: string },
|
||||
matchedItem
|
||||
) => {
|
||||
const dataStreamItem = matchedItem.item;
|
||||
const dataStreamTimestampField = dataStreamItem.timestamp_field;
|
||||
const isDataStream = !!dataStreamItem.timestamp_field;
|
||||
const timestampFieldMatches =
|
||||
timeFieldName === undefined || timeFieldName === dataStreamTimestampField;
|
||||
|
||||
return {
|
||||
canPreselect: canPreselect && isDataStream && timestampFieldMatches,
|
||||
timeFieldName: dataStreamTimestampField || timeFieldName,
|
||||
};
|
||||
},
|
||||
{
|
||||
canPreselect: true,
|
||||
timeFieldName: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
return preselectStatus.canPreselect ? preselectStatus.timeFieldName : undefined;
|
||||
};
|
||||
|
||||
export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndexPatternState> {
|
||||
static contextType = contextType;
|
||||
|
||||
|
@ -78,9 +104,9 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
appendedWildcard: false,
|
||||
showingIndexPatternQueryErrors: false,
|
||||
indexPatternName: '',
|
||||
isIncludingSystemIndices: false,
|
||||
};
|
||||
ILLEGAL_CHARACTERS = [...indexPatterns.ILLEGAL_CHARACTERS];
|
||||
lastQuery: string | undefined;
|
||||
|
||||
constructor(props: StepIndexPatternProps, context: IndexPatternManagmentContextValue) {
|
||||
super(props, context);
|
||||
|
@ -91,6 +117,8 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
this.state.indexPatternName = indexPatternCreationType.getIndexPatternName();
|
||||
}
|
||||
|
||||
lastQuery = '';
|
||||
|
||||
async UNSAFE_componentWillMount() {
|
||||
this.fetchExistingIndexPatterns();
|
||||
if (this.state.query) {
|
||||
|
@ -129,10 +157,10 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
if (query.endsWith('*')) {
|
||||
const exactMatchedIndices = await ensureMinimumTime(
|
||||
getIndices(
|
||||
this.context.services.data.search.__LEGACY.esClient,
|
||||
this.context.services.http,
|
||||
indexPatternCreationType,
|
||||
query,
|
||||
MAX_SEARCH_SIZE
|
||||
this.state.isIncludingSystemIndices
|
||||
)
|
||||
);
|
||||
// If the search changed, discard this state
|
||||
|
@ -145,16 +173,16 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
|
||||
const [partialMatchedIndices, exactMatchedIndices] = await ensureMinimumTime([
|
||||
getIndices(
|
||||
this.context.services.data.search.__LEGACY.esClient,
|
||||
this.context.services.http,
|
||||
indexPatternCreationType,
|
||||
`${query}*`,
|
||||
MAX_SEARCH_SIZE
|
||||
this.state.isIncludingSystemIndices
|
||||
),
|
||||
getIndices(
|
||||
this.context.services.data.search.__LEGACY.esClient,
|
||||
this.context.services.http,
|
||||
indexPatternCreationType,
|
||||
query,
|
||||
MAX_SEARCH_SIZE
|
||||
this.state.isIncludingSystemIndices
|
||||
),
|
||||
]);
|
||||
|
||||
|
@ -202,12 +230,12 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
}
|
||||
|
||||
renderStatusMessage(matchedIndices: {
|
||||
allIndices: MatchedIndex[];
|
||||
exactMatchedIndices: MatchedIndex[];
|
||||
partialMatchedIndices: MatchedIndex[];
|
||||
allIndices: MatchedItem[];
|
||||
exactMatchedIndices: MatchedItem[];
|
||||
partialMatchedIndices: MatchedItem[];
|
||||
}) {
|
||||
const { indexPatternCreationType, isIncludingSystemIndices } = this.props;
|
||||
const { query, isLoadingIndices, indexPatternExists } = this.state;
|
||||
const { indexPatternCreationType } = this.props;
|
||||
const { query, isLoadingIndices, indexPatternExists, isIncludingSystemIndices } = this.state;
|
||||
|
||||
if (isLoadingIndices || indexPatternExists) {
|
||||
return null;
|
||||
|
@ -227,8 +255,8 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
visibleIndices,
|
||||
allIndices,
|
||||
}: {
|
||||
visibleIndices: MatchedIndex[];
|
||||
allIndices: MatchedIndex[];
|
||||
visibleIndices: MatchedItem[];
|
||||
allIndices: MatchedItem[];
|
||||
}) {
|
||||
const { query, isLoadingIndices, indexPatternExists } = this.state;
|
||||
|
||||
|
@ -268,13 +296,14 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
);
|
||||
}
|
||||
|
||||
renderHeader({ exactMatchedIndices: indices }: { exactMatchedIndices: MatchedIndex[] }) {
|
||||
renderHeader({ exactMatchedIndices: indices }: { exactMatchedIndices: MatchedItem[] }) {
|
||||
const { goToNextStep, indexPatternCreationType } = this.props;
|
||||
const {
|
||||
query,
|
||||
showingIndexPatternQueryErrors,
|
||||
indexPatternExists,
|
||||
indexPatternName,
|
||||
isIncludingSystemIndices,
|
||||
} = this.state;
|
||||
|
||||
let containsErrors = false;
|
||||
|
@ -316,15 +345,24 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
characterList={characterList}
|
||||
query={query}
|
||||
onQueryChanged={this.onQueryChanged}
|
||||
goToNextStep={goToNextStep}
|
||||
goToNextStep={() => goToNextStep(query, canPreselectTimeField(indices))}
|
||||
isNextStepDisabled={isNextStepDisabled}
|
||||
onChangeIncludingSystemIndices={this.onChangeIncludingSystemIndices}
|
||||
isIncludingSystemIndices={isIncludingSystemIndices}
|
||||
showSystemIndices={this.props.showSystemIndices}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onChangeIncludingSystemIndices = (event: EuiSwitchEvent) => {
|
||||
this.setState({ isIncludingSystemIndices: event.target.checked }, () =>
|
||||
this.fetchIndices(this.state.query)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isIncludingSystemIndices, allIndices } = this.props;
|
||||
const { partialMatchedIndices, exactMatchedIndices } = this.state;
|
||||
const { allIndices } = this.props;
|
||||
const { partialMatchedIndices, exactMatchedIndices, isIncludingSystemIndices } = this.state;
|
||||
|
||||
const matchedIndices = getMatchedIndices(
|
||||
allIndices,
|
||||
|
@ -334,15 +372,15 @@ export class StepIndexPattern extends Component<StepIndexPatternProps, StepIndex
|
|||
);
|
||||
|
||||
return (
|
||||
<EuiPanel paddingSize="l">
|
||||
<>
|
||||
{this.renderHeader(matchedIndices)}
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer />
|
||||
{this.renderLoadingState()}
|
||||
{this.renderIndexPatternExists()}
|
||||
{this.renderStatusMessage(matchedIndices)}
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer />
|
||||
{this.renderList(matchedIndices)}
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@ exports[`StepTimeField should enable the action button if the user decides to no
|
|||
`;
|
||||
|
||||
exports[`StepTimeField should render "Custom index pattern ID already exists" when error is "Conflict" 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -34,9 +32,7 @@ exports[`StepTimeField should render "Custom index pattern ID already exists" wh
|
|||
onTimeFieldChanged={[Function]}
|
||||
timeFieldOptions={Array []}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -73,38 +69,45 @@ exports[`StepTimeField should render "Custom index pattern ID already exists" wh
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render a loading state when creating the index pattern 1`] = `
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
direction="column"
|
||||
gutterSize="s"
|
||||
justifyContent="center"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
<EuiTitle
|
||||
size="s"
|
||||
>
|
||||
<EuiLoadingSpinner />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiText>
|
||||
<h3
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Creating index pattern…"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.creatingLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiLoadingSpinner
|
||||
size="l"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render a selected timeField 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -137,9 +140,7 @@ exports[`StepTimeField should render a selected timeField 1`] = `
|
|||
]
|
||||
}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -154,13 +155,11 @@ exports[`StepTimeField should render a selected timeField 1`] = `
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render advanced options 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -175,9 +174,7 @@ exports[`StepTimeField should render advanced options 1`] = `
|
|||
onTimeFieldChanged={[Function]}
|
||||
timeFieldOptions={Array []}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -192,13 +189,11 @@ exports[`StepTimeField should render advanced options 1`] = `
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render advanced options with an index pattern id 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -213,9 +208,7 @@ exports[`StepTimeField should render advanced options with an index pattern id 1
|
|||
onTimeFieldChanged={[Function]}
|
||||
timeFieldOptions={Array []}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId="foobar"
|
||||
isVisible={false}
|
||||
|
@ -230,13 +223,11 @@ exports[`StepTimeField should render advanced options with an index pattern id 1
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render any error message 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -251,9 +242,7 @@ exports[`StepTimeField should render any error message 1`] = `
|
|||
onTimeFieldChanged={[Function]}
|
||||
timeFieldOptions={Array []}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -286,13 +275,11 @@ exports[`StepTimeField should render any error message 1`] = `
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render normally 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -307,9 +294,7 @@ exports[`StepTimeField should render normally 1`] = `
|
|||
onTimeFieldChanged={[Function]}
|
||||
timeFieldOptions={Array []}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -324,13 +309,11 @@ exports[`StepTimeField should render normally 1`] = `
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`StepTimeField should render timeFields 1`] = `
|
||||
<EuiPanel
|
||||
paddingSize="l"
|
||||
>
|
||||
<Fragment>
|
||||
<Header
|
||||
indexPattern="ki*"
|
||||
indexPatternName="name"
|
||||
|
@ -362,9 +345,7 @@ exports[`StepTimeField should render timeFields 1`] = `
|
|||
]
|
||||
}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
indexPatternId=""
|
||||
isVisible={false}
|
||||
|
@ -379,5 +360,5 @@ exports[`StepTimeField should render timeFields 1`] = `
|
|||
goToPreviousStep={[Function]}
|
||||
submittable={false}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -16,21 +16,10 @@ exports[`Header should render normally 1`] = `
|
|||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiText
|
||||
color="subdued"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="You've defined {indexPattern} as your {indexPatternName}. Now you can specify some settings before we create it."
|
||||
id="indexPatternManagement.createIndexPattern.stepTimeLabel"
|
||||
values={
|
||||
Object {
|
||||
"indexPattern": <strong>
|
||||
ki*
|
||||
</strong>,
|
||||
"indexPatternName": "ki*",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<EuiText>
|
||||
<strong>
|
||||
ki*
|
||||
</strong>
|
||||
</EuiText>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -39,15 +39,8 @@ export const Header: React.FC<HeaderProps> = ({ indexPattern, indexPatternName }
|
|||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText color="subdued">
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTimeLabel"
|
||||
defaultMessage="You've defined {indexPattern} as your {indexPatternName}. Now you can specify some settings before we create it."
|
||||
values={{
|
||||
indexPattern: <strong>{indexPattern}</strong>,
|
||||
indexPatternName,
|
||||
}}
|
||||
/>
|
||||
<EuiText>
|
||||
<strong>{indexPattern}</strong>
|
||||
</EuiText>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,55 +2,33 @@
|
|||
|
||||
exports[`TimeField should render a loading state 1`] = `
|
||||
<EuiForm>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Select a primary time field for use with the global time filter."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.timeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="The Time Filter will use this field to filter your data by time."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can choose not to have a time field, but you will not be able to narrow down your data by a time range."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldWarningLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
gutterSize="xs"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Time Filter field name"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldHeader"
|
||||
values={Object {}}
|
||||
/>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiLoadingSpinner
|
||||
size="s"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<FormattedMessage
|
||||
defaultMessage="Time field"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelAppend={
|
||||
<EuiLoadingSpinner
|
||||
size="s"
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
|
@ -73,62 +51,43 @@ exports[`TimeField should render a loading state 1`] = `
|
|||
|
||||
exports[`TimeField should render a selected time field 1`] = `
|
||||
<EuiForm>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Select a primary time field for use with the global time filter."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.timeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="The Time Filter will use this field to filter your data by time."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can choose not to have a time field, but you will not be able to narrow down your data by a time range."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldWarningLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
gutterSize="xs"
|
||||
justifyContent="spaceBetween"
|
||||
<FormattedMessage
|
||||
defaultMessage="Time field"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelAppend={
|
||||
<EuiText
|
||||
size="xs"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
<EuiLink
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Time Filter field name"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldHeader"
|
||||
values={Object {}}
|
||||
/>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiLink
|
||||
className="timeFieldRefreshButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Refresh"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.refreshButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<FormattedMessage
|
||||
defaultMessage="Refresh"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.refreshButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
|
@ -154,62 +113,43 @@ exports[`TimeField should render a selected time field 1`] = `
|
|||
|
||||
exports[`TimeField should render normally 1`] = `
|
||||
<EuiForm>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Select a primary time field for use with the global time filter."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.timeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="The Time Filter will use this field to filter your data by time."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="You can choose not to have a time field, but you will not be able to narrow down your data by a time range."
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldWarningLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
gutterSize="xs"
|
||||
justifyContent="spaceBetween"
|
||||
<FormattedMessage
|
||||
defaultMessage="Time field"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelAppend={
|
||||
<EuiText
|
||||
size="xs"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
<EuiLink
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Time Filter field name"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldHeader"
|
||||
values={Object {}}
|
||||
/>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiLink
|
||||
className="timeFieldRefreshButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Refresh"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.refreshButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<FormattedMessage
|
||||
defaultMessage="Refresh"
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.refreshButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
|
|
|
@ -24,8 +24,7 @@ import React from 'react';
|
|||
import {
|
||||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiSpacer,
|
||||
EuiLink,
|
||||
EuiSelect,
|
||||
EuiText,
|
||||
|
@ -54,77 +53,68 @@ export const TimeField: React.FC<TimeFieldProps> = ({
|
|||
}) => (
|
||||
<EuiForm>
|
||||
{isVisible ? (
|
||||
<EuiFormRow
|
||||
label={
|
||||
<EuiFlexGroup gutterSize="xs" justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldHeader"
|
||||
defaultMessage="Time Filter field name"
|
||||
/>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{isLoading ? (
|
||||
<EuiLoadingSpinner size="s" />
|
||||
) : (
|
||||
<EuiLink className="timeFieldRefreshButton" onClick={fetchTimeFields}>
|
||||
<>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.timeDescription"
|
||||
defaultMessage="Select a primary time field for use with the global time filter."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
defaultMessage="Time field"
|
||||
/>
|
||||
}
|
||||
labelAppend={
|
||||
isLoading ? (
|
||||
<EuiLoadingSpinner size="s" />
|
||||
) : (
|
||||
<EuiText size="xs">
|
||||
<EuiLink onClick={fetchTimeFields}>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.refreshButton"
|
||||
defaultMessage="Refresh"
|
||||
/>
|
||||
</EuiLink>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
helpText={
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldLabel"
|
||||
defaultMessage="The Time Filter will use this field to filter your data by time."
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.fieldWarningLabel"
|
||||
defaultMessage="You can choose not to have a time field, but you will not be able to narrow down your data by a time range."
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{isLoading ? (
|
||||
<EuiSelect
|
||||
name="timeField"
|
||||
data-test-subj="createIndexPatternTimeFieldSelect"
|
||||
options={[
|
||||
{
|
||||
text: i18n.translate(
|
||||
'indexPatternManagement.createIndexPattern.stepTime.field.loadingDropDown',
|
||||
{
|
||||
defaultMessage: 'Loading…',
|
||||
}
|
||||
),
|
||||
value: '',
|
||||
},
|
||||
]}
|
||||
disabled={true}
|
||||
/>
|
||||
) : (
|
||||
<EuiSelect
|
||||
name="timeField"
|
||||
data-test-subj="createIndexPatternTimeFieldSelect"
|
||||
options={timeFieldOptions}
|
||||
isLoading={isLoading}
|
||||
disabled={isLoading}
|
||||
value={selectedTimeField}
|
||||
onChange={onTimeFieldChanged}
|
||||
/>
|
||||
)}
|
||||
</EuiFormRow>
|
||||
</EuiText>
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLoading ? (
|
||||
<EuiSelect
|
||||
name="timeField"
|
||||
data-test-subj="createIndexPatternTimeFieldSelect"
|
||||
options={[
|
||||
{
|
||||
text: i18n.translate(
|
||||
'indexPatternManagement.createIndexPattern.stepTime.field.loadingDropDown',
|
||||
{
|
||||
defaultMessage: 'Loading…',
|
||||
}
|
||||
),
|
||||
value: '',
|
||||
},
|
||||
]}
|
||||
disabled={true}
|
||||
/>
|
||||
) : (
|
||||
<EuiSelect
|
||||
name="timeField"
|
||||
data-test-subj="createIndexPatternTimeFieldSelect"
|
||||
options={timeFieldOptions}
|
||||
isLoading={isLoading}
|
||||
disabled={isLoading}
|
||||
value={selectedTimeField}
|
||||
onChange={onTimeFieldChanged}
|
||||
/>
|
||||
)}
|
||||
</EuiFormRow>
|
||||
</>
|
||||
) : (
|
||||
<EuiText>
|
||||
<p>
|
||||
|
|
|
@ -22,10 +22,10 @@ import {
|
|||
EuiCallOut,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiLoadingSpinner,
|
||||
EuiHorizontalRule,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { ensureMinimumTime, extractTimeFields } from '../../lib';
|
||||
|
@ -43,6 +43,7 @@ interface StepTimeFieldProps {
|
|||
goToPreviousStep: () => void;
|
||||
createIndexPattern: (selectedTimeField: string | undefined, indexPatternId: string) => void;
|
||||
indexPatternCreationType: IndexPatternCreationConfig;
|
||||
selectedTimeField?: string;
|
||||
}
|
||||
|
||||
interface StepTimeFieldState {
|
||||
|
@ -69,7 +70,7 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
|
||||
public readonly context!: IndexPatternManagmentContextValue;
|
||||
|
||||
state = {
|
||||
state: StepTimeFieldState = {
|
||||
error: '',
|
||||
timeFields: [],
|
||||
selectedTimeField: undefined,
|
||||
|
@ -86,6 +87,10 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
super(props);
|
||||
this.state.indexPatternType = props.indexPatternCreationType.getIndexPatternType() || '';
|
||||
this.state.indexPatternName = props.indexPatternCreationType.getIndexPatternName();
|
||||
this.state.selectedTimeField = props.selectedTimeField;
|
||||
if (props.selectedTimeField) {
|
||||
this.state.timeFieldSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
mounted = false;
|
||||
|
@ -183,21 +188,22 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
|
||||
if (isCreating) {
|
||||
return (
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
<EuiFlexGroup justifyContent="center" alignItems="center" direction="column" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="s">
|
||||
<h3 className="eui-textCenter">
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.stepTime.creatingLabel"
|
||||
defaultMessage="Creating index pattern…"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="l" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -236,7 +242,7 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
) : null;
|
||||
|
||||
return (
|
||||
<EuiPanel paddingSize="l">
|
||||
<>
|
||||
<Header indexPattern={indexPattern} indexPatternName={indexPatternName} />
|
||||
<EuiSpacer size="m" />
|
||||
<TimeField
|
||||
|
@ -247,7 +253,7 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
selectedTimeField={selectedTimeField}
|
||||
onTimeFieldChanged={this.onTimeFieldChanged}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiHorizontalRule />
|
||||
<AdvancedOptions
|
||||
isVisible={isAdvancedOptionsVisible}
|
||||
indexPatternId={indexPatternId}
|
||||
|
@ -261,7 +267,7 @@ export class StepTimeField extends Component<StepTimeFieldProps, StepTimeFieldSt
|
|||
submittable={submittable}
|
||||
createIndexPattern={this.createIndexPattern}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,16 @@
|
|||
|
||||
import React, { ReactElement, Component } from 'react';
|
||||
|
||||
import { EuiGlobalToastList, EuiGlobalToastListToast, EuiPanel } from '@elastic/eui';
|
||||
import {
|
||||
EuiGlobalToastList,
|
||||
EuiGlobalToastListToast,
|
||||
EuiPageContent,
|
||||
EuiHorizontalRule,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { DocLinksStart } from 'src/core/public';
|
||||
import { StepIndexPattern } from './components/step_index_pattern';
|
||||
import { StepTimeField } from './components/step_time_field';
|
||||
import { Header } from './components/header';
|
||||
|
@ -31,21 +37,21 @@ import { EmptyState } from './components/empty_state';
|
|||
|
||||
import { context as contextType } from '../../../../kibana_react/public';
|
||||
import { getCreateBreadcrumbs } from '../breadcrumbs';
|
||||
import { MAX_SEARCH_SIZE } from './constants';
|
||||
import { ensureMinimumTime, getIndices } from './lib';
|
||||
import { IndexPatternCreationConfig } from '../..';
|
||||
import { IndexPatternManagmentContextValue } from '../../types';
|
||||
import { MatchedIndex } from './types';
|
||||
import { MatchedItem } from './types';
|
||||
|
||||
interface CreateIndexPatternWizardState {
|
||||
step: number;
|
||||
indexPattern: string;
|
||||
allIndices: MatchedIndex[];
|
||||
allIndices: MatchedItem[];
|
||||
remoteClustersExist: boolean;
|
||||
isInitiallyLoadingIndices: boolean;
|
||||
isIncludingSystemIndices: boolean;
|
||||
toasts: EuiGlobalToastListToast[];
|
||||
indexPatternCreationType: IndexPatternCreationConfig;
|
||||
selectedTimeField?: string;
|
||||
docLinks: DocLinksStart;
|
||||
}
|
||||
|
||||
export class CreateIndexPatternWizard extends Component<
|
||||
|
@ -69,9 +75,9 @@ export class CreateIndexPatternWizard extends Component<
|
|||
allIndices: [],
|
||||
remoteClustersExist: false,
|
||||
isInitiallyLoadingIndices: true,
|
||||
isIncludingSystemIndices: false,
|
||||
toasts: [],
|
||||
indexPatternCreationType: context.services.indexPatternManagementStart.creation.getType(type),
|
||||
docLinks: context.services.docLinks,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,7 +86,7 @@ export class CreateIndexPatternWizard extends Component<
|
|||
}
|
||||
|
||||
catchAndWarn = async (
|
||||
asyncFn: Promise<MatchedIndex[]>,
|
||||
asyncFn: Promise<MatchedItem[]>,
|
||||
errorValue: [] | string[],
|
||||
errorMsg: ReactElement
|
||||
) => {
|
||||
|
@ -102,12 +108,6 @@ export class CreateIndexPatternWizard extends Component<
|
|||
};
|
||||
|
||||
fetchData = async () => {
|
||||
this.setState({
|
||||
allIndices: [],
|
||||
isInitiallyLoadingIndices: true,
|
||||
remoteClustersExist: false,
|
||||
});
|
||||
|
||||
const indicesFailMsg = (
|
||||
<FormattedMessage
|
||||
id="indexPatternManagement.createIndexPattern.loadIndicesFailMsg"
|
||||
|
@ -125,31 +125,21 @@ export class CreateIndexPatternWizard extends Component<
|
|||
// query local and remote indices, updating state independently
|
||||
ensureMinimumTime(
|
||||
this.catchAndWarn(
|
||||
getIndices(
|
||||
this.context.services.data.search.__LEGACY.esClient,
|
||||
this.state.indexPatternCreationType,
|
||||
`*`,
|
||||
MAX_SEARCH_SIZE
|
||||
),
|
||||
getIndices(this.context.services.http, this.state.indexPatternCreationType, `*`, false),
|
||||
[],
|
||||
indicesFailMsg
|
||||
)
|
||||
).then((allIndices: MatchedIndex[]) =>
|
||||
).then((allIndices: MatchedItem[]) =>
|
||||
this.setState({ allIndices, isInitiallyLoadingIndices: false })
|
||||
);
|
||||
|
||||
this.catchAndWarn(
|
||||
// if we get an error from remote cluster query, supply fallback value that allows user entry.
|
||||
// ['a'] is fallback value
|
||||
getIndices(
|
||||
this.context.services.data.search.__LEGACY.esClient,
|
||||
this.state.indexPatternCreationType,
|
||||
`*:*`,
|
||||
1
|
||||
),
|
||||
getIndices(this.context.services.http, this.state.indexPatternCreationType, `*:*`, false),
|
||||
['a'],
|
||||
clustersFailMsg
|
||||
).then((remoteIndices: string[] | MatchedIndex[]) =>
|
||||
).then((remoteIndices: string[] | MatchedItem[]) =>
|
||||
this.setState({ remoteClustersExist: !!remoteIndices.length })
|
||||
);
|
||||
};
|
||||
|
@ -189,7 +179,7 @@ export class CreateIndexPatternWizard extends Component<
|
|||
if (isConfirmed) {
|
||||
return history.push(`/patterns/${indexPatternId}`);
|
||||
} else {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,31 +191,21 @@ export class CreateIndexPatternWizard extends Component<
|
|||
history.push(`/patterns/${createdId}`);
|
||||
};
|
||||
|
||||
goToTimeFieldStep = (indexPattern: string) => {
|
||||
this.setState({ step: 2, indexPattern });
|
||||
goToTimeFieldStep = (indexPattern: string, selectedTimeField?: string) => {
|
||||
this.setState({ step: 2, indexPattern, selectedTimeField });
|
||||
};
|
||||
|
||||
goToIndexPatternStep = () => {
|
||||
this.setState({ step: 1 });
|
||||
};
|
||||
|
||||
onChangeIncludingSystemIndices = () => {
|
||||
this.setState((prevState) => ({
|
||||
isIncludingSystemIndices: !prevState.isIncludingSystemIndices,
|
||||
}));
|
||||
};
|
||||
|
||||
renderHeader() {
|
||||
const { isIncludingSystemIndices } = this.state;
|
||||
|
||||
return (
|
||||
<Header
|
||||
prompt={this.state.indexPatternCreationType.renderPrompt()}
|
||||
showSystemIndices={this.state.indexPatternCreationType.getShowSystemIndices()}
|
||||
isIncludingSystemIndices={isIncludingSystemIndices}
|
||||
onChangeIncludingSystemIndices={this.onChangeIncludingSystemIndices}
|
||||
indexPatternName={this.state.indexPatternCreationType.getIndexPatternName()}
|
||||
isBeta={this.state.indexPatternCreationType.getIsBeta()}
|
||||
docLinks={this.state.docLinks}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -234,7 +214,6 @@ export class CreateIndexPatternWizard extends Component<
|
|||
const {
|
||||
allIndices,
|
||||
isInitiallyLoadingIndices,
|
||||
isIncludingSystemIndices,
|
||||
step,
|
||||
indexPattern,
|
||||
remoteClustersExist,
|
||||
|
@ -244,8 +223,8 @@ export class CreateIndexPatternWizard extends Component<
|
|||
return <LoadingState />;
|
||||
}
|
||||
|
||||
const hasDataIndices = allIndices.some(({ name }: MatchedIndex) => !name.startsWith('.'));
|
||||
if (!hasDataIndices && !isIncludingSystemIndices && !remoteClustersExist) {
|
||||
const hasDataIndices = allIndices.some(({ name }: MatchedItem) => !name.startsWith('.'));
|
||||
if (!hasDataIndices && !remoteClustersExist) {
|
||||
return (
|
||||
<EmptyState
|
||||
onRefresh={this.fetchData}
|
||||
|
@ -254,29 +233,42 @@ export class CreateIndexPatternWizard extends Component<
|
|||
);
|
||||
}
|
||||
|
||||
const header = this.renderHeader();
|
||||
|
||||
if (step === 1) {
|
||||
const { location } = this.props;
|
||||
const initialQuery = new URLSearchParams(location.search).get('id') || undefined;
|
||||
|
||||
return (
|
||||
<StepIndexPattern
|
||||
allIndices={allIndices}
|
||||
initialQuery={indexPattern || initialQuery}
|
||||
isIncludingSystemIndices={isIncludingSystemIndices}
|
||||
indexPatternCreationType={this.state.indexPatternCreationType}
|
||||
goToNextStep={this.goToTimeFieldStep}
|
||||
/>
|
||||
<EuiPageContent>
|
||||
{header}
|
||||
<EuiHorizontalRule />
|
||||
<StepIndexPattern
|
||||
allIndices={allIndices}
|
||||
initialQuery={indexPattern || initialQuery}
|
||||
indexPatternCreationType={this.state.indexPatternCreationType}
|
||||
goToNextStep={this.goToTimeFieldStep}
|
||||
showSystemIndices={
|
||||
this.state.indexPatternCreationType.getShowSystemIndices() && this.state.step === 1
|
||||
}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
);
|
||||
}
|
||||
|
||||
if (step === 2) {
|
||||
return (
|
||||
<StepTimeField
|
||||
indexPattern={indexPattern}
|
||||
goToPreviousStep={this.goToIndexPatternStep}
|
||||
createIndexPattern={this.createIndexPattern}
|
||||
indexPatternCreationType={this.state.indexPatternCreationType}
|
||||
/>
|
||||
<EuiPageContent>
|
||||
{header}
|
||||
<EuiHorizontalRule />
|
||||
<StepTimeField
|
||||
indexPattern={indexPattern}
|
||||
goToPreviousStep={this.goToIndexPatternStep}
|
||||
createIndexPattern={this.createIndexPattern}
|
||||
indexPatternCreationType={this.state.indexPatternCreationType}
|
||||
selectedTimeField={this.state.selectedTimeField}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -290,15 +282,11 @@ export class CreateIndexPatternWizard extends Component<
|
|||
};
|
||||
|
||||
render() {
|
||||
const header = this.renderHeader();
|
||||
const content = this.renderContent();
|
||||
|
||||
return (
|
||||
<EuiPanel paddingSize={'l'}>
|
||||
<div>
|
||||
{header}
|
||||
{content}
|
||||
</div>
|
||||
<>
|
||||
{content}
|
||||
<EuiGlobalToastList
|
||||
toasts={this.state.toasts}
|
||||
dismissToast={({ id }) => {
|
||||
|
@ -306,7 +294,7 @@ export class CreateIndexPatternWizard extends Component<
|
|||
}}
|
||||
toastLifeTimeMs={6000}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getIndices response object to item array 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"item": Object {
|
||||
"attributes": Array [
|
||||
"frozen",
|
||||
],
|
||||
"name": "frozen_index",
|
||||
},
|
||||
"name": "frozen_index",
|
||||
"tags": Array [
|
||||
Object {
|
||||
"color": "default",
|
||||
"key": "index",
|
||||
"name": "Index",
|
||||
},
|
||||
Object {
|
||||
"color": "danger",
|
||||
"key": "frozen",
|
||||
"name": "Frozen",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"item": Object {
|
||||
"indices": Array [],
|
||||
"name": "test_alias",
|
||||
},
|
||||
"name": "test_alias",
|
||||
"tags": Array [
|
||||
Object {
|
||||
"color": "default",
|
||||
"key": "alias",
|
||||
"name": "Alias",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"item": Object {
|
||||
"backing_indices": Array [],
|
||||
"name": "test_data_stream",
|
||||
"timestamp_field": "test_timestamp_field",
|
||||
},
|
||||
"name": "test_data_stream",
|
||||
"tags": Array [
|
||||
Object {
|
||||
"color": "primary",
|
||||
"key": "data_stream",
|
||||
"name": "Data stream",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"item": Object {
|
||||
"name": "test_index",
|
||||
},
|
||||
"name": "test_index",
|
||||
"tags": Array [
|
||||
Object {
|
||||
"color": "default",
|
||||
"key": "index",
|
||||
"name": "Index",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -17,66 +17,31 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { getIndices } from './get_indices';
|
||||
import { getIndices, responseToItemArray } from './get_indices';
|
||||
import { IndexPatternCreationConfig } from '../../../../../index_pattern_management/public';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { LegacyApiCaller } from '../../../../../data/public/search/legacy';
|
||||
import { httpServiceMock } from '../../../../../../core/public/mocks';
|
||||
import { ResolveIndexResponseItemIndexAttrs } from '../types';
|
||||
|
||||
export const successfulResponse = {
|
||||
hits: {
|
||||
total: 1,
|
||||
max_score: 0.0,
|
||||
hits: [],
|
||||
},
|
||||
aggregations: {
|
||||
indices: {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: '1',
|
||||
doc_count: 1,
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
doc_count: 1,
|
||||
},
|
||||
],
|
||||
indices: [
|
||||
{
|
||||
name: 'remoteCluster1:bar-01',
|
||||
attributes: ['open'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const exceptionResponse = {
|
||||
body: {
|
||||
error: {
|
||||
root_cause: [
|
||||
{
|
||||
type: 'index_not_found_exception',
|
||||
reason: 'no such index',
|
||||
index_uuid: '_na_',
|
||||
'resource.type': 'index_or_alias',
|
||||
'resource.id': 't',
|
||||
index: 't',
|
||||
},
|
||||
],
|
||||
type: 'transport_exception',
|
||||
reason: 'unable to communicate with remote cluster [cluster_one]',
|
||||
caused_by: {
|
||||
type: 'index_not_found_exception',
|
||||
reason: 'no such index',
|
||||
index_uuid: '_na_',
|
||||
'resource.type': 'index_or_alias',
|
||||
'resource.id': 't',
|
||||
index: 't',
|
||||
},
|
||||
],
|
||||
aliases: [
|
||||
{
|
||||
name: 'f-alias',
|
||||
indices: ['freeze-index', 'my-index'],
|
||||
},
|
||||
},
|
||||
status: 500,
|
||||
};
|
||||
|
||||
export const errorResponse = {
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
],
|
||||
data_streams: [
|
||||
{
|
||||
name: 'foo',
|
||||
backing_indices: ['foo-000001'],
|
||||
timestamp_field: '@timestamp',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockIndexPatternCreationType = new IndexPatternCreationConfig({
|
||||
|
@ -87,81 +52,62 @@ const mockIndexPatternCreationType = new IndexPatternCreationConfig({
|
|||
isBeta: false,
|
||||
});
|
||||
|
||||
function esClientFactory(search: (params: any) => any): LegacyApiCaller {
|
||||
return {
|
||||
search,
|
||||
msearch: () => ({
|
||||
abort: () => {},
|
||||
...new Promise((resolve) => resolve({})),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const es = esClientFactory(() => successfulResponse);
|
||||
const http = httpServiceMock.createStartContract();
|
||||
http.get.mockResolvedValue(successfulResponse);
|
||||
|
||||
describe('getIndices', () => {
|
||||
it('should work in a basic case', async () => {
|
||||
const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1);
|
||||
expect(result.length).toBe(2);
|
||||
expect(result[0].name).toBe('1');
|
||||
expect(result[1].name).toBe('2');
|
||||
const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false);
|
||||
expect(result.length).toBe(3);
|
||||
expect(result[0].name).toBe('f-alias');
|
||||
expect(result[1].name).toBe('foo');
|
||||
});
|
||||
|
||||
it('should ignore ccs query-all', async () => {
|
||||
expect((await getIndices(es, mockIndexPatternCreationType, '*:', 10)).length).toBe(0);
|
||||
expect((await getIndices(http, mockIndexPatternCreationType, '*:', false)).length).toBe(0);
|
||||
});
|
||||
|
||||
it('should ignore a single comma', async () => {
|
||||
expect((await getIndices(es, mockIndexPatternCreationType, ',', 10)).length).toBe(0);
|
||||
expect((await getIndices(es, mockIndexPatternCreationType, ',*', 10)).length).toBe(0);
|
||||
expect((await getIndices(es, mockIndexPatternCreationType, ',foobar', 10)).length).toBe(0);
|
||||
expect((await getIndices(http, mockIndexPatternCreationType, ',', false)).length).toBe(0);
|
||||
expect((await getIndices(http, mockIndexPatternCreationType, ',*', false)).length).toBe(0);
|
||||
expect((await getIndices(http, mockIndexPatternCreationType, ',foobar', false)).length).toBe(0);
|
||||
});
|
||||
|
||||
it('should trim the input', async () => {
|
||||
let index;
|
||||
const esClient = esClientFactory(
|
||||
jest.fn().mockImplementation((params) => {
|
||||
index = params.index;
|
||||
})
|
||||
);
|
||||
|
||||
await getIndices(esClient, mockIndexPatternCreationType, 'kibana ', 1);
|
||||
expect(index).toBe('kibana');
|
||||
});
|
||||
|
||||
it('should use the limit', async () => {
|
||||
let limit;
|
||||
const esClient = esClientFactory(
|
||||
jest.fn().mockImplementation((params) => {
|
||||
limit = params.body.aggs.indices.terms.size;
|
||||
})
|
||||
);
|
||||
await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 10);
|
||||
expect(limit).toBe(10);
|
||||
it('response object to item array', () => {
|
||||
const result = {
|
||||
indices: [
|
||||
{
|
||||
name: 'test_index',
|
||||
},
|
||||
{
|
||||
name: 'frozen_index',
|
||||
attributes: ['frozen' as ResolveIndexResponseItemIndexAttrs],
|
||||
},
|
||||
],
|
||||
aliases: [
|
||||
{
|
||||
name: 'test_alias',
|
||||
indices: [],
|
||||
},
|
||||
],
|
||||
data_streams: [
|
||||
{
|
||||
name: 'test_data_stream',
|
||||
backing_indices: [],
|
||||
timestamp_field: 'test_timestamp_field',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(responseToItemArray(result, mockIndexPatternCreationType)).toMatchSnapshot();
|
||||
expect(responseToItemArray({}, mockIndexPatternCreationType)).toEqual([]);
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it('should handle errors gracefully', async () => {
|
||||
const esClient = esClientFactory(() => errorResponse);
|
||||
const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw exceptions', async () => {
|
||||
const esClient = esClientFactory(() => {
|
||||
throw new Error('Fail');
|
||||
http.get.mockImplementationOnce(() => {
|
||||
throw new Error('Test error');
|
||||
});
|
||||
|
||||
await expect(
|
||||
getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should handle index_not_found_exception errors gracefully', async () => {
|
||||
const esClient = esClientFactory(
|
||||
() => new Promise((resolve, reject) => reject(exceptionResponse))
|
||||
);
|
||||
const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1);
|
||||
const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,17 +17,31 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get, sortBy } from 'lodash';
|
||||
import { sortBy } from 'lodash';
|
||||
import { HttpStart } from 'kibana/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { IndexPatternCreationConfig } from '../../../../../index_pattern_management/public';
|
||||
import { DataPublicPluginStart } from '../../../../../data/public';
|
||||
import { MatchedIndex } from '../types';
|
||||
import { MatchedItem, ResolveIndexResponse, ResolveIndexResponseItemIndexAttrs } from '../types';
|
||||
|
||||
const aliasLabel = i18n.translate('indexPatternManagement.aliasLabel', { defaultMessage: 'Alias' });
|
||||
const dataStreamLabel = i18n.translate('indexPatternManagement.dataStreamLabel', {
|
||||
defaultMessage: 'Data stream',
|
||||
});
|
||||
|
||||
const indexLabel = i18n.translate('indexPatternManagement.indexLabel', {
|
||||
defaultMessage: 'Index',
|
||||
});
|
||||
|
||||
const frozenLabel = i18n.translate('indexPatternManagement.frozenLabel', {
|
||||
defaultMessage: 'Frozen',
|
||||
});
|
||||
|
||||
export async function getIndices(
|
||||
es: DataPublicPluginStart['search']['__LEGACY']['esClient'],
|
||||
http: HttpStart,
|
||||
indexPatternCreationType: IndexPatternCreationConfig,
|
||||
rawPattern: string,
|
||||
limit: number
|
||||
): Promise<MatchedIndex[]> {
|
||||
showAllIndices: boolean
|
||||
): Promise<MatchedItem[]> {
|
||||
const pattern = rawPattern.trim();
|
||||
|
||||
// Searching for `*:` fails for CCS environments. The search request
|
||||
|
@ -48,54 +62,58 @@ export async function getIndices(
|
|||
return [];
|
||||
}
|
||||
|
||||
// We need to always provide a limit and not rely on the default
|
||||
if (!limit) {
|
||||
throw new Error('`getIndices()` was called without the required `limit` parameter.');
|
||||
}
|
||||
|
||||
const params = {
|
||||
ignoreUnavailable: true,
|
||||
index: pattern,
|
||||
ignore: [404],
|
||||
body: {
|
||||
size: 0, // no hits
|
||||
aggs: {
|
||||
indices: {
|
||||
terms: {
|
||||
field: '_index',
|
||||
size: limit,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const query = showAllIndices ? { expand_wildcards: 'all' } : undefined;
|
||||
|
||||
try {
|
||||
const response = await es.search(params);
|
||||
if (!response || response.error || !response.aggregations) {
|
||||
const response = await http.get<ResolveIndexResponse>(
|
||||
`/internal/index-pattern-management/resolve_index/${pattern}`,
|
||||
{ query }
|
||||
);
|
||||
if (!response) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return sortBy(
|
||||
response.aggregations.indices.buckets
|
||||
.map((bucket: { key: string; doc_count: number }) => {
|
||||
return bucket.key;
|
||||
})
|
||||
.map((indexName: string) => {
|
||||
return {
|
||||
name: indexName,
|
||||
tags: indexPatternCreationType.getIndexTags(indexName),
|
||||
};
|
||||
}),
|
||||
'name'
|
||||
);
|
||||
} catch (err) {
|
||||
const type = get(err, 'body.error.caused_by.type');
|
||||
if (type === 'index_not_found_exception') {
|
||||
// This happens in a CSS environment when the controlling node returns a 500 even though the data
|
||||
// nodes returned a 404. Remove this when/if this is handled: https://github.com/elastic/elasticsearch/issues/27461
|
||||
return [];
|
||||
}
|
||||
throw err;
|
||||
return responseToItemArray(response, indexPatternCreationType);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export const responseToItemArray = (
|
||||
response: ResolveIndexResponse,
|
||||
indexPatternCreationType: IndexPatternCreationConfig
|
||||
): MatchedItem[] => {
|
||||
const source: MatchedItem[] = [];
|
||||
|
||||
(response.indices || []).forEach((index) => {
|
||||
const tags: MatchedItem['tags'] = [{ key: 'index', name: indexLabel, color: 'default' }];
|
||||
const isFrozen = (index.attributes || []).includes(ResolveIndexResponseItemIndexAttrs.FROZEN);
|
||||
|
||||
tags.push(...indexPatternCreationType.getIndexTags(index.name));
|
||||
if (isFrozen) {
|
||||
tags.push({ name: frozenLabel, key: 'frozen', color: 'danger' });
|
||||
}
|
||||
|
||||
source.push({
|
||||
name: index.name,
|
||||
tags,
|
||||
item: index,
|
||||
});
|
||||
});
|
||||
(response.aliases || []).forEach((alias) => {
|
||||
source.push({
|
||||
name: alias.name,
|
||||
tags: [{ key: 'alias', name: aliasLabel, color: 'default' }],
|
||||
item: alias,
|
||||
});
|
||||
});
|
||||
(response.data_streams || []).forEach((dataStream) => {
|
||||
source.push({
|
||||
name: dataStream.name,
|
||||
tags: [{ key: 'data_stream', name: dataStreamLabel, color: 'primary' }],
|
||||
item: dataStream,
|
||||
});
|
||||
});
|
||||
|
||||
return sortBy(source, 'name');
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { getMatchedIndices } from './get_matched_indices';
|
||||
import { Tag } from '../types';
|
||||
import { Tag, MatchedItem } from '../types';
|
||||
|
||||
jest.mock('./../constants', () => ({
|
||||
MAX_NUMBER_OF_MATCHING_INDICES: 6,
|
||||
|
@ -32,18 +32,18 @@ const indices = [
|
|||
{ name: 'packetbeat', tags },
|
||||
{ name: 'metricbeat', tags },
|
||||
{ name: '.kibana', tags },
|
||||
];
|
||||
] as MatchedItem[];
|
||||
|
||||
const partialIndices = [
|
||||
{ name: 'kibana', tags },
|
||||
{ name: 'es', tags },
|
||||
{ name: '.kibana', tags },
|
||||
];
|
||||
] as MatchedItem[];
|
||||
|
||||
const exactIndices = [
|
||||
{ name: 'kibana', tags },
|
||||
{ name: '.kibana', tags },
|
||||
];
|
||||
] as MatchedItem[];
|
||||
|
||||
describe('getMatchedIndices', () => {
|
||||
it('should return all indices', () => {
|
||||
|
|
|
@ -33,7 +33,7 @@ function isSystemIndex(index: string): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
function filterSystemIndices(indices: MatchedIndex[], isIncludingSystemIndices: boolean) {
|
||||
function filterSystemIndices(indices: MatchedItem[], isIncludingSystemIndices: boolean) {
|
||||
if (!indices) {
|
||||
return indices;
|
||||
}
|
||||
|
@ -65,12 +65,12 @@ function filterSystemIndices(indices: MatchedIndex[], isIncludingSystemIndices:
|
|||
We call this `exact` matches because ES is telling us exactly what it matches
|
||||
*/
|
||||
|
||||
import { MatchedIndex } from '../types';
|
||||
import { MatchedItem } from '../types';
|
||||
|
||||
export function getMatchedIndices(
|
||||
unfilteredAllIndices: MatchedIndex[],
|
||||
unfilteredPartialMatchedIndices: MatchedIndex[],
|
||||
unfilteredExactMatchedIndices: MatchedIndex[],
|
||||
unfilteredAllIndices: MatchedItem[],
|
||||
unfilteredPartialMatchedIndices: MatchedItem[],
|
||||
unfilteredExactMatchedIndices: MatchedItem[],
|
||||
isIncludingSystemIndices: boolean = false
|
||||
) {
|
||||
const allIndices = filterSystemIndices(unfilteredAllIndices, isIncludingSystemIndices);
|
||||
|
|
|
@ -17,12 +17,54 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export interface MatchedIndex {
|
||||
export interface MatchedItem {
|
||||
name: string;
|
||||
tags: Tag[];
|
||||
item: {
|
||||
name: string;
|
||||
backing_indices?: string[];
|
||||
timestamp_field?: string;
|
||||
indices?: string[];
|
||||
aliases?: string[];
|
||||
attributes?: ResolveIndexResponseItemIndexAttrs[];
|
||||
data_stream?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResolveIndexResponse {
|
||||
indices?: ResolveIndexResponseItemIndex[];
|
||||
aliases?: ResolveIndexResponseItemAlias[];
|
||||
data_streams?: ResolveIndexResponseItemDataStream[];
|
||||
}
|
||||
|
||||
export interface ResolveIndexResponseItem {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ResolveIndexResponseItemDataStream extends ResolveIndexResponseItem {
|
||||
backing_indices: string[];
|
||||
timestamp_field: string;
|
||||
}
|
||||
|
||||
export interface ResolveIndexResponseItemAlias extends ResolveIndexResponseItem {
|
||||
indices: string[];
|
||||
}
|
||||
|
||||
export interface ResolveIndexResponseItemIndex extends ResolveIndexResponseItem {
|
||||
aliases?: string[];
|
||||
attributes?: ResolveIndexResponseItemIndexAttrs[];
|
||||
data_stream?: string;
|
||||
}
|
||||
|
||||
export enum ResolveIndexResponseItemIndexAttrs {
|
||||
OPEN = 'open',
|
||||
CLOSED = 'closed',
|
||||
HIDDEN = 'hidden',
|
||||
FROZEN = 'frozen',
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
name: string;
|
||||
key: string;
|
||||
color: string;
|
||||
}
|
||||
|
|
|
@ -836,7 +836,6 @@ exports[`FieldEditor should show deprecated lang warning 1`] = `
|
|||
testlang
|
||||
</eui-code>,
|
||||
"painlessLink": <eui-link
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/modules-scripting-painless.html"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -61,7 +61,6 @@ exports[`ScriptingWarningCallOut should render normally 1`] = `
|
|||
values={
|
||||
Object {
|
||||
"scripFields": <EuiLink
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-request-script-fields.html"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -75,7 +74,6 @@ exports[`ScriptingWarningCallOut should render normally 1`] = `
|
|||
/>
|
||||
</EuiLink>,
|
||||
"scriptsInAggregation": <EuiLink
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-aggregations.html#_values_source"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -94,14 +92,11 @@ exports[`ScriptingWarningCallOut should render normally 1`] = `
|
|||
<span>
|
||||
Please familiarize yourself with
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-request-script-fields.html"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-request-script-fields.html"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="script fields"
|
||||
|
@ -120,18 +115,15 @@ exports[`ScriptingWarningCallOut should render normally 1`] = `
|
|||
data-euiicon-type="link"
|
||||
/>
|
||||
</EuiIcon>
|
||||
</a>
|
||||
</button>
|
||||
</EuiLink>
|
||||
and with
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-aggregations.html#_values_source"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/search-aggregations.html#_values_source"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="scripts in aggregations"
|
||||
|
@ -150,7 +142,7 @@ exports[`ScriptingWarningCallOut should render normally 1`] = `
|
|||
data-euiicon-type="link"
|
||||
/>
|
||||
</EuiIcon>
|
||||
</a>
|
||||
</button>
|
||||
</EuiLink>
|
||||
before using scripted fields.
|
||||
</span>
|
||||
|
|
|
@ -76,6 +76,13 @@ const createInstance = async () => {
|
|||
};
|
||||
};
|
||||
|
||||
const docLinks = {
|
||||
links: {
|
||||
indexPatterns: {},
|
||||
scriptedFields: {},
|
||||
},
|
||||
};
|
||||
|
||||
const createIndexPatternManagmentContext = () => {
|
||||
const {
|
||||
chrome,
|
||||
|
@ -84,7 +91,6 @@ const createIndexPatternManagmentContext = () => {
|
|||
uiSettings,
|
||||
notifications,
|
||||
overlays,
|
||||
docLinks,
|
||||
} = coreMock.createStart();
|
||||
const { http } = coreMock.createSetup();
|
||||
const data = dataPluginMock.createStartContract();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { MatchedIndex } from '../../components/create_index_pattern_wizard/types';
|
||||
import { MatchedItem } from '../../components/create_index_pattern_wizard/types';
|
||||
|
||||
const indexPatternTypeName = i18n.translate(
|
||||
'indexPatternManagement.editIndexPattern.createIndex.defaultTypeName',
|
||||
|
@ -105,7 +105,7 @@ export class IndexPatternCreationConfig {
|
|||
return [];
|
||||
}
|
||||
|
||||
public checkIndicesForErrors(indices: MatchedIndex[]) {
|
||||
public checkIndicesForErrors(indices: MatchedItem[]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
25
src/plugins/index_pattern_management/server/index.ts
Normal file
25
src/plugins/index_pattern_management/server/index.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext } from 'src/core/server';
|
||||
import { IndexPatternManagementPlugin } from './plugin';
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new IndexPatternManagementPlugin(initializerContext);
|
||||
}
|
70
src/plugins/index_pattern_management/server/plugin.ts
Normal file
70
src/plugins/index_pattern_management/server/plugin.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext, CoreSetup, Plugin } from 'src/core/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
export class IndexPatternManagementPlugin implements Plugin<void, void> {
|
||||
constructor(initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
const router = core.http.createRouter();
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: '/internal/index-pattern-management/resolve_index/{query}',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
query: schema.string(),
|
||||
}),
|
||||
query: schema.object({
|
||||
expand_wildcards: schema.maybe(
|
||||
schema.oneOf([
|
||||
schema.literal('all'),
|
||||
schema.literal('open'),
|
||||
schema.literal('closed'),
|
||||
schema.literal('hidden'),
|
||||
schema.literal('none'),
|
||||
])
|
||||
),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const queryString = req.query.expand_wildcards
|
||||
? { expand_wildcards: req.query.expand_wildcards }
|
||||
: null;
|
||||
const result = await context.core.elasticsearch.legacy.client.callAsCurrentUser(
|
||||
'transport.request',
|
||||
{
|
||||
method: 'GET',
|
||||
path: `/_resolve/index/${encodeURIComponent(req.params.query)}${
|
||||
queryString ? '?' + new URLSearchParams(queryString).toString() : ''
|
||||
}`,
|
||||
}
|
||||
);
|
||||
return res.ok({ body: result });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
||||
public stop() {}
|
||||
}
|
|
@ -22,6 +22,7 @@ import expect from '@kbn/expect';
|
|||
export default function ({ getService, getPageObjects }) {
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const es = getService('legacyEs');
|
||||
const PageObjects = getPageObjects(['settings', 'common']);
|
||||
|
||||
describe('"Create Index Pattern" wizard', function () {
|
||||
|
@ -48,5 +49,59 @@ export default function ({ getService, getPageObjects }) {
|
|||
expect(isEnabled).to.be.ok();
|
||||
});
|
||||
});
|
||||
|
||||
describe('data streams', () => {
|
||||
it('can be an index pattern', async () => {
|
||||
await es.transport.request({
|
||||
path: '/_index_template/generic-logs',
|
||||
method: 'PUT',
|
||||
body: {
|
||||
index_patterns: ['logs-*', 'test_data_stream'],
|
||||
template: {
|
||||
mappings: {
|
||||
properties: {
|
||||
'@timestamp': {
|
||||
type: 'date',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
data_stream: {
|
||||
timestamp_field: '@timestamp',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await es.transport.request({
|
||||
path: '/_data_stream/test_data_stream',
|
||||
method: 'PUT',
|
||||
});
|
||||
|
||||
await PageObjects.settings.createIndexPattern('test_data_stream', false);
|
||||
|
||||
await es.transport.request({
|
||||
path: '/_data_stream/test_data_stream',
|
||||
method: 'DELETE',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('index alias', () => {
|
||||
it('can be an index pattern', async () => {
|
||||
await es.transport.request({
|
||||
path: '/blogs/_doc',
|
||||
method: 'POST',
|
||||
body: { user: 'matt', message: 20 },
|
||||
});
|
||||
|
||||
await es.transport.request({
|
||||
path: '/_aliases',
|
||||
method: 'POST',
|
||||
body: { actions: [{ add: { index: 'blogs', alias: 'alias1' } }] },
|
||||
});
|
||||
|
||||
await PageObjects.settings.createIndexPattern('alias1', false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig
|
|||
{
|
||||
key: this.type,
|
||||
name: rollupIndexPatternIndexLabel,
|
||||
color: 'primary',
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
|
Loading…
Reference in a new issue