mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Backports the following commits to 6.x: - [Infra UI] Replace redux source slice with constate container (#26121)
This commit is contained in:
parent
18d41b6cde
commit
73e7ac28f5
41 changed files with 797 additions and 472 deletions
|
@ -152,6 +152,7 @@
|
||||||
"chroma-js": "^1.3.6",
|
"chroma-js": "^1.3.6",
|
||||||
"classnames": "2.2.5",
|
"classnames": "2.2.5",
|
||||||
"concat-stream": "1.5.1",
|
"concat-stream": "1.5.1",
|
||||||
|
"constate": "^0.9.0",
|
||||||
"copy-to-clipboard": "^3.0.8",
|
"copy-to-clipboard": "^3.0.8",
|
||||||
"cronstrue": "^1.51.0",
|
"cronstrue": "^1.51.0",
|
||||||
"d3": "3.5.6",
|
"d3": "3.5.6",
|
||||||
|
|
|
@ -705,6 +705,52 @@ export namespace WaffleNodesQuery {
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export namespace SourceQuery {
|
||||||
|
export type Variables = {
|
||||||
|
sourceId?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Query = {
|
||||||
|
__typename?: 'Query';
|
||||||
|
source: Source;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Source = {
|
||||||
|
__typename?: 'InfraSource';
|
||||||
|
id: string;
|
||||||
|
configuration: Configuration;
|
||||||
|
status: Status;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Configuration = {
|
||||||
|
__typename?: 'InfraSourceConfiguration';
|
||||||
|
metricAlias: string;
|
||||||
|
logAlias: string;
|
||||||
|
fields: Fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Fields = {
|
||||||
|
__typename?: 'InfraSourceFields';
|
||||||
|
container: string;
|
||||||
|
host: string;
|
||||||
|
pod: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Status = {
|
||||||
|
__typename?: 'InfraSourceStatus';
|
||||||
|
indexFields: IndexFields[];
|
||||||
|
logIndicesExist: boolean;
|
||||||
|
metricIndicesExist: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IndexFields = {
|
||||||
|
__typename?: 'InfraIndexField';
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
searchable: boolean;
|
||||||
|
aggregatable: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
export namespace LogEntries {
|
export namespace LogEntries {
|
||||||
export type Variables = {
|
export type Variables = {
|
||||||
sourceId?: string | null;
|
sourceId?: string | null;
|
||||||
|
@ -800,52 +846,6 @@ export namespace LogSummary {
|
||||||
entriesCount: number;
|
entriesCount: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export namespace SourceQuery {
|
|
||||||
export type Variables = {
|
|
||||||
sourceId?: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Query = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
source: Source;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Source = {
|
|
||||||
__typename?: 'InfraSource';
|
|
||||||
id: string;
|
|
||||||
configuration: Configuration;
|
|
||||||
status: Status;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Configuration = {
|
|
||||||
__typename?: 'InfraSourceConfiguration';
|
|
||||||
metricAlias: string;
|
|
||||||
logAlias: string;
|
|
||||||
fields: Fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Fields = {
|
|
||||||
__typename?: 'InfraSourceFields';
|
|
||||||
container: string;
|
|
||||||
host: string;
|
|
||||||
pod: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Status = {
|
|
||||||
__typename?: 'InfraSourceStatus';
|
|
||||||
indexFields: IndexFields[];
|
|
||||||
logIndicesExist: boolean;
|
|
||||||
metricIndicesExist: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IndexFields = {
|
|
||||||
__typename?: 'InfraIndexField';
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
searchable: boolean;
|
|
||||||
aggregatable: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace InfraTimeKeyFields {
|
export namespace InfraTimeKeyFields {
|
||||||
export type Fragment = {
|
export type Fragment = {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { I18nProvider } from '@kbn/i18n/react';
|
import { Provider as ConstateProvider } from 'constate';
|
||||||
import { createHashHistory } from 'history';
|
import { createHashHistory } from 'history';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ApolloProvider } from 'react-apollo';
|
import { ApolloProvider } from 'react-apollo';
|
||||||
|
@ -16,6 +16,7 @@ import { ThemeProvider } from 'styled-components';
|
||||||
// TODO use theme provided from parentApp when kibana supports it
|
// TODO use theme provided from parentApp when kibana supports it
|
||||||
import { EuiErrorBoundary } from '@elastic/eui';
|
import { EuiErrorBoundary } from '@elastic/eui';
|
||||||
import euiVars from '@elastic/eui/dist/eui_theme_k6_light.json';
|
import euiVars from '@elastic/eui/dist/eui_theme_k6_light.json';
|
||||||
|
import { I18nProvider } from '@kbn/i18n/react';
|
||||||
import { InfraFrontendLibs } from '../lib/lib';
|
import { InfraFrontendLibs } from '../lib/lib';
|
||||||
import { PageRouter } from '../routes';
|
import { PageRouter } from '../routes';
|
||||||
import { createStore } from '../store';
|
import { createStore } from '../store';
|
||||||
|
@ -32,6 +33,7 @@ export async function startApp(libs: InfraFrontendLibs) {
|
||||||
libs.framework.render(
|
libs.framework.render(
|
||||||
<I18nProvider>
|
<I18nProvider>
|
||||||
<EuiErrorBoundary>
|
<EuiErrorBoundary>
|
||||||
|
<ConstateProvider devtools>
|
||||||
<ReduxStoreProvider store={store}>
|
<ReduxStoreProvider store={store}>
|
||||||
<ApolloProvider client={libs.apolloClient}>
|
<ApolloProvider client={libs.apolloClient}>
|
||||||
<ThemeProvider theme={{ eui: euiVars }}>
|
<ThemeProvider theme={{ eui: euiVars }}>
|
||||||
|
@ -39,6 +41,7 @@ export async function startApp(libs: InfraFrontendLibs) {
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
</ReduxStoreProvider>
|
</ReduxStoreProvider>
|
||||||
|
</ConstateProvider>
|
||||||
</EuiErrorBoundary>
|
</EuiErrorBoundary>
|
||||||
</I18nProvider>
|
</I18nProvider>
|
||||||
);
|
);
|
||||||
|
|
56
x-pack/plugins/infra/public/components/error_page.tsx
Normal file
56
x-pack/plugins/infra/public/components/error_page.tsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
EuiButton,
|
||||||
|
EuiCallOut,
|
||||||
|
EuiFlexGroup,
|
||||||
|
EuiFlexItem,
|
||||||
|
EuiPageBody,
|
||||||
|
EuiPageContent,
|
||||||
|
EuiPageContentBody,
|
||||||
|
} from '@elastic/eui';
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { FlexPage } from './page';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
detailedMessage?: React.ReactNode;
|
||||||
|
retry?: () => void;
|
||||||
|
shortMessage: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ErrorPage: React.SFC<Props> = ({ detailedMessage, retry, shortMessage }) => (
|
||||||
|
<FlexPage>
|
||||||
|
<EuiPageBody>
|
||||||
|
<MinimumPageContent
|
||||||
|
horizontalPosition="center"
|
||||||
|
verticalPosition="center"
|
||||||
|
panelPaddingSize="none"
|
||||||
|
>
|
||||||
|
<EuiPageContentBody>
|
||||||
|
<EuiCallOut color="danger" iconType="cross" title="An error occurred">
|
||||||
|
<EuiFlexGroup>
|
||||||
|
<EuiFlexItem>{shortMessage}</EuiFlexItem>
|
||||||
|
{retry ? (
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiButton onClick={retry} iconType="refresh">
|
||||||
|
Try again
|
||||||
|
</EuiButton>
|
||||||
|
</EuiFlexItem>
|
||||||
|
) : null}
|
||||||
|
</EuiFlexGroup>
|
||||||
|
{detailedMessage ? <div>{detailedMessage}</div> : null}
|
||||||
|
</EuiCallOut>
|
||||||
|
</EuiPageContentBody>
|
||||||
|
</MinimumPageContent>
|
||||||
|
</EuiPageBody>
|
||||||
|
</FlexPage>
|
||||||
|
);
|
||||||
|
|
||||||
|
const MinimumPageContent = styled(EuiPageContent)`
|
||||||
|
min-width: 50vh;
|
||||||
|
`;
|
|
@ -7,23 +7,41 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||||
import { logFilterActions, logFilterSelectors, State } from '../../store';
|
import { logFilterActions, logFilterSelectors, State } from '../../store';
|
||||||
|
import { FilterQuery } from '../../store/local/log_filter';
|
||||||
|
import { convertKueryToElasticSearchQuery } from '../../utils/kuery';
|
||||||
import { asChildFunctionRenderer } from '../../utils/typed_react';
|
import { asChildFunctionRenderer } from '../../utils/typed_react';
|
||||||
import { bindPlainActionCreators } from '../../utils/typed_redux';
|
import { bindPlainActionCreators } from '../../utils/typed_redux';
|
||||||
import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state';
|
import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state';
|
||||||
|
|
||||||
|
interface WithLogFilterProps {
|
||||||
|
indexPattern: StaticIndexPattern;
|
||||||
|
}
|
||||||
|
|
||||||
const withLogFilter = connect(
|
const withLogFilter = connect(
|
||||||
(state: State) => ({
|
(state: State) => ({
|
||||||
filterQuery: logFilterSelectors.selectLogFilterQuery(state),
|
filterQuery: logFilterSelectors.selectLogFilterQuery(state),
|
||||||
filterQueryDraft: logFilterSelectors.selectLogFilterQueryDraft(state),
|
filterQueryDraft: logFilterSelectors.selectLogFilterQueryDraft(state),
|
||||||
isFilterQueryDraftValid: logFilterSelectors.selectIsLogFilterQueryDraftValid(state),
|
isFilterQueryDraftValid: logFilterSelectors.selectIsLogFilterQueryDraftValid(state),
|
||||||
}),
|
}),
|
||||||
|
(dispatch, ownProps: WithLogFilterProps) =>
|
||||||
bindPlainActionCreators({
|
bindPlainActionCreators({
|
||||||
applyFilterQuery: logFilterActions.applyLogFilterQuery,
|
applyFilterQuery: (query: FilterQuery) =>
|
||||||
|
logFilterActions.applyLogFilterQuery({
|
||||||
|
query,
|
||||||
|
serializedQuery: convertKueryToElasticSearchQuery(
|
||||||
|
query.expression,
|
||||||
|
ownProps.indexPattern
|
||||||
|
),
|
||||||
|
}),
|
||||||
applyFilterQueryFromKueryExpression: (expression: string) =>
|
applyFilterQueryFromKueryExpression: (expression: string) =>
|
||||||
logFilterActions.applyLogFilterQuery({
|
logFilterActions.applyLogFilterQuery({
|
||||||
|
query: {
|
||||||
kind: 'kuery',
|
kind: 'kuery',
|
||||||
expression,
|
expression,
|
||||||
|
},
|
||||||
|
serializedQuery: convertKueryToElasticSearchQuery(expression, ownProps.indexPattern),
|
||||||
}),
|
}),
|
||||||
setFilterQueryDraft: logFilterActions.setLogFilterQueryDraft,
|
setFilterQueryDraft: logFilterActions.setLogFilterQueryDraft,
|
||||||
setFilterQueryDraftFromKueryExpression: (expression: string) =>
|
setFilterQueryDraftFromKueryExpression: (expression: string) =>
|
||||||
|
@ -31,7 +49,7 @@ const withLogFilter = connect(
|
||||||
kind: 'kuery',
|
kind: 'kuery',
|
||||||
expression,
|
expression,
|
||||||
}),
|
}),
|
||||||
})
|
})(dispatch)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const WithLogFilter = asChildFunctionRenderer(withLogFilter);
|
export const WithLogFilter = asChildFunctionRenderer(withLogFilter);
|
||||||
|
@ -42,8 +60,10 @@ export const WithLogFilter = asChildFunctionRenderer(withLogFilter);
|
||||||
|
|
||||||
type LogFilterUrlState = ReturnType<typeof logFilterSelectors.selectLogFilterQuery>;
|
type LogFilterUrlState = ReturnType<typeof logFilterSelectors.selectLogFilterQuery>;
|
||||||
|
|
||||||
export const WithLogFilterUrlState = () => (
|
type WithLogFilterUrlStateProps = WithLogFilterProps;
|
||||||
<WithLogFilter>
|
|
||||||
|
export const WithLogFilterUrlState: React.SFC<WithLogFilterUrlStateProps> = ({ indexPattern }) => (
|
||||||
|
<WithLogFilter indexPattern={indexPattern}>
|
||||||
{({ applyFilterQuery, filterQuery }) => (
|
{({ applyFilterQuery, filterQuery }) => (
|
||||||
<UrlStateContainer
|
<UrlStateContainer
|
||||||
urlState={filterQuery}
|
urlState={filterQuery}
|
||||||
|
|
|
@ -7,24 +7,42 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { sharedSelectors, State, waffleFilterActions, waffleFilterSelectors } from '../../store';
|
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||||
|
import { State, waffleFilterActions, waffleFilterSelectors } from '../../store';
|
||||||
|
import { FilterQuery } from '../../store/local/waffle_filter';
|
||||||
|
import { convertKueryToElasticSearchQuery } from '../../utils/kuery';
|
||||||
import { asChildFunctionRenderer } from '../../utils/typed_react';
|
import { asChildFunctionRenderer } from '../../utils/typed_react';
|
||||||
import { bindPlainActionCreators } from '../../utils/typed_redux';
|
import { bindPlainActionCreators } from '../../utils/typed_redux';
|
||||||
import { UrlStateContainer } from '../../utils/url_state';
|
import { UrlStateContainer } from '../../utils/url_state';
|
||||||
|
|
||||||
|
interface WithWaffleFilterProps {
|
||||||
|
indexPattern: StaticIndexPattern;
|
||||||
|
}
|
||||||
|
|
||||||
export const withWaffleFilter = connect(
|
export const withWaffleFilter = connect(
|
||||||
(state: State) => ({
|
(state: State) => ({
|
||||||
filterQuery: waffleFilterSelectors.selectWaffleFilterQuery(state),
|
filterQuery: waffleFilterSelectors.selectWaffleFilterQuery(state),
|
||||||
filterQueryDraft: waffleFilterSelectors.selectWaffleFilterQueryDraft(state),
|
filterQueryDraft: waffleFilterSelectors.selectWaffleFilterQueryDraft(state),
|
||||||
filterQueryAsJson: sharedSelectors.selectWaffleFilterQueryAsJson(state),
|
filterQueryAsJson: waffleFilterSelectors.selectWaffleFilterQueryAsJson(state),
|
||||||
isFilterQueryDraftValid: waffleFilterSelectors.selectIsWaffleFilterQueryDraftValid(state),
|
isFilterQueryDraftValid: waffleFilterSelectors.selectIsWaffleFilterQueryDraftValid(state),
|
||||||
}),
|
}),
|
||||||
|
(dispatch, ownProps: WithWaffleFilterProps) =>
|
||||||
bindPlainActionCreators({
|
bindPlainActionCreators({
|
||||||
applyFilterQuery: waffleFilterActions.applyWaffleFilterQuery,
|
applyFilterQuery: (query: FilterQuery) =>
|
||||||
|
waffleFilterActions.applyWaffleFilterQuery({
|
||||||
|
query,
|
||||||
|
serializedQuery: convertKueryToElasticSearchQuery(
|
||||||
|
query.expression,
|
||||||
|
ownProps.indexPattern
|
||||||
|
),
|
||||||
|
}),
|
||||||
applyFilterQueryFromKueryExpression: (expression: string) =>
|
applyFilterQueryFromKueryExpression: (expression: string) =>
|
||||||
waffleFilterActions.applyWaffleFilterQuery({
|
waffleFilterActions.applyWaffleFilterQuery({
|
||||||
|
query: {
|
||||||
kind: 'kuery',
|
kind: 'kuery',
|
||||||
expression,
|
expression,
|
||||||
|
},
|
||||||
|
serializedQuery: convertKueryToElasticSearchQuery(expression, ownProps.indexPattern),
|
||||||
}),
|
}),
|
||||||
setFilterQueryDraft: waffleFilterActions.setWaffleFilterQueryDraft,
|
setFilterQueryDraft: waffleFilterActions.setWaffleFilterQueryDraft,
|
||||||
setFilterQueryDraftFromKueryExpression: (expression: string) =>
|
setFilterQueryDraftFromKueryExpression: (expression: string) =>
|
||||||
|
@ -43,8 +61,12 @@ export const WithWaffleFilter = asChildFunctionRenderer(withWaffleFilter);
|
||||||
|
|
||||||
type WaffleFilterUrlState = ReturnType<typeof waffleFilterSelectors.selectWaffleFilterQuery>;
|
type WaffleFilterUrlState = ReturnType<typeof waffleFilterSelectors.selectWaffleFilterQuery>;
|
||||||
|
|
||||||
export const WithWaffleFilterUrlState = () => (
|
type WithWaffleFilterUrlStateProps = WithWaffleFilterProps;
|
||||||
<WithWaffleFilter>
|
|
||||||
|
export const WithWaffleFilterUrlState: React.SFC<WithWaffleFilterUrlStateProps> = ({
|
||||||
|
indexPattern,
|
||||||
|
}) => (
|
||||||
|
<WithWaffleFilter indexPattern={indexPattern}>
|
||||||
{({ applyFilterQuery, filterQuery }) => (
|
{({ applyFilterQuery, filterQuery }) => (
|
||||||
<UrlStateContainer
|
<UrlStateContainer
|
||||||
urlState={filterQuery}
|
urlState={filterQuery}
|
||||||
|
|
|
@ -5,18 +5,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { AutocompleteSuggestion, getAutocompleteProvider } from 'ui/autocomplete_providers';
|
import { AutocompleteSuggestion, getAutocompleteProvider } from 'ui/autocomplete_providers';
|
||||||
import { StaticIndexPattern } from 'ui/index_patterns';
|
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||||
|
|
||||||
import { sourceSelectors, State } from '../store';
|
|
||||||
import { RendererFunction } from '../utils/typed_react';
|
import { RendererFunction } from '../utils/typed_react';
|
||||||
|
|
||||||
const withIndexPattern = connect((state: State) => ({
|
|
||||||
indexPattern: sourceSelectors.selectDerivedIndexPattern(state),
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface WithKueryAutocompletionLifecycleProps {
|
interface WithKueryAutocompletionLifecycleProps {
|
||||||
children: RendererFunction<{
|
children: RendererFunction<{
|
||||||
isLoadingSuggestions: boolean;
|
isLoadingSuggestions: boolean;
|
||||||
|
@ -36,8 +30,7 @@ interface WithKueryAutocompletionLifecycleState {
|
||||||
suggestions: AutocompleteSuggestion[];
|
suggestions: AutocompleteSuggestion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WithKueryAutocompletion = withIndexPattern(
|
export class WithKueryAutocompletion extends React.Component<
|
||||||
class WithKueryAutocompletionLifecycle extends React.Component<
|
|
||||||
WithKueryAutocompletionLifecycleProps,
|
WithKueryAutocompletionLifecycleProps,
|
||||||
WithKueryAutocompletionLifecycleState
|
WithKueryAutocompletionLifecycleState
|
||||||
> {
|
> {
|
||||||
|
@ -104,4 +97,3 @@ export const WithKueryAutocompletion = withIndexPattern(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { sourceSelectors, State } from '../store';
|
|
||||||
import { asChildFunctionRenderer } from '../utils/typed_react';
|
|
||||||
|
|
||||||
export const withSource = connect((state: State) => ({
|
|
||||||
configuredFields: sourceSelectors.selectSourceFields(state),
|
|
||||||
logIndicesExist: sourceSelectors.selectSourceLogIndicesExist(state),
|
|
||||||
metricIndicesExist: sourceSelectors.selectSourceMetricIndicesExist(state),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const WithSource = asChildFunctionRenderer(withSource);
|
|
|
@ -4,6 +4,6 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { loadSourceActionCreators } from './operations/load';
|
export { SourceErrorPage } from './source_error_page';
|
||||||
|
export { SourceLoadingPage } from './source_loading_page';
|
||||||
export const loadSource = loadSourceActionCreators.resolve;
|
export { WithSource } from './with_source';
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ErrorPage } from '../../components/error_page';
|
||||||
|
|
||||||
|
interface SourceErrorPageProps {
|
||||||
|
errorMessage: string;
|
||||||
|
retry: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SourceErrorPage: React.SFC<SourceErrorPageProps> = ({ errorMessage, retry }) => (
|
||||||
|
<ErrorPage
|
||||||
|
shortMessage="Failed to load data sources."
|
||||||
|
detailedMessage={<code>{errorMessage}</code>}
|
||||||
|
retry={retry}
|
||||||
|
/>
|
||||||
|
);
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { LoadingPage } from '../../components/loading_page';
|
||||||
|
|
||||||
|
export const SourceLoadingPage: React.SFC = () => <LoadingPage message="Loading data sources" />;
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ApolloClient } from 'apollo-client';
|
||||||
|
import { Container as ConstateContainer, OnMount } from 'constate';
|
||||||
|
import React from 'react';
|
||||||
|
import { ApolloConsumer } from 'react-apollo';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { oc } from 'ts-optchain';
|
||||||
|
|
||||||
|
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||||
|
import { memoizeLast } from 'ui/utils/memoize';
|
||||||
|
import { SourceQuery } from '../../../common/graphql/types';
|
||||||
|
import {
|
||||||
|
createStatusActions,
|
||||||
|
createStatusSelectors,
|
||||||
|
Operation,
|
||||||
|
OperationStatus,
|
||||||
|
StatusHistoryUpdater,
|
||||||
|
} from '../../utils/operation_status';
|
||||||
|
import { inferActionMap, inferEffectMap, inferSelectorMap } from '../../utils/typed_constate';
|
||||||
|
import { RendererFunction } from '../../utils/typed_react';
|
||||||
|
import { sourceQuery } from './query_source.gql_query';
|
||||||
|
|
||||||
|
type Operations = Operation<'load', SourceQuery.Variables>;
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
operationStatusHistory: Array<OperationStatus<Operations>>;
|
||||||
|
source: SourceQuery.Source | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createContainerProps = memoizeLast((sourceId: string, apolloClient: ApolloClient<any>) => {
|
||||||
|
const initialState: State = {
|
||||||
|
operationStatusHistory: [],
|
||||||
|
source: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = inferActionMap<State>()({
|
||||||
|
...createStatusActions((updater: StatusHistoryUpdater<Operations>) => (state: State) => ({
|
||||||
|
...state,
|
||||||
|
operationStatusHistory: updater(state.operationStatusHistory),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getDerivedIndexPattern = createSelector(
|
||||||
|
(state: State) => oc(state).source.status.indexFields([]),
|
||||||
|
(state: State) => oc(state).source.configuration.logAlias(),
|
||||||
|
(state: State) => oc(state).source.configuration.metricAlias(),
|
||||||
|
(indexFields, logAlias, metricAlias) => ({
|
||||||
|
fields: indexFields,
|
||||||
|
title: `${logAlias},${metricAlias}`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectors = inferSelectorMap<State>()({
|
||||||
|
...createStatusSelectors(({ operationStatusHistory }: State) => operationStatusHistory),
|
||||||
|
getConfiguredFields: () => state => oc(state).source.configuration.fields(),
|
||||||
|
getLogIndicesExist: () => state => oc(state).source.status.logIndicesExist(),
|
||||||
|
getMetricIndicesExist: () => state => oc(state).source.status.metricIndicesExist(),
|
||||||
|
getDerivedIndexPattern: () => getDerivedIndexPattern,
|
||||||
|
});
|
||||||
|
|
||||||
|
const effects = inferEffectMap<State>()({
|
||||||
|
load: () => ({ setState }) => {
|
||||||
|
const variables = {
|
||||||
|
sourceId,
|
||||||
|
};
|
||||||
|
|
||||||
|
setState(actions.startOperation({ name: 'load', parameters: variables }));
|
||||||
|
|
||||||
|
apolloClient
|
||||||
|
.query<SourceQuery.Query, SourceQuery.Variables>({
|
||||||
|
query: sourceQuery,
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
result =>
|
||||||
|
setState(state => ({
|
||||||
|
...actions.finishOperation({ name: 'load', parameters: variables })(state),
|
||||||
|
source: result.data.source,
|
||||||
|
})),
|
||||||
|
error =>
|
||||||
|
setState(state => ({
|
||||||
|
...actions.failOperation({ name: 'load', parameters: variables }, `${error}`)(state),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onMount: OnMount<State> = props => {
|
||||||
|
effects.load()(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
actions,
|
||||||
|
context: `source-${sourceId}`,
|
||||||
|
effects,
|
||||||
|
initialState,
|
||||||
|
key: `source-${sourceId}`,
|
||||||
|
onMount,
|
||||||
|
selectors,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
interface WithSourceProps {
|
||||||
|
children: RendererFunction<{
|
||||||
|
configuredFields?: SourceQuery.Fields;
|
||||||
|
derivedIndexPattern: StaticIndexPattern;
|
||||||
|
hasFailed: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
|
lastFailureMessage?: string;
|
||||||
|
load: () => void;
|
||||||
|
logIndicesExist?: boolean;
|
||||||
|
metricIndicesExist?: boolean;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WithSource: React.SFC<WithSourceProps> = ({ children }) => (
|
||||||
|
<ApolloConsumer>
|
||||||
|
{client => (
|
||||||
|
<ConstateContainer pure {...createContainerProps('default', client)}>
|
||||||
|
{({
|
||||||
|
getConfiguredFields,
|
||||||
|
getDerivedIndexPattern,
|
||||||
|
getHasFailed,
|
||||||
|
getIsInProgress,
|
||||||
|
getLastFailureMessage,
|
||||||
|
getLogIndicesExist,
|
||||||
|
getMetricIndicesExist,
|
||||||
|
load,
|
||||||
|
}) =>
|
||||||
|
children({
|
||||||
|
configuredFields: getConfiguredFields(),
|
||||||
|
derivedIndexPattern: getDerivedIndexPattern(),
|
||||||
|
hasFailed: getHasFailed(),
|
||||||
|
isLoading: getIsInProgress(),
|
||||||
|
lastFailureMessage: getLastFailureMessage(),
|
||||||
|
load,
|
||||||
|
logIndicesExist: getLogIndicesExist(),
|
||||||
|
metricIndicesExist: getMetricIndicesExist(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ConstateContainer>
|
||||||
|
)}
|
||||||
|
</ApolloConsumer>
|
||||||
|
);
|
|
@ -4,9 +4,10 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||||
|
|
||||||
import { HomePageContent } from './page_content';
|
import { HomePageContent } from './page_content';
|
||||||
import { HomeToolbar } from './toolbar';
|
import { HomeToolbar } from './toolbar';
|
||||||
|
|
||||||
|
@ -19,30 +20,43 @@ import { WithWaffleFilterUrlState } from '../../containers/waffle/with_waffle_fi
|
||||||
import { WithWaffleOptionsUrlState } from '../../containers/waffle/with_waffle_options';
|
import { WithWaffleOptionsUrlState } from '../../containers/waffle/with_waffle_options';
|
||||||
import { WithWaffleTimeUrlState } from '../../containers/waffle/with_waffle_time';
|
import { WithWaffleTimeUrlState } from '../../containers/waffle/with_waffle_time';
|
||||||
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
|
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
|
||||||
import { WithSource } from '../../containers/with_source';
|
import { SourceErrorPage, SourceLoadingPage, WithSource } from '../../containers/with_source';
|
||||||
|
|
||||||
interface HomePageProps {
|
interface HomePageProps {
|
||||||
intl: InjectedIntl;
|
intl: InjectedIntl;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HomePage = injectI18n(
|
export const HomePage = injectI18n(
|
||||||
class extends React.PureComponent<HomePageProps, {}> {
|
class extends React.Component<HomePageProps, {}> {
|
||||||
public static displayName = 'HomePage';
|
public static displayName = 'HomePage';
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColumnarPage>
|
<ColumnarPage>
|
||||||
|
<Header appendSections={<InfrastructureBetaBadgeHeaderSection />} />
|
||||||
<WithSource>
|
<WithSource>
|
||||||
{({ metricIndicesExist }) =>
|
{({
|
||||||
metricIndicesExist || metricIndicesExist === null ? (
|
derivedIndexPattern,
|
||||||
|
hasFailed,
|
||||||
|
isLoading,
|
||||||
|
lastFailureMessage,
|
||||||
|
load,
|
||||||
|
metricIndicesExist,
|
||||||
|
}) =>
|
||||||
|
metricIndicesExist ? (
|
||||||
<>
|
<>
|
||||||
<WithWaffleTimeUrlState />
|
<WithWaffleTimeUrlState />
|
||||||
<WithWaffleFilterUrlState />
|
<WithWaffleFilterUrlState indexPattern={derivedIndexPattern} />
|
||||||
<WithWaffleOptionsUrlState />
|
<WithWaffleOptionsUrlState />
|
||||||
<Header appendSections={<InfrastructureBetaBadgeHeaderSection />} />
|
|
||||||
<HomeToolbar />
|
<HomeToolbar />
|
||||||
<HomePageContent />
|
<HomePageContent />
|
||||||
</>
|
</>
|
||||||
|
) : isLoading ? (
|
||||||
|
<SourceLoadingPage />
|
||||||
|
) : hasFailed ? (
|
||||||
|
<SourceErrorPage errorMessage={lastFailureMessage || ''} retry={load} />
|
||||||
) : (
|
) : (
|
||||||
<WithKibanaChrome>
|
<WithKibanaChrome>
|
||||||
{({ basePath }) => (
|
{({ basePath }) => (
|
||||||
|
|
|
@ -19,10 +19,10 @@ import { WithSource } from '../../containers/with_source';
|
||||||
export const HomePageContent: React.SFC = () => (
|
export const HomePageContent: React.SFC = () => (
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<WithSource>
|
<WithSource>
|
||||||
{({ configuredFields }) => (
|
{({ configuredFields, derivedIndexPattern }) => (
|
||||||
<WithOptions>
|
<WithOptions>
|
||||||
{({ wafflemap, sourceId }) => (
|
{({ wafflemap, sourceId }) => (
|
||||||
<WithWaffleFilter>
|
<WithWaffleFilter indexPattern={derivedIndexPattern}>
|
||||||
{({ filterQueryAsJson, applyFilterQuery }) => (
|
{({ filterQueryAsJson, applyFilterQuery }) => (
|
||||||
<WithWaffleTime>
|
<WithWaffleTime>
|
||||||
{({ currentTimeRange, isAutoReloading }) => (
|
{({ currentTimeRange, isAutoReloading }) => (
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { WithWaffleFilter } from '../../containers/waffle/with_waffle_filters';
|
||||||
import { WithWaffleOptions } from '../../containers/waffle/with_waffle_options';
|
import { WithWaffleOptions } from '../../containers/waffle/with_waffle_options';
|
||||||
import { WithWaffleTime } from '../../containers/waffle/with_waffle_time';
|
import { WithWaffleTime } from '../../containers/waffle/with_waffle_time';
|
||||||
import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion';
|
import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion';
|
||||||
|
import { WithSource } from '../../containers/with_source';
|
||||||
|
|
||||||
const getTitle = (nodeType: string) => {
|
const getTitle = (nodeType: string) => {
|
||||||
const TITLES = {
|
const TITLES = {
|
||||||
|
@ -78,9 +79,11 @@ export const HomeToolbar = injectI18n(({ intl }) => (
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="m">
|
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="m">
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<WithKueryAutocompletion>
|
<WithSource>
|
||||||
|
{({ derivedIndexPattern }) => (
|
||||||
|
<WithKueryAutocompletion indexPattern={derivedIndexPattern}>
|
||||||
{({ isLoadingSuggestions, loadSuggestions, suggestions }) => (
|
{({ isLoadingSuggestions, loadSuggestions, suggestions }) => (
|
||||||
<WithWaffleFilter>
|
<WithWaffleFilter indexPattern={derivedIndexPattern}>
|
||||||
{({
|
{({
|
||||||
applyFilterQueryFromKueryExpression,
|
applyFilterQueryFromKueryExpression,
|
||||||
filterQueryDraft,
|
filterQueryDraft,
|
||||||
|
@ -104,6 +107,8 @@ export const HomeToolbar = injectI18n(({ intl }) => (
|
||||||
</WithWaffleFilter>
|
</WithWaffleFilter>
|
||||||
)}
|
)}
|
||||||
</WithKueryAutocompletion>
|
</WithKueryAutocompletion>
|
||||||
|
)}
|
||||||
|
</WithSource>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<WithWaffleOptions>
|
<WithWaffleOptions>
|
||||||
{({ changeMetric, changeGroupBy, groupBy, metric, nodeType }) => (
|
{({ changeMetric, changeGroupBy, groupBy, metric, nodeType }) => (
|
||||||
|
|
|
@ -20,26 +20,21 @@ import { WithLogMinimapUrlState } from '../../containers/logs/with_log_minimap';
|
||||||
import { WithLogPositionUrlState } from '../../containers/logs/with_log_position';
|
import { WithLogPositionUrlState } from '../../containers/logs/with_log_position';
|
||||||
import { WithLogTextviewUrlState } from '../../containers/logs/with_log_textview';
|
import { WithLogTextviewUrlState } from '../../containers/logs/with_log_textview';
|
||||||
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
|
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
|
||||||
import { WithSource } from '../../containers/with_source';
|
import { SourceErrorPage, SourceLoadingPage, WithSource } from '../../containers/with_source';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
intl: InjectedIntl;
|
intl: InjectedIntl;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LogsPage = injectI18n(
|
export const LogsPage = injectI18n(
|
||||||
class extends React.Component<Props> {
|
class extends React.Component<Props> {
|
||||||
public static displayName = 'LogsPage';
|
public static displayName = 'LogsPage';
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColumnarPage>
|
<ColumnarPage>
|
||||||
<WithSource>
|
|
||||||
{({ logIndicesExist }) =>
|
|
||||||
logIndicesExist || logIndicesExist === null ? (
|
|
||||||
<>
|
|
||||||
<WithLogFilterUrlState />
|
|
||||||
<WithLogPositionUrlState />
|
|
||||||
<WithLogMinimapUrlState />
|
|
||||||
<WithLogTextviewUrlState />
|
|
||||||
<Header
|
<Header
|
||||||
appendSections={<LogsBetaBadgeHeaderSection />}
|
appendSections={<LogsBetaBadgeHeaderSection />}
|
||||||
breadcrumbs={[
|
breadcrumbs={[
|
||||||
|
@ -51,9 +46,28 @@ export const LogsPage = injectI18n(
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<WithSource>
|
||||||
|
{({
|
||||||
|
derivedIndexPattern,
|
||||||
|
hasFailed,
|
||||||
|
isLoading,
|
||||||
|
lastFailureMessage,
|
||||||
|
load,
|
||||||
|
logIndicesExist,
|
||||||
|
}) =>
|
||||||
|
logIndicesExist ? (
|
||||||
|
<>
|
||||||
|
<WithLogFilterUrlState indexPattern={derivedIndexPattern} />
|
||||||
|
<WithLogPositionUrlState />
|
||||||
|
<WithLogMinimapUrlState />
|
||||||
|
<WithLogTextviewUrlState />
|
||||||
<LogsToolbar />
|
<LogsToolbar />
|
||||||
<LogsPageContent />
|
<LogsPageContent />
|
||||||
</>
|
</>
|
||||||
|
) : isLoading ? (
|
||||||
|
<SourceLoadingPage />
|
||||||
|
) : hasFailed ? (
|
||||||
|
<SourceErrorPage errorMessage={lastFailureMessage || ''} retry={load} />
|
||||||
) : (
|
) : (
|
||||||
<WithKibanaChrome>
|
<WithKibanaChrome>
|
||||||
{({ basePath }) => (
|
{({ basePath }) => (
|
||||||
|
|
|
@ -20,17 +20,19 @@ import { WithLogMinimap } from '../../containers/logs/with_log_minimap';
|
||||||
import { WithLogPosition } from '../../containers/logs/with_log_position';
|
import { WithLogPosition } from '../../containers/logs/with_log_position';
|
||||||
import { WithLogTextview } from '../../containers/logs/with_log_textview';
|
import { WithLogTextview } from '../../containers/logs/with_log_textview';
|
||||||
import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion';
|
import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion';
|
||||||
|
import { WithSource } from '../../containers/with_source';
|
||||||
|
|
||||||
export const LogsToolbar = injectI18n(({ intl }) => (
|
export const LogsToolbar = injectI18n(({ intl }) => (
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="none">
|
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="none">
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<WithKueryAutocompletion>
|
<WithSource>
|
||||||
|
{({ derivedIndexPattern }) => (
|
||||||
|
<WithKueryAutocompletion indexPattern={derivedIndexPattern}>
|
||||||
{({ isLoadingSuggestions, loadSuggestions, suggestions }) => (
|
{({ isLoadingSuggestions, loadSuggestions, suggestions }) => (
|
||||||
<WithLogFilter>
|
<WithLogFilter indexPattern={derivedIndexPattern}>
|
||||||
{({
|
{({
|
||||||
applyFilterQueryFromKueryExpression,
|
applyFilterQueryFromKueryExpression,
|
||||||
/* filterQuery,*/
|
|
||||||
filterQueryDraft,
|
filterQueryDraft,
|
||||||
isFilterQueryDraftValid,
|
isFilterQueryDraftValid,
|
||||||
setFilterQueryDraftFromKueryExpression,
|
setFilterQueryDraftFromKueryExpression,
|
||||||
|
@ -52,6 +54,8 @@ export const LogsToolbar = injectI18n(({ intl }) => (
|
||||||
</WithLogFilter>
|
</WithLogFilter>
|
||||||
)}
|
)}
|
||||||
</WithKueryAutocompletion>
|
</WithKueryAutocompletion>
|
||||||
|
)}
|
||||||
|
</WithSource>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<LogCustomizationMenu>
|
<LogCustomizationMenu>
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
import actionCreatorFactory from 'typescript-fsa';
|
import actionCreatorFactory from 'typescript-fsa';
|
||||||
|
|
||||||
import { FilterQuery } from './reducer';
|
import { FilterQuery, SerializedFilterQuery } from './reducer';
|
||||||
|
|
||||||
const actionCreator = actionCreatorFactory('x-pack/infra/local/log_filter');
|
const actionCreator = actionCreatorFactory('x-pack/infra/local/log_filter');
|
||||||
|
|
||||||
export const setLogFilterQueryDraft = actionCreator<FilterQuery>('SET_LOG_FILTER_QUERY_DRAFT');
|
export const setLogFilterQueryDraft = actionCreator<FilterQuery>('SET_LOG_FILTER_QUERY_DRAFT');
|
||||||
|
|
||||||
export const applyLogFilterQuery = actionCreator<FilterQuery>('APPLY_LOG_FILTER_QUERY');
|
export const applyLogFilterQuery = actionCreator<SerializedFilterQuery>('APPLY_LOG_FILTER_QUERY');
|
||||||
|
|
|
@ -15,8 +15,13 @@ export interface KueryFilterQuery {
|
||||||
|
|
||||||
export type FilterQuery = KueryFilterQuery;
|
export type FilterQuery = KueryFilterQuery;
|
||||||
|
|
||||||
|
export interface SerializedFilterQuery {
|
||||||
|
query: FilterQuery;
|
||||||
|
serializedQuery: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LogFilterState {
|
export interface LogFilterState {
|
||||||
filterQuery: KueryFilterQuery | null;
|
filterQuery: SerializedFilterQuery | null;
|
||||||
filterQueryDraft: KueryFilterQuery | null;
|
filterQueryDraft: KueryFilterQuery | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +38,6 @@ export const logFilterReducer = reducerWithInitialState(initialLogFilterState)
|
||||||
.case(applyLogFilterQuery, (state, filterQuery) => ({
|
.case(applyLogFilterQuery, (state, filterQuery) => ({
|
||||||
...state,
|
...state,
|
||||||
filterQuery,
|
filterQuery,
|
||||||
filterQueryDraft: filterQuery,
|
filterQueryDraft: filterQuery.query,
|
||||||
}))
|
}))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -10,7 +10,11 @@ import { fromKueryExpression } from 'ui/kuery';
|
||||||
|
|
||||||
import { LogFilterState } from './reducer';
|
import { LogFilterState } from './reducer';
|
||||||
|
|
||||||
export const selectLogFilterQuery = (state: LogFilterState) => state.filterQuery;
|
export const selectLogFilterQuery = (state: LogFilterState) =>
|
||||||
|
state.filterQuery ? state.filterQuery.query : null;
|
||||||
|
|
||||||
|
export const selectLogFilterQueryAsJson = (state: LogFilterState) =>
|
||||||
|
state.filterQuery ? state.filterQuery.serializedQuery : null;
|
||||||
|
|
||||||
export const selectLogFilterQueryDraft = (state: LogFilterState) => state.filterQueryDraft;
|
export const selectLogFilterQueryDraft = (state: LogFilterState) => state.filterQueryDraft;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import actionCreatorFactory from 'typescript-fsa';
|
import actionCreatorFactory from 'typescript-fsa';
|
||||||
|
|
||||||
import { FilterQuery } from './reducer';
|
import { FilterQuery, SerializedFilterQuery } from './reducer';
|
||||||
|
|
||||||
const actionCreator = actionCreatorFactory('x-pack/infra/local/waffle_filter');
|
const actionCreator = actionCreatorFactory('x-pack/infra/local/waffle_filter');
|
||||||
|
|
||||||
|
@ -14,4 +14,6 @@ export const setWaffleFilterQueryDraft = actionCreator<FilterQuery>(
|
||||||
'SET_WAFFLE_FILTER_QUERY_DRAFT'
|
'SET_WAFFLE_FILTER_QUERY_DRAFT'
|
||||||
);
|
);
|
||||||
|
|
||||||
export const applyWaffleFilterQuery = actionCreator<FilterQuery>('APPLY_WAFFLE_FILTER_QUERY');
|
export const applyWaffleFilterQuery = actionCreator<SerializedFilterQuery>(
|
||||||
|
'APPLY_WAFFLE_FILTER_QUERY'
|
||||||
|
);
|
||||||
|
|
|
@ -15,8 +15,13 @@ export interface KueryFilterQuery {
|
||||||
|
|
||||||
export type FilterQuery = KueryFilterQuery;
|
export type FilterQuery = KueryFilterQuery;
|
||||||
|
|
||||||
|
export interface SerializedFilterQuery {
|
||||||
|
query: FilterQuery;
|
||||||
|
serializedQuery: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WaffleFilterState {
|
export interface WaffleFilterState {
|
||||||
filterQuery: KueryFilterQuery | null;
|
filterQuery: SerializedFilterQuery | null;
|
||||||
filterQueryDraft: KueryFilterQuery | null;
|
filterQueryDraft: KueryFilterQuery | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +38,6 @@ export const waffleFilterReducer = reducerWithInitialState(initialWaffleFilterSt
|
||||||
.case(applyWaffleFilterQuery, (state, filterQuery) => ({
|
.case(applyWaffleFilterQuery, (state, filterQuery) => ({
|
||||||
...state,
|
...state,
|
||||||
filterQuery,
|
filterQuery,
|
||||||
filterQueryDraft: filterQuery,
|
filterQueryDraft: filterQuery.query,
|
||||||
}))
|
}))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -10,7 +10,11 @@ import { fromKueryExpression } from 'ui/kuery';
|
||||||
|
|
||||||
import { WaffleFilterState } from './reducer';
|
import { WaffleFilterState } from './reducer';
|
||||||
|
|
||||||
export const selectWaffleFilterQuery = (state: WaffleFilterState) => state.filterQuery;
|
export const selectWaffleFilterQuery = (state: WaffleFilterState) =>
|
||||||
|
state.filterQuery ? state.filterQuery.query : null;
|
||||||
|
|
||||||
|
export const selectWaffleFilterQueryAsJson = (state: WaffleFilterState) =>
|
||||||
|
state.filterQuery ? state.filterQuery.serializedQuery : null;
|
||||||
|
|
||||||
export const selectWaffleFilterQueryDraft = (state: WaffleFilterState) => state.filterQueryDraft;
|
export const selectWaffleFilterQueryDraft = (state: WaffleFilterState) => state.filterQueryDraft;
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,3 @@
|
||||||
|
|
||||||
export { logEntriesActions } from './log_entries';
|
export { logEntriesActions } from './log_entries';
|
||||||
export { logSummaryActions } from './log_summary';
|
export { logSummaryActions } from './log_summary';
|
||||||
export { sourceActions } from './source';
|
|
||||||
|
|
|
@ -8,11 +8,6 @@ import { combineEpics } from 'redux-observable';
|
||||||
|
|
||||||
import { createLogEntriesEpic } from './log_entries';
|
import { createLogEntriesEpic } from './log_entries';
|
||||||
import { createLogSummaryEpic } from './log_summary';
|
import { createLogSummaryEpic } from './log_summary';
|
||||||
import { createSourceEpic } from './source';
|
|
||||||
|
|
||||||
export const createRemoteEpic = <State>() =>
|
export const createRemoteEpic = <State>() =>
|
||||||
combineEpics(
|
combineEpics(createLogEntriesEpic<State>(), createLogSummaryEpic<State>());
|
||||||
createLogEntriesEpic<State>(),
|
|
||||||
createLogSummaryEpic<State>(),
|
|
||||||
createSourceEpic<State>()
|
|
||||||
);
|
|
||||||
|
|
|
@ -7,22 +7,18 @@
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import { initialLogEntriesState, logEntriesReducer, LogEntriesState } from './log_entries';
|
import { initialLogEntriesState, logEntriesReducer, LogEntriesState } from './log_entries';
|
||||||
import { initialLogSummaryState, logSummaryReducer, LogSummaryState } from './log_summary';
|
import { initialLogSummaryState, logSummaryReducer, LogSummaryState } from './log_summary';
|
||||||
import { initialSourceState, sourceReducer, SourceState } from './source';
|
|
||||||
|
|
||||||
export interface RemoteState {
|
export interface RemoteState {
|
||||||
logEntries: LogEntriesState;
|
logEntries: LogEntriesState;
|
||||||
logSummary: LogSummaryState;
|
logSummary: LogSummaryState;
|
||||||
source: SourceState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialRemoteState = {
|
export const initialRemoteState = {
|
||||||
logEntries: initialLogEntriesState,
|
logEntries: initialLogEntriesState,
|
||||||
logSummary: initialLogSummaryState,
|
logSummary: initialLogSummaryState,
|
||||||
source: initialSourceState,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remoteReducer = combineReducers<RemoteState>({
|
export const remoteReducer = combineReducers<RemoteState>({
|
||||||
logEntries: logEntriesReducer,
|
logEntries: logEntriesReducer,
|
||||||
logSummary: logSummaryReducer,
|
logSummary: logSummaryReducer,
|
||||||
source: sourceReducer,
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { globalizeSelectors } from '../../utils/typed_redux';
|
||||||
import { logEntriesSelectors as innerLogEntriesSelectors } from './log_entries';
|
import { logEntriesSelectors as innerLogEntriesSelectors } from './log_entries';
|
||||||
import { logSummarySelectors as innerLogSummarySelectors } from './log_summary';
|
import { logSummarySelectors as innerLogSummarySelectors } from './log_summary';
|
||||||
import { RemoteState } from './reducer';
|
import { RemoteState } from './reducer';
|
||||||
import { sourceSelectors as innerSourceSelectors } from './source';
|
|
||||||
|
|
||||||
export const logEntriesSelectors = globalizeSelectors(
|
export const logEntriesSelectors = globalizeSelectors(
|
||||||
(state: RemoteState) => state.logEntries,
|
(state: RemoteState) => state.logEntries,
|
||||||
|
@ -19,8 +18,3 @@ export const logSummarySelectors = globalizeSelectors(
|
||||||
(state: RemoteState) => state.logSummary,
|
(state: RemoteState) => state.logSummary,
|
||||||
innerLogSummarySelectors
|
innerLogSummarySelectors
|
||||||
);
|
);
|
||||||
|
|
||||||
export const sourceSelectors = globalizeSelectors(
|
|
||||||
(state: RemoteState) => state.source,
|
|
||||||
innerSourceSelectors
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Action } from 'redux';
|
|
||||||
import { combineEpics, Epic, EpicWithState } from 'redux-observable';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
|
|
||||||
import { loadSource } from './actions';
|
|
||||||
import { loadSourceEpic } from './operations/load';
|
|
||||||
|
|
||||||
export const createSourceEpic = <State>() =>
|
|
||||||
combineEpics(createSourceEffectsEpic<State>(), loadSourceEpic as EpicWithState<
|
|
||||||
typeof loadSourceEpic,
|
|
||||||
State
|
|
||||||
>);
|
|
||||||
|
|
||||||
export const createSourceEffectsEpic = <State>(): Epic<Action, Action, State, {}> => action$ => {
|
|
||||||
return of(loadSource({ sourceId: 'default' }));
|
|
||||||
};
|
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as sourceActions from './actions';
|
|
||||||
import * as sourceSelectors from './selectors';
|
|
||||||
|
|
||||||
export { sourceActions, sourceSelectors };
|
|
||||||
export * from './epic';
|
|
||||||
export * from './reducer';
|
|
||||||
export { initialSourceState, SourceState } from './state';
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { SourceQuery } from '../../../../../common/graphql/types';
|
|
||||||
import {
|
|
||||||
createGraphqlOperationActionCreators,
|
|
||||||
createGraphqlOperationReducer,
|
|
||||||
createGraphqlQueryEpic,
|
|
||||||
} from '../../../../utils/remote_state/remote_graphql_state';
|
|
||||||
import { initialSourceState } from '../state';
|
|
||||||
import { sourceQuery } from './query_source.gql_query';
|
|
||||||
|
|
||||||
const operationKey = 'load';
|
|
||||||
|
|
||||||
export const loadSourceActionCreators = createGraphqlOperationActionCreators<
|
|
||||||
SourceQuery.Query,
|
|
||||||
SourceQuery.Variables
|
|
||||||
>('source', operationKey);
|
|
||||||
|
|
||||||
export const loadSourceReducer = createGraphqlOperationReducer(
|
|
||||||
operationKey,
|
|
||||||
initialSourceState,
|
|
||||||
loadSourceActionCreators,
|
|
||||||
(state, action) => action.payload.result.data.source
|
|
||||||
);
|
|
||||||
|
|
||||||
export const loadSourceEpic = createGraphqlQueryEpic(sourceQuery, loadSourceActionCreators);
|
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import reduceReducers from 'reduce-reducers';
|
|
||||||
import { Reducer } from 'redux';
|
|
||||||
|
|
||||||
import { loadSourceReducer } from './operations/load';
|
|
||||||
import { SourceState } from './state';
|
|
||||||
|
|
||||||
export const sourceReducer = reduceReducers(loadSourceReducer) as Reducer<SourceState>;
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
|
|
||||||
import { createGraphqlStateSelectors } from '../../../utils/remote_state/remote_graphql_state';
|
|
||||||
import { SourceRemoteState } from './state';
|
|
||||||
|
|
||||||
const sourceStatusGraphqlStateSelectors = createGraphqlStateSelectors<SourceRemoteState>();
|
|
||||||
|
|
||||||
export const selectSource = sourceStatusGraphqlStateSelectors.selectData;
|
|
||||||
|
|
||||||
export const selectSourceConfiguration = createSelector(
|
|
||||||
selectSource,
|
|
||||||
source => (source ? source.configuration : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceLogAlias = createSelector(
|
|
||||||
selectSourceConfiguration,
|
|
||||||
configuration => (configuration ? configuration.logAlias : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceMetricAlias = createSelector(
|
|
||||||
selectSourceConfiguration,
|
|
||||||
configuration => (configuration ? configuration.metricAlias : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceFields = createSelector(
|
|
||||||
selectSourceConfiguration,
|
|
||||||
configuration => (configuration ? configuration.fields : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceStatus = createSelector(
|
|
||||||
selectSource,
|
|
||||||
source => (source ? source.status : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceLogIndicesExist = createSelector(
|
|
||||||
selectSourceStatus,
|
|
||||||
sourceStatus => (sourceStatus ? sourceStatus.logIndicesExist : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceMetricIndicesExist = createSelector(
|
|
||||||
selectSourceStatus,
|
|
||||||
sourceStatus => (sourceStatus ? sourceStatus.metricIndicesExist : null)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectSourceIndexFields = createSelector(
|
|
||||||
selectSourceStatus,
|
|
||||||
sourceStatus => (sourceStatus ? sourceStatus.indexFields : [])
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectDerivedIndexPattern = createSelector(
|
|
||||||
selectSourceIndexFields,
|
|
||||||
selectSourceLogAlias,
|
|
||||||
selectSourceMetricAlias,
|
|
||||||
(indexFields, logAlias, metricAlias) => ({
|
|
||||||
fields: indexFields,
|
|
||||||
title: `${logAlias},${metricAlias}`,
|
|
||||||
})
|
|
||||||
);
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { SourceQuery } from '../../../../common/graphql/types';
|
|
||||||
import {
|
|
||||||
createGraphqlInitialState,
|
|
||||||
GraphqlState,
|
|
||||||
} from '../../../utils/remote_state/remote_graphql_state';
|
|
||||||
|
|
||||||
export type SourceRemoteState = SourceQuery.Source;
|
|
||||||
export type SourceState = GraphqlState<SourceRemoteState>;
|
|
||||||
|
|
||||||
export const initialSourceState = createGraphqlInitialState<SourceRemoteState>();
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { fromKueryExpression, toElasticsearchQuery } from 'ui/kuery';
|
|
||||||
|
|
||||||
import { getLogEntryAtTime } from '../utils/log_entry';
|
import { getLogEntryAtTime } from '../utils/log_entry';
|
||||||
import { globalizeSelectors } from '../utils/typed_redux';
|
import { globalizeSelectors } from '../utils/typed_redux';
|
||||||
import {
|
import {
|
||||||
|
@ -24,7 +22,6 @@ import { State } from './reducer';
|
||||||
import {
|
import {
|
||||||
logEntriesSelectors as remoteLogEntriesSelectors,
|
logEntriesSelectors as remoteLogEntriesSelectors,
|
||||||
logSummarySelectors as remoteLogSummarySelectors,
|
logSummarySelectors as remoteLogSummarySelectors,
|
||||||
sourceSelectors as remoteSourceSelectors,
|
|
||||||
} from './remote';
|
} from './remote';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +47,6 @@ const selectRemote = (state: State) => state.remote;
|
||||||
|
|
||||||
export const logEntriesSelectors = globalizeSelectors(selectRemote, remoteLogEntriesSelectors);
|
export const logEntriesSelectors = globalizeSelectors(selectRemote, remoteLogEntriesSelectors);
|
||||||
export const logSummarySelectors = globalizeSelectors(selectRemote, remoteLogSummarySelectors);
|
export const logSummarySelectors = globalizeSelectors(selectRemote, remoteLogSummarySelectors);
|
||||||
export const sourceSelectors = globalizeSelectors(selectRemote, remoteSourceSelectors);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shared selectors
|
* shared selectors
|
||||||
|
@ -75,34 +71,4 @@ export const sharedSelectors = {
|
||||||
(entries, lastVisiblePosition) =>
|
(entries, lastVisiblePosition) =>
|
||||||
lastVisiblePosition ? getLogEntryAtTime(entries, lastVisiblePosition) : null
|
lastVisiblePosition ? getLogEntryAtTime(entries, lastVisiblePosition) : null
|
||||||
),
|
),
|
||||||
selectLogFilterQueryAsJson: createSelector(
|
|
||||||
logFilterSelectors.selectLogFilterQuery,
|
|
||||||
sourceSelectors.selectDerivedIndexPattern,
|
|
||||||
(filterQuery, indexPattern) => {
|
|
||||||
try {
|
|
||||||
return filterQuery
|
|
||||||
? JSON.stringify(
|
|
||||||
toElasticsearchQuery(fromKueryExpression(filterQuery.expression), indexPattern)
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
selectWaffleFilterQueryAsJson: createSelector(
|
|
||||||
waffleFilterSelectors.selectWaffleFilterQuery,
|
|
||||||
sourceSelectors.selectDerivedIndexPattern,
|
|
||||||
(filterQuery, indexPattern) => {
|
|
||||||
try {
|
|
||||||
return filterQuery
|
|
||||||
? JSON.stringify(
|
|
||||||
toElasticsearchQuery(fromKueryExpression(filterQuery.expression), indexPattern)
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,10 +13,10 @@ import {
|
||||||
createRootEpic,
|
createRootEpic,
|
||||||
initialState,
|
initialState,
|
||||||
logEntriesSelectors,
|
logEntriesSelectors,
|
||||||
|
logFilterSelectors,
|
||||||
logPositionSelectors,
|
logPositionSelectors,
|
||||||
metricTimeSelectors,
|
metricTimeSelectors,
|
||||||
reducer,
|
reducer,
|
||||||
sharedSelectors,
|
|
||||||
State,
|
State,
|
||||||
waffleTimeSelectors,
|
waffleTimeSelectors,
|
||||||
} from '.';
|
} from '.';
|
||||||
|
@ -45,7 +45,7 @@ export function createStore({ apolloClient, observableApi }: StoreDependencies)
|
||||||
selectHasMoreLogEntriesAfterEnd: logEntriesSelectors.selectHasMoreAfterEnd,
|
selectHasMoreLogEntriesAfterEnd: logEntriesSelectors.selectHasMoreAfterEnd,
|
||||||
selectHasMoreLogEntriesBeforeStart: logEntriesSelectors.selectHasMoreBeforeStart,
|
selectHasMoreLogEntriesBeforeStart: logEntriesSelectors.selectHasMoreBeforeStart,
|
||||||
selectIsAutoReloadingLogEntries: logPositionSelectors.selectIsAutoReloading,
|
selectIsAutoReloadingLogEntries: logPositionSelectors.selectIsAutoReloading,
|
||||||
selectLogFilterQueryAsJson: sharedSelectors.selectLogFilterQueryAsJson,
|
selectLogFilterQueryAsJson: logFilterSelectors.selectLogFilterQueryAsJson,
|
||||||
selectLogTargetPosition: logPositionSelectors.selectTargetPosition,
|
selectLogTargetPosition: logPositionSelectors.selectTargetPosition,
|
||||||
selectVisibleLogMidpointOrTarget: logPositionSelectors.selectVisibleMidpointOrTarget,
|
selectVisibleLogMidpointOrTarget: logPositionSelectors.selectVisibleMidpointOrTarget,
|
||||||
selectVisibleLogSummary: logPositionSelectors.selectVisibleSummary,
|
selectVisibleLogSummary: logPositionSelectors.selectVisibleSummary,
|
||||||
|
|
21
x-pack/plugins/infra/public/utils/kuery.ts
Normal file
21
x-pack/plugins/infra/public/utils/kuery.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||||
|
import { fromKueryExpression, toElasticsearchQuery } from 'ui/kuery';
|
||||||
|
|
||||||
|
export const convertKueryToElasticSearchQuery = (
|
||||||
|
kueryExpression: string,
|
||||||
|
indexPattern: StaticIndexPattern
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
return kueryExpression
|
||||||
|
? JSON.stringify(toElasticsearchQuery(fromKueryExpression(kueryExpression), indexPattern))
|
||||||
|
: '';
|
||||||
|
} catch (err) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
90
x-pack/plugins/infra/public/utils/operation_status.ts
Normal file
90
x-pack/plugins/infra/public/utils/operation_status.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import last from 'lodash/fp/last';
|
||||||
|
import { oc } from 'ts-optchain';
|
||||||
|
|
||||||
|
export interface InProgressStatus<O extends Operation<string, any>> {
|
||||||
|
operation: O;
|
||||||
|
status: 'in-progress';
|
||||||
|
time: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SucceededStatus<O extends Operation<string, any>> {
|
||||||
|
operation: O;
|
||||||
|
status: 'succeeded';
|
||||||
|
time: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FailedStatus<O extends Operation<string, any>> {
|
||||||
|
message: string;
|
||||||
|
operation: O;
|
||||||
|
status: 'failed';
|
||||||
|
time: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFailedStatus = <O extends Operation<string, any>>(
|
||||||
|
status: OperationStatus<O>
|
||||||
|
): status is FailedStatus<O> => status.status === 'failed';
|
||||||
|
|
||||||
|
export type OperationStatus<O extends Operation<string, any>> =
|
||||||
|
| InProgressStatus<O>
|
||||||
|
| SucceededStatus<O>
|
||||||
|
| FailedStatus<O>;
|
||||||
|
|
||||||
|
export interface Operation<Name extends string, Parameters> {
|
||||||
|
name: Name;
|
||||||
|
parameters: Parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createStatusSelectors = <S extends {}>(
|
||||||
|
selectStatusHistory: (state: S) => Array<OperationStatus<any>>
|
||||||
|
) => ({
|
||||||
|
getIsInProgress: () => (state: S) =>
|
||||||
|
oc(last(selectStatusHistory(state))).status() === 'in-progress',
|
||||||
|
getHasSucceeded: () => (state: S) =>
|
||||||
|
oc(last(selectStatusHistory(state))).status() === 'succeeded',
|
||||||
|
getHasFailed: () => (state: S) => oc(last(selectStatusHistory(state))).status() === 'failed',
|
||||||
|
getLastFailureMessage: () => (state: S) =>
|
||||||
|
oc(last(selectStatusHistory(state).filter(isFailedStatus))).message(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type StatusHistoryUpdater<Operations extends Operation<string, any>> = (
|
||||||
|
statusHistory: Array<OperationStatus<Operations>>
|
||||||
|
) => Array<OperationStatus<Operations>>;
|
||||||
|
|
||||||
|
export const createStatusActions = <S extends {}, Operations extends Operation<string, any>>(
|
||||||
|
updateStatusHistory: (updater: StatusHistoryUpdater<Operations>) => (state: S) => S
|
||||||
|
) => ({
|
||||||
|
startOperation: (operation: Operations) =>
|
||||||
|
updateStatusHistory(statusHistory => [
|
||||||
|
...statusHistory,
|
||||||
|
{
|
||||||
|
operation,
|
||||||
|
status: 'in-progress',
|
||||||
|
time: Date.now(),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
finishOperation: (operation: Operations) =>
|
||||||
|
updateStatusHistory(statusHistory => [
|
||||||
|
...statusHistory,
|
||||||
|
{
|
||||||
|
operation,
|
||||||
|
status: 'succeeded',
|
||||||
|
time: Date.now(),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
failOperation: (operation: Operations, message: string) =>
|
||||||
|
updateStatusHistory(statusHistory => [
|
||||||
|
...statusHistory,
|
||||||
|
{
|
||||||
|
message,
|
||||||
|
operation,
|
||||||
|
status: 'failed',
|
||||||
|
time: Date.now(),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
});
|
101
x-pack/plugins/infra/public/utils/typed_constate.tsx
Normal file
101
x-pack/plugins/infra/public/utils/typed_constate.tsx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The helper types and functions below are designed to be used with constate
|
||||||
|
* v0.9. From version 1.0 the use of react hooks probably makes them
|
||||||
|
* unnecessary.
|
||||||
|
*
|
||||||
|
* The `inferActionMap`, `inferEffectMap` and `inferSelectorMap` functions
|
||||||
|
* remove the necessity to type out the child-facing interfaces as suggested in
|
||||||
|
* the constate typescript documentation by inferring the `ActionMap`,
|
||||||
|
* `EffectMap` and `SelectorMap` types from the object passed as an argument.
|
||||||
|
* At runtime these functions just return their first argument without
|
||||||
|
* modification.
|
||||||
|
*
|
||||||
|
* Until partial type argument inference is (hopefully) introduced with
|
||||||
|
* TypeScript 3.3, the functions are split into two nested functions to allow
|
||||||
|
* for specifying the `State` type argument while leaving the other type
|
||||||
|
* arguments for inference by the compiler.
|
||||||
|
*
|
||||||
|
* Example Usage:
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* const actions = inferActionMap<State>()({
|
||||||
|
* increment: (amount: number) => state => ({ ...state, count: state.count + amount }),
|
||||||
|
* });
|
||||||
|
* // actions has type ActionMap<State, { increment: (amount: number) => void; }>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ActionMap, EffectMap, EffectProps, SelectorMap } from 'constate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* actions
|
||||||
|
*/
|
||||||
|
|
||||||
|
type InferredAction<State, Action> = Action extends (...args: infer A) => (state: State) => State
|
||||||
|
? (...args: A) => void
|
||||||
|
: never;
|
||||||
|
|
||||||
|
type InferredActions<State, Actions> = ActionMap<
|
||||||
|
State,
|
||||||
|
{ [K in keyof Actions]: InferredAction<State, Actions[K]> }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const inferActionMap = <State extends any>() => <
|
||||||
|
Actions extends {
|
||||||
|
[key: string]: (...args: any[]) => (state: State) => State;
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
actionMap: Actions
|
||||||
|
): InferredActions<State, Actions> => actionMap as any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* effects
|
||||||
|
*/
|
||||||
|
|
||||||
|
type InferredEffect<State, Effect> = Effect extends (
|
||||||
|
...args: infer A
|
||||||
|
) => (props: EffectProps<State>) => infer R
|
||||||
|
? (...args: A) => R
|
||||||
|
: never;
|
||||||
|
|
||||||
|
type InferredEffects<State, Effects> = EffectMap<
|
||||||
|
State,
|
||||||
|
{ [K in keyof Effects]: InferredEffect<State, Effects[K]> }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const inferEffectMap = <State extends any>() => <
|
||||||
|
Effects extends {
|
||||||
|
[key: string]: (...args: any[]) => (props: EffectProps<State>) => any;
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
effectMap: Effects
|
||||||
|
): InferredEffects<State, Effects> => effectMap as any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* selectors
|
||||||
|
*/
|
||||||
|
|
||||||
|
type InferredSelector<State, Selector> = Selector extends (
|
||||||
|
...args: infer A
|
||||||
|
) => (state: State) => infer R
|
||||||
|
? (...args: A) => R
|
||||||
|
: never;
|
||||||
|
|
||||||
|
type InferredSelectors<State, Selectors> = SelectorMap<
|
||||||
|
State,
|
||||||
|
{ [K in keyof Selectors]: InferredSelector<State, Selectors[K]> }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const inferSelectorMap = <State extends any>() => <
|
||||||
|
Selectors extends {
|
||||||
|
[key: string]: (...args: any[]) => (state: State) => any;
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
selectorMap: Selectors
|
||||||
|
): InferredSelectors<State, Selectors> => selectorMap as any;
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import expect from 'expect.js';
|
import expect from 'expect.js';
|
||||||
import { SourceQuery } from '../../../../plugins/infra/common/graphql/types';
|
import { SourceQuery } from '../../../../plugins/infra/common/graphql/types';
|
||||||
import { sourceQuery } from '../../../../plugins/infra/public/store/remote/source/operations/query_source.gql_query';
|
import { sourceQuery } from '../../../../plugins/infra/public/containers/with_source/query_source.gql_query';
|
||||||
|
|
||||||
import { KbnTestProvider } from './types';
|
import { KbnTestProvider } from './types';
|
||||||
|
|
||||||
|
|
|
@ -5710,6 +5710,11 @@ constants-browserify@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||||
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
||||||
|
|
||||||
|
constate@^0.9.0:
|
||||||
|
version "0.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/constate/-/constate-0.9.0.tgz#877197ef8fbcacee95672a7e98f7b21dec818891"
|
||||||
|
integrity sha512-Cgkqefi4GrepnA7gwqbrsU+Kf/xl0sPv3O1UNE/vUZtTgpWlkd+/rSZjjd7npICtExn6yuICro7Vb2zoFCnS/A==
|
||||||
|
|
||||||
contains-path@^0.1.0:
|
contains-path@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
|
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue