Modify I18nProvider so that it does not generate new React components (#43556)
This fixes some edge-cases that caused infinite loops: React thinks the tree has changed because of a new root component, effects fire off which change the state and cause a re-render, React thinks the tree has changed because of a new root component...
This commit is contained in:
parent
0f2324e445
commit
f188b292c8
|
@ -103,4 +103,8 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`I18nProvider renders children 1`] = `<ChildrenMock />`;
|
||||
exports[`I18nProvider renders children 1`] = `
|
||||
<PseudoLocaleWrapper>
|
||||
<ChildrenMock />
|
||||
</PseudoLocaleWrapper>
|
||||
`;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
import { intlShape } from 'react-intl';
|
||||
import { injectI18n } from './inject';
|
||||
import { I18nProvider } from './provider';
|
||||
|
||||
|
@ -46,7 +45,7 @@ describe('I18nProvider', () => {
|
|||
</I18nProvider>,
|
||||
{
|
||||
childContextTypes: {
|
||||
intl: intlShape,
|
||||
intl: { formatMessage: jest.fn() },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -22,47 +22,7 @@ import * as React from 'react';
|
|||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import * as i18n from '../core';
|
||||
import { isPseudoLocale, translateUsingPseudoLocale } from '../core/pseudo_locale';
|
||||
import { injectI18n } from './inject';
|
||||
|
||||
/**
|
||||
* To translate label that includes nested `FormattedMessage` instances React Intl
|
||||
* replaces them with special placeholders (@__uid__@ELEMENT-uid-counter@__uid__@)
|
||||
* and maps them back with nested translations after `formatMessage` processes
|
||||
* original string, so we shouldn't modify these special placeholders with pseudo
|
||||
* translations otherwise React Intl won't be able to properly replace placeholders.
|
||||
* It's implementation detail of the React Intl, but since pseudo localization is dev
|
||||
* only feature we should be fine here.
|
||||
* @param message
|
||||
*/
|
||||
function translateFormattedMessageUsingPseudoLocale(message: string) {
|
||||
const formattedMessageDelimiter = message.match(/@__.{10}__@/);
|
||||
if (formattedMessageDelimiter !== null) {
|
||||
return message
|
||||
.split(formattedMessageDelimiter[0])
|
||||
.map(part => (part.startsWith('ELEMENT-') ? part : translateUsingPseudoLocale(part)))
|
||||
.join(formattedMessageDelimiter[0]);
|
||||
}
|
||||
|
||||
return translateUsingPseudoLocale(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* If pseudo locale is detected, default intl.formatMessage should be decorated
|
||||
* with the pseudo localization function.
|
||||
* @param child I18nProvider child component.
|
||||
*/
|
||||
function wrapIntlFormatMessage(child: React.ReactElement) {
|
||||
return React.createElement(
|
||||
injectI18n(({ intl }) => {
|
||||
const formatMessage = intl.formatMessage;
|
||||
intl.formatMessage = (...args) =>
|
||||
translateFormattedMessageUsingPseudoLocale(formatMessage(...args));
|
||||
|
||||
return React.Children.only(child);
|
||||
})
|
||||
);
|
||||
}
|
||||
import { PseudoLocaleWrapper } from './pseudo_locale_wrapper';
|
||||
|
||||
/**
|
||||
* The library uses the provider pattern to scope an i18n context to a tree
|
||||
|
@ -81,9 +41,7 @@ export class I18nProvider extends React.PureComponent {
|
|||
formats={i18n.getFormats()}
|
||||
textComponent={React.Fragment}
|
||||
>
|
||||
{isPseudoLocale(i18n.getLocale()) && React.isValidElement(this.props.children)
|
||||
? wrapIntlFormatMessage(this.props.children)
|
||||
: this.props.children}
|
||||
<PseudoLocaleWrapper>{this.props.children}</PseudoLocaleWrapper>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
|
75
packages/kbn-i18n/src/react/pseudo_locale_wrapper.tsx
Normal file
75
packages/kbn-i18n/src/react/pseudo_locale_wrapper.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
import * as i18n from '../core';
|
||||
import { isPseudoLocale, translateUsingPseudoLocale } from '../core/pseudo_locale';
|
||||
|
||||
/**
|
||||
* To translate label that includes nested `FormattedMessage` instances React Intl
|
||||
* replaces them with special placeholders (@__uid__@ELEMENT-uid-counter@__uid__@)
|
||||
* and maps them back with nested translations after `formatMessage` processes
|
||||
* original string, so we shouldn't modify these special placeholders with pseudo
|
||||
* translations otherwise React Intl won't be able to properly replace placeholders.
|
||||
* It's implementation detail of the React Intl, but since pseudo localization is dev
|
||||
* only feature we should be fine here.
|
||||
* @param message
|
||||
*/
|
||||
function translateFormattedMessageUsingPseudoLocale(message: string) {
|
||||
const formattedMessageDelimiter = message.match(/@__.{10}__@/);
|
||||
if (formattedMessageDelimiter !== null) {
|
||||
return message
|
||||
.split(formattedMessageDelimiter[0])
|
||||
.map(part => (part.startsWith('ELEMENT-') ? part : translateUsingPseudoLocale(part)))
|
||||
.join(formattedMessageDelimiter[0]);
|
||||
}
|
||||
|
||||
return translateUsingPseudoLocale(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the locale is our pseudo locale (e.g. en-xa), we override the
|
||||
* intl.formatMessage function to display scrambled characters. We are
|
||||
* overriding the context rather than using injectI18n, because the
|
||||
* latter creates a new React component, which causes React diffs to
|
||||
* be inefficient in some cases, and can cause React hooks to lose
|
||||
* their state.
|
||||
*/
|
||||
export class PseudoLocaleWrapper extends React.PureComponent {
|
||||
public static propTypes = { children: PropTypes.element.isRequired };
|
||||
|
||||
public static contextTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
constructor(props: { children: React.ReactNode }, context: any) {
|
||||
super(props, context);
|
||||
|
||||
if (isPseudoLocale(i18n.getLocale())) {
|
||||
const formatMessage = context.intl.formatMessage;
|
||||
context.intl.formatMessage = (...args: any[]) =>
|
||||
translateFormattedMessageUsingPseudoLocale(formatMessage(...args));
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
|
@ -28,15 +28,8 @@ const getStateChildComponent = (
|
|||
): // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
React.Component<{}, {}, any> =>
|
||||
wrapper
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.find('[data-test-subj="stateful-timeline"]')
|
||||
.last()
|
||||
.instance();
|
||||
|
||||
describe('StatefulOpenTimeline', () => {
|
||||
|
@ -49,6 +42,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -81,6 +75,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -306,6 +301,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -336,6 +332,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -377,6 +374,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -416,6 +414,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -468,6 +467,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -505,6 +505,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -532,6 +533,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -569,6 +571,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<TestProviderWithoutDragAndDrop>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -600,6 +603,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
@ -637,6 +641,7 @@ describe('StatefulOpenTimeline', () => {
|
|||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<StatefulOpenTimeline
|
||||
data-test-subj="stateful-timeline"
|
||||
apolloClient={apolloClient}
|
||||
isModal={false}
|
||||
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
|
||||
|
|
|
@ -24,17 +24,7 @@ const getStateChildComponent = (
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
wrapper: ReactWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>
|
||||
): // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
React.Component<{}, {}, any> =>
|
||||
wrapper
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.childAt(0)
|
||||
.instance();
|
||||
React.Component<{}, {}, any> => wrapper.find('[data-test-subj="state-child-component"]').instance();
|
||||
|
||||
describe('OpenTimelineModalButton', () => {
|
||||
const theme = () => ({ eui: euiDarkVars, darkMode: true });
|
||||
|
@ -66,7 +56,10 @@ describe('OpenTimelineModalButton', () => {
|
|||
<ThemeProvider theme={theme}>
|
||||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<OpenTimelineModalButton onToggle={jest.fn()} />
|
||||
<OpenTimelineModalButton
|
||||
data-test-subj="state-child-component"
|
||||
onToggle={jest.fn()}
|
||||
/>
|
||||
</MockedProvider>
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
</ThemeProvider>
|
||||
|
@ -158,7 +151,10 @@ describe('OpenTimelineModalButton', () => {
|
|||
<ThemeProvider theme={theme}>
|
||||
<TestProviderWithoutDragAndDrop>
|
||||
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
|
||||
<OpenTimelineModalButton onToggle={jest.fn()} />
|
||||
<OpenTimelineModalButton
|
||||
data-test-subj="state-child-component"
|
||||
onToggle={jest.fn()}
|
||||
/>
|
||||
</MockedProvider>
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
</ThemeProvider>
|
||||
|
|
|
@ -198,55 +198,11 @@ exports[`UrlStateContainer mounts and renders 1`] = `
|
|||
messages={Object {}}
|
||||
textComponent={Symbol(react.fragment)}
|
||||
>
|
||||
<ApolloProvider
|
||||
client={
|
||||
ApolloClient {
|
||||
"__operations_cache__": Map {},
|
||||
"cache": InMemoryCache {
|
||||
"addTypename": true,
|
||||
"cacheKeyRoot": KeyTrie {
|
||||
"weakness": true,
|
||||
},
|
||||
"config": Object {
|
||||
"addTypename": true,
|
||||
"dataIdFromObject": [Function],
|
||||
"fragmentMatcher": HeuristicFragmentMatcher {},
|
||||
"freezeResults": false,
|
||||
"resultCaching": true,
|
||||
},
|
||||
"data": DepTrackingCache {
|
||||
"data": Object {},
|
||||
"depend": [Function],
|
||||
},
|
||||
"maybeBroadcastWatch": [Function],
|
||||
"optimisticData": DepTrackingCache {
|
||||
"data": Object {},
|
||||
"depend": [Function],
|
||||
},
|
||||
"silenceBroadcast": false,
|
||||
"storeReader": StoreReader {
|
||||
"executeSelectionSet": [Function],
|
||||
"executeStoreQuery": [Function],
|
||||
"executeSubSelectedArray": [Function],
|
||||
"freezeResults": false,
|
||||
},
|
||||
"storeWriter": StoreWriter {},
|
||||
"typenameDocumentCache": Map {},
|
||||
"watches": Set {},
|
||||
},
|
||||
"defaultOptions": Object {},
|
||||
"disableNetworkFetches": false,
|
||||
"link": ApolloLink {
|
||||
"request": [Function],
|
||||
},
|
||||
"mutate": [Function],
|
||||
"query": [Function],
|
||||
"queryDeduplication": true,
|
||||
"reFetchObservableQueries": [Function],
|
||||
"resetStore": [Function],
|
||||
"resetStoreCallbacks": Array [],
|
||||
"ssrMode": false,
|
||||
"store": DataStore {
|
||||
<PseudoLocaleWrapper>
|
||||
<ApolloProvider
|
||||
client={
|
||||
ApolloClient {
|
||||
"__operations_cache__": Map {},
|
||||
"cache": InMemoryCache {
|
||||
"addTypename": true,
|
||||
"cacheKeyRoot": KeyTrie {
|
||||
|
@ -279,177 +235,142 @@ exports[`UrlStateContainer mounts and renders 1`] = `
|
|||
"typenameDocumentCache": Map {},
|
||||
"watches": Set {},
|
||||
},
|
||||
},
|
||||
"version": "2.3.8",
|
||||
"watchQuery": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Provider
|
||||
store={
|
||||
Object {
|
||||
"dispatch": [Function],
|
||||
"getState": [Function],
|
||||
"replaceReducer": [Function],
|
||||
"subscribe": [Function],
|
||||
Symbol(observable): [Function],
|
||||
"defaultOptions": Object {},
|
||||
"disableNetworkFetches": false,
|
||||
"link": ApolloLink {
|
||||
"request": [Function],
|
||||
},
|
||||
"mutate": [Function],
|
||||
"query": [Function],
|
||||
"queryDeduplication": true,
|
||||
"reFetchObservableQueries": [Function],
|
||||
"resetStore": [Function],
|
||||
"resetStoreCallbacks": Array [],
|
||||
"ssrMode": false,
|
||||
"store": DataStore {
|
||||
"cache": InMemoryCache {
|
||||
"addTypename": true,
|
||||
"cacheKeyRoot": KeyTrie {
|
||||
"weakness": true,
|
||||
},
|
||||
"config": Object {
|
||||
"addTypename": true,
|
||||
"dataIdFromObject": [Function],
|
||||
"fragmentMatcher": HeuristicFragmentMatcher {},
|
||||
"freezeResults": false,
|
||||
"resultCaching": true,
|
||||
},
|
||||
"data": DepTrackingCache {
|
||||
"data": Object {},
|
||||
"depend": [Function],
|
||||
},
|
||||
"maybeBroadcastWatch": [Function],
|
||||
"optimisticData": DepTrackingCache {
|
||||
"data": Object {},
|
||||
"depend": [Function],
|
||||
},
|
||||
"silenceBroadcast": false,
|
||||
"storeReader": StoreReader {
|
||||
"executeSelectionSet": [Function],
|
||||
"executeStoreQuery": [Function],
|
||||
"executeSubSelectedArray": [Function],
|
||||
"freezeResults": false,
|
||||
},
|
||||
"storeWriter": StoreWriter {},
|
||||
"typenameDocumentCache": Map {},
|
||||
"watches": Set {},
|
||||
},
|
||||
},
|
||||
"version": "2.3.8",
|
||||
"watchQuery": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<ThemeProvider
|
||||
theme={[Function]}
|
||||
<Provider
|
||||
store={
|
||||
Object {
|
||||
"dispatch": [Function],
|
||||
"getState": [Function],
|
||||
"replaceReducer": [Function],
|
||||
"subscribe": [Function],
|
||||
Symbol(observable): [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<DragDropContext
|
||||
onDragEnd={[MockFunction]}
|
||||
<ThemeProvider
|
||||
theme={[Function]}
|
||||
>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [MockFunction],
|
||||
"createHref": [MockFunction],
|
||||
"go": [MockFunction],
|
||||
"goBack": [MockFunction],
|
||||
"goForward": [MockFunction],
|
||||
"length": 2,
|
||||
"listen": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
<DragDropContext
|
||||
onDragEnd={[MockFunction]}
|
||||
>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [MockFunction],
|
||||
"createHref": [MockFunction],
|
||||
"go": [MockFunction],
|
||||
"goBack": [MockFunction],
|
||||
"goForward": [MockFunction],
|
||||
"length": 2,
|
||||
"listen": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
],
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
},
|
||||
"push": [MockFunction],
|
||||
"replace": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"results": Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "?kqlQuery=(filterQuery:!n,queryLocation:network.page,type:page)",
|
||||
"state": "",
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<withRouter(Connect(UrlStateContainer))
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"name": "response",
|
||||
"searchable": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
"title": "logstash-*",
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
},
|
||||
"push": [MockFunction],
|
||||
"replace": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "?kqlQuery=(filterQuery:!n,queryLocation:network.page,type:page)",
|
||||
"state": "",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<Route>
|
||||
<Connect(UrlStateContainer)
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [MockFunction],
|
||||
"createHref": [MockFunction],
|
||||
"go": [MockFunction],
|
||||
"goBack": [MockFunction],
|
||||
"goForward": [MockFunction],
|
||||
"length": 2,
|
||||
"listen": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
<withRouter(Connect(UrlStateContainer))
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"name": "response",
|
||||
"searchable": true,
|
||||
"type": "number",
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
},
|
||||
"push": [MockFunction],
|
||||
"replace": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "?kqlQuery=(filterQuery:!n,queryLocation:network.page,type:page)",
|
||||
"state": "",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
],
|
||||
"title": "logstash-*",
|
||||
}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"name": "response",
|
||||
"searchable": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
"title": "logstash-*",
|
||||
}
|
||||
}
|
||||
location={
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
}
|
||||
}
|
||||
match={
|
||||
Object {
|
||||
"isExact": false,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Component
|
||||
}
|
||||
>
|
||||
<Route>
|
||||
<Connect(UrlStateContainer)
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
|
@ -528,74 +449,155 @@ exports[`UrlStateContainer mounts and renders 1`] = `
|
|||
"url": "/",
|
||||
}
|
||||
}
|
||||
setAbsoluteTimerange={[Function]}
|
||||
setHostsKql={[Function]}
|
||||
setNetworkKql={[Function]}
|
||||
setRelativeTimerange={[Function]}
|
||||
toggleTimelineLinkTo={[Function]}
|
||||
urlState={
|
||||
Object {
|
||||
"kqlQuery": Object {
|
||||
"hosts.details": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "hosts.details",
|
||||
"type": "details",
|
||||
},
|
||||
"hosts.page": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "hosts.page",
|
||||
"type": "page",
|
||||
},
|
||||
"network.details": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "network.details",
|
||||
"type": "details",
|
||||
},
|
||||
"network.page": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "network.page",
|
||||
"type": "page",
|
||||
},
|
||||
},
|
||||
"timerange": Object {
|
||||
"global": Object {
|
||||
"linkTo": Array [
|
||||
"timeline",
|
||||
],
|
||||
"timerange": Object {
|
||||
"from": 0,
|
||||
"fromStr": "now-24h",
|
||||
"kind": "relative",
|
||||
"to": 1,
|
||||
"toStr": "now",
|
||||
},
|
||||
},
|
||||
"timeline": Object {
|
||||
"linkTo": Array [
|
||||
"global",
|
||||
],
|
||||
"timerange": Object {
|
||||
"from": 0,
|
||||
"fromStr": "now-24h",
|
||||
"kind": "relative",
|
||||
"to": 1,
|
||||
"toStr": "now",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span />
|
||||
</Component>
|
||||
</Connect(UrlStateContainer)>
|
||||
</Route>
|
||||
</withRouter(Connect(UrlStateContainer))>
|
||||
</Router>
|
||||
</DragDropContext>
|
||||
</ThemeProvider>
|
||||
</Provider>
|
||||
</ApolloProvider>
|
||||
<Component
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [MockFunction],
|
||||
"createHref": [MockFunction],
|
||||
"go": [MockFunction],
|
||||
"goBack": [MockFunction],
|
||||
"goForward": [MockFunction],
|
||||
"length": 2,
|
||||
"listen": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
},
|
||||
"push": [MockFunction],
|
||||
"replace": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "?kqlQuery=(filterQuery:!n,queryLocation:network.page,type:page)",
|
||||
"state": "",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"name": "response",
|
||||
"searchable": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
"title": "logstash-*",
|
||||
}
|
||||
}
|
||||
location={
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "/network",
|
||||
"search": "",
|
||||
"state": "",
|
||||
}
|
||||
}
|
||||
match={
|
||||
Object {
|
||||
"isExact": false,
|
||||
"params": Object {},
|
||||
"path": "/",
|
||||
"url": "/",
|
||||
}
|
||||
}
|
||||
setAbsoluteTimerange={[Function]}
|
||||
setHostsKql={[Function]}
|
||||
setNetworkKql={[Function]}
|
||||
setRelativeTimerange={[Function]}
|
||||
toggleTimelineLinkTo={[Function]}
|
||||
urlState={
|
||||
Object {
|
||||
"kqlQuery": Object {
|
||||
"hosts.details": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "hosts.details",
|
||||
"type": "details",
|
||||
},
|
||||
"hosts.page": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "hosts.page",
|
||||
"type": "page",
|
||||
},
|
||||
"network.details": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "network.details",
|
||||
"type": "details",
|
||||
},
|
||||
"network.page": Object {
|
||||
"filterQuery": null,
|
||||
"queryLocation": "network.page",
|
||||
"type": "page",
|
||||
},
|
||||
},
|
||||
"timerange": Object {
|
||||
"global": Object {
|
||||
"linkTo": Array [
|
||||
"timeline",
|
||||
],
|
||||
"timerange": Object {
|
||||
"from": 0,
|
||||
"fromStr": "now-24h",
|
||||
"kind": "relative",
|
||||
"to": 1,
|
||||
"toStr": "now",
|
||||
},
|
||||
},
|
||||
"timeline": Object {
|
||||
"linkTo": Array [
|
||||
"global",
|
||||
],
|
||||
"timerange": Object {
|
||||
"from": 0,
|
||||
"fromStr": "now-24h",
|
||||
"kind": "relative",
|
||||
"to": 1,
|
||||
"toStr": "now",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<span />
|
||||
</Component>
|
||||
</Connect(UrlStateContainer)>
|
||||
</Route>
|
||||
</withRouter(Connect(UrlStateContainer))>
|
||||
</Router>
|
||||
</DragDropContext>
|
||||
</ThemeProvider>
|
||||
</Provider>
|
||||
</ApolloProvider>
|
||||
</PseudoLocaleWrapper>
|
||||
</IntlProvider>
|
||||
</I18nProvider>
|
||||
</Component>
|
||||
|
|
Loading…
Reference in a new issue