[Logs UI] Remove apollo deps from log link-to routes (#74502)

This replaces the use of the old graphql-based `useSource` hook with the new plain JSON `useLogSource` hook.

It also fixes two more problems:

- A rendering problem with the source configuration loading screen and a `setState` race condition in the `useLogSource` hook.
- A non-backwards-compatible change of the `/link-to/:sourceId/logs` route in #61162.
This commit is contained in:
Felix Stürmer 2020-08-14 19:50:20 +02:00 committed by GitHub
parent 1ac87168b1
commit 0f1128281e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 453 additions and 147 deletions

View file

@ -20,6 +20,9 @@ export const logSourceConfigurationOriginRT = rt.keyof({
export type LogSourceConfigurationOrigin = rt.TypeOf<typeof logSourceConfigurationOriginRT>;
const logSourceFieldsConfigurationRT = rt.strict({
container: rt.string,
host: rt.string,
pod: rt.string,
timestamp: rt.string,
tiebreaker: rt.string,
});

View file

@ -30,7 +30,6 @@ export const findInventoryModel = (type: InventoryItemType) => {
};
interface InventoryFields {
message: string[];
host: string;
pod: string;
container: string;

View file

@ -17,10 +17,14 @@ import { FlexPage } from './page';
interface LoadingPageProps {
message?: ReactNode;
'data-test-subj'?: string;
}
export const LoadingPage = ({ message }: LoadingPageProps) => (
<FlexPage>
export const LoadingPage = ({
message,
'data-test-subj': dataTestSubj = 'loadingPage',
}: LoadingPageProps) => (
<FlexPage data-test-subj={dataTestSubj}>
<EuiPageBody>
<EuiPageContent verticalPosition="center" horizontalPosition="center">
<EuiFlexGroup alignItems="center">

View file

@ -23,5 +23,6 @@ export const PageContent = euiStyled.div`
`;
export const FlexPage = euiStyled(EuiPage)`
align-self: stretch;
flex: 1 0 0%;
`;

View file

@ -11,6 +11,7 @@ import { LoadingPage } from './loading_page';
export const SourceLoadingPage: React.FunctionComponent = () => (
<LoadingPage
data-test-subj="sourceLoadingPage"
message={
<FormattedMessage
id="xpack.infra.sourceLoadingPage.loadingDataSourcesMessage"

View file

@ -0,0 +1,78 @@
/*
* 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 { LogSourceConfiguration, LogSourceStatus, useLogSource } from './log_source';
type CreateUseLogSource = (sourceConfiguration?: { sourceId?: string }) => typeof useLogSource;
const defaultSourceId = 'default';
export const createUninitializedUseLogSourceMock: CreateUseLogSource = ({
sourceId = defaultSourceId,
} = {}) => () => ({
derivedIndexPattern: {
fields: [],
title: 'unknown',
},
hasFailedLoadingSource: false,
hasFailedLoadingSourceStatus: false,
initialize: jest.fn(),
isLoading: false,
isLoadingSourceConfiguration: false,
isLoadingSourceStatus: false,
isUninitialized: true,
loadSource: jest.fn(),
loadSourceConfiguration: jest.fn(),
loadSourceFailureMessage: undefined,
loadSourceStatus: jest.fn(),
sourceConfiguration: undefined,
sourceId,
sourceStatus: undefined,
updateSourceConfiguration: jest.fn(),
});
export const createLoadingUseLogSourceMock: CreateUseLogSource = ({
sourceId = defaultSourceId,
} = {}) => (args) => ({
...createUninitializedUseLogSourceMock({ sourceId })(args),
isLoading: true,
isLoadingSourceConfiguration: true,
isLoadingSourceStatus: true,
});
export const createLoadedUseLogSourceMock: CreateUseLogSource = ({
sourceId = defaultSourceId,
} = {}) => (args) => ({
...createUninitializedUseLogSourceMock({ sourceId })(args),
sourceConfiguration: createBasicSourceConfiguration(sourceId),
sourceStatus: {
logIndexFields: [],
logIndexStatus: 'available',
},
});
export const createBasicSourceConfiguration = (sourceId: string): LogSourceConfiguration => ({
id: sourceId,
origin: 'stored',
configuration: {
description: `description for ${sourceId}`,
logAlias: 'LOG_INDICES',
logColumns: [],
fields: {
container: 'CONTAINER_FIELD',
host: 'HOST_FIELD',
pod: 'POD_FIELD',
tiebreaker: 'TIEBREAKER_FIELD',
timestamp: 'TIMESTAMP_FIELD',
},
name: sourceId,
},
});
export const createAvailableSourceStatus = (logIndexFields = []): LogSourceStatus => ({
logIndexFields,
logIndexStatus: 'available',
});

View file

@ -5,13 +5,14 @@
*/
import createContainer from 'constate';
import { useState, useMemo, useCallback } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useMountedState } from 'react-use';
import { HttpSetup } from 'src/core/public';
import {
LogSourceConfiguration,
LogSourceStatus,
LogSourceConfigurationPropertiesPatch,
LogSourceConfigurationProperties,
LogSourceConfigurationPropertiesPatch,
LogSourceStatus,
} from '../../../../common/http_api/log_sources';
import { useTrackedPromise } from '../../../utils/use_tracked_promise';
import { callFetchLogSourceConfigurationAPI } from './api/fetch_log_source_configuration';
@ -32,6 +33,7 @@ export const useLogSource = ({
sourceId: string;
fetch: HttpSetup['fetch'];
}) => {
const getIsMounted = useMountedState();
const [sourceConfiguration, setSourceConfiguration] = useState<
LogSourceConfiguration | undefined
>(undefined);
@ -45,6 +47,10 @@ export const useLogSource = ({
return await callFetchLogSourceConfigurationAPI(sourceId, fetch);
},
onResolve: ({ data }) => {
if (!getIsMounted()) {
return;
}
setSourceConfiguration(data);
},
},
@ -58,6 +64,10 @@ export const useLogSource = ({
return await callPatchLogSourceConfigurationAPI(sourceId, patchedProperties, fetch);
},
onResolve: ({ data }) => {
if (!getIsMounted()) {
return;
}
setSourceConfiguration(data);
loadSourceStatus();
},
@ -72,6 +82,10 @@ export const useLogSource = ({
return await callFetchLogSourceStatusAPI(sourceId, fetch);
},
onResolve: ({ data }) => {
if (!getIsMounted()) {
return;
}
setSourceStatus(data);
},
},

View file

@ -0,0 +1,326 @@
/*
* 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.
*/
/*
* 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 { render } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Route, Router, Switch } from 'react-router-dom';
import { httpServiceMock } from 'src/core/public/mocks';
// import { HttpSetup } from 'src/core/public';
import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
import { useLogSource } from '../../containers/logs/log_source';
import {
createLoadedUseLogSourceMock,
createLoadingUseLogSourceMock,
} from '../../containers/logs/log_source/log_source.mock';
import { LinkToLogsPage } from './link_to_logs';
jest.mock('../../containers/logs/log_source');
const useLogSourceMock = useLogSource as jest.MockedFunction<typeof useLogSource>;
const renderRoutes = (routes: React.ReactElement) => {
const history = createMemoryHistory();
const services = {
http: httpServiceMock.createStartContract(),
};
const renderResult = render(
<KibanaContextProvider services={services}>
<Router history={history}>{routes}</Router>
</KibanaContextProvider>
);
return {
...renderResult,
history,
services,
};
};
describe('LinkToLogsPage component', () => {
beforeEach(() => {
useLogSourceMock.mockImplementation(createLoadedUseLogSourceMock());
});
afterEach(() => {
useLogSourceMock.mockRestore();
});
describe('default route', () => {
it('redirects to the stream at a given time filtered for a user-defined criterion', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'FILTER_FIELD:FILTER_VALUE',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toMatchInlineSnapshot(
`"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"`
);
});
it('redirects to the stream using a specific source id', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/OTHER_SOURCE');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(`"(expression:'',kind:kuery)"`);
expect(searchParams.get('logPosition')).toEqual(null);
});
});
describe('logs route', () => {
it('redirects to the stream at a given time filtered for a user-defined criterion', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/logs?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'FILTER_FIELD:FILTER_VALUE',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toMatchInlineSnapshot(
`"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"`
);
});
it('redirects to the stream using a specific source id', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/OTHER_SOURCE/logs');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(`"(expression:'',kind:kuery)"`);
expect(searchParams.get('logPosition')).toEqual(null);
});
});
describe('host-logs route', () => {
it('redirects to the stream filtered for a host', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/host-logs/HOST_NAME');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'HOST_FIELD: HOST_NAME',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toEqual(null);
});
it('redirects to the stream at a given time filtered for a host and a user-defined criterion', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push(
'/link-to/host-logs/HOST_NAME?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE'
);
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'(HOST_FIELD: HOST_NAME) and (FILTER_FIELD:FILTER_VALUE)',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toMatchInlineSnapshot(
`"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"`
);
});
it('redirects to the stream filtered for a host using a specific source id', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/OTHER_SOURCE/host-logs/HOST_NAME');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'HOST_FIELD: HOST_NAME',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toEqual(null);
});
it('renders a loading page while loading the source configuration', () => {
useLogSourceMock.mockImplementation(createLoadingUseLogSourceMock());
const { history, queryByTestId } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/host-logs/HOST_NAME');
expect(queryByTestId('nodeLoadingPage-host')).not.toBeEmpty();
});
});
describe('container-logs route', () => {
it('redirects to the stream filtered for a container', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/container-logs/CONTAINER_ID');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'CONTAINER_FIELD: CONTAINER_ID',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toEqual(null);
});
it('redirects to the stream at a given time filtered for a container and a user-defined criterion', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push(
'/link-to/container-logs/CONTAINER_ID?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE'
);
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'(CONTAINER_FIELD: CONTAINER_ID) and (FILTER_FIELD:FILTER_VALUE)',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toMatchInlineSnapshot(
`"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"`
);
});
it('renders a loading page while loading the source configuration', () => {
useLogSourceMock.mockImplementation(createLoadingUseLogSourceMock());
const { history, queryByTestId } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/container-logs/CONTAINER_ID');
expect(queryByTestId('nodeLoadingPage-container')).not.toBeEmpty();
});
});
describe('pod-logs route', () => {
it('redirects to the stream filtered for a pod', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/pod-logs/POD_UID');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'POD_FIELD: POD_UID',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toEqual(null);
});
it('redirects to the stream at a given time filtered for a pod and a user-defined criterion', () => {
const { history } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/pod-logs/POD_UID?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE');
expect(history.location.pathname).toEqual('/stream');
const searchParams = new URLSearchParams(history.location.search);
expect(searchParams.get('sourceId')).toEqual('default');
expect(searchParams.get('logFilter')).toMatchInlineSnapshot(
`"(expression:'(POD_FIELD: POD_UID) and (FILTER_FIELD:FILTER_VALUE)',kind:kuery)"`
);
expect(searchParams.get('logPosition')).toMatchInlineSnapshot(
`"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"`
);
});
it('renders a loading page while loading the source configuration', () => {
useLogSourceMock.mockImplementation(createLoadingUseLogSourceMock());
const { history, queryByTestId } = renderRoutes(
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
</Switch>
);
history.push('/link-to/pod-logs/POD_UID');
expect(queryByTestId('nodeLoadingPage-pod')).not.toBeEmpty();
});
});
});

View file

@ -27,6 +27,7 @@ export const LinkToLogsPage: React.FC<LinkToPageProps> = (props) => {
path={`${props.match.url}/:sourceId?/:nodeType(${ITEM_TYPES})-logs/:nodeId`}
component={RedirectToNodeLogs}
/>
<Route path={`${props.match.url}/:sourceId?/logs`} component={RedirectToLogs} />
<Route path={`${props.match.url}/:sourceId?`} component={RedirectToLogs} />
<Redirect to="/" />
</Switch>

View file

@ -1,119 +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 { createLocation } from 'history';
import React from 'react';
import { matchPath } from 'react-router-dom';
import { shallow } from 'enzyme';
import { RedirectToNodeLogs } from './redirect_to_node_logs';
jest.mock('../../containers/source/source', () => ({
useSource: ({ sourceId }: { sourceId: string }) => ({
sourceId,
source: {
configuration: {
fields: {
container: 'CONTAINER_FIELD',
host: 'HOST_FIELD',
pod: 'POD_FIELD',
},
},
},
isLoading: sourceId === 'perpetuallyLoading',
}),
}));
describe('RedirectToNodeLogs component', () => {
it('renders a redirect with the correct host filter', () => {
const component = shallow(
<RedirectToNodeLogs {...createRouteComponentProps('/host-logs/HOST_NAME')} />
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?sourceId=default&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
/>
`);
});
it('renders a redirect with the correct container filter', () => {
const component = shallow(
<RedirectToNodeLogs {...createRouteComponentProps('/container-logs/CONTAINER_ID')} />
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?sourceId=default&logFilter=(expression:'CONTAINER_FIELD:%20CONTAINER_ID',kind:kuery)"
/>
`);
});
it('renders a redirect with the correct pod filter', () => {
const component = shallow(
<RedirectToNodeLogs {...createRouteComponentProps('/pod-logs/POD_ID')} />
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?sourceId=default&logFilter=(expression:'POD_FIELD:%20POD_ID',kind:kuery)"
/>
`);
});
it('renders a redirect with the correct position', () => {
const component = shallow(
<RedirectToNodeLogs
{...createRouteComponentProps('/host-logs/HOST_NAME?time=1550671089404')}
/>
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?logPosition=(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)&sourceId=default&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
/>
`);
});
it('renders a redirect with the correct user-defined filter', () => {
const component = shallow(
<RedirectToNodeLogs
{...createRouteComponentProps(
'/host-logs/HOST_NAME?time=1550671089404&filter=FILTER_FIELD:FILTER_VALUE'
)}
/>
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?logPosition=(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)&sourceId=default&logFilter=(expression:'(HOST_FIELD:%20HOST_NAME)%20and%20(FILTER_FIELD:FILTER_VALUE)',kind:kuery)"
/>
`);
});
it('renders a redirect with the correct custom source id', () => {
const component = shallow(
<RedirectToNodeLogs
{...createRouteComponentProps('/SOME-OTHER-SOURCE/host-logs/HOST_NAME')}
/>
);
expect(component).toMatchInlineSnapshot(`
<Redirect
to="/stream?sourceId=SOME-OTHER-SOURCE&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
/>
`);
});
});
const createRouteComponentProps = (path: string) => {
const location = createLocation(path);
return {
match: matchPath(location.pathname, { path: '/:sourceId?/:nodeType-logs/:nodeId' }) as any,
history: null as any,
location,
};
};

View file

@ -5,21 +5,20 @@
*/
import { i18n } from '@kbn/i18n';
import { flowRight } from 'lodash';
import flowRight from 'lodash/flowRight';
import React from 'react';
import { Redirect, RouteComponentProps } from 'react-router-dom';
import { useMount } from 'react-use';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { findInventoryFields } from '../../../common/inventory_models';
import { InventoryItemType } from '../../../common/inventory_models/types';
import { LoadingPage } from '../../components/loading_page';
import { replaceLogFilterInQueryString } from '../../containers/logs/log_filter';
import { replaceLogPositionInQueryString } from '../../containers/logs/log_position';
import { useLogSource } from '../../containers/logs/log_source';
import { replaceSourceIdInQueryString } from '../../containers/source_id';
import { SourceConfigurationFields } from '../../graphql/types';
import { getFilterFromLocation, getTimeFromLocation } from './query_params';
import { useSource } from '../../containers/source/source';
import { findInventoryFields } from '../../../common/inventory_models';
import { InventoryItemType } from '../../../common/inventory_models/types';
import { LinkDescriptor } from '../../hooks/use_link_props';
import { getFilterFromLocation, getTimeFromLocation } from './query_params';
type RedirectToNodeLogsType = RouteComponentProps<{
nodeId: string;
@ -27,26 +26,27 @@ type RedirectToNodeLogsType = RouteComponentProps<{
sourceId?: string;
}>;
const getFieldByNodeType = (
nodeType: InventoryItemType,
fields: SourceConfigurationFields.Fields
) => {
const inventoryFields = findInventoryFields(nodeType, fields);
return inventoryFields.id;
};
export const RedirectToNodeLogs = ({
match: {
params: { nodeId, nodeType, sourceId = 'default' },
},
location,
}: RedirectToNodeLogsType) => {
const { source, isLoading } = useSource({ sourceId });
const configuration = source && source.configuration;
const { services } = useKibana();
const { isLoading, loadSourceConfiguration, sourceConfiguration } = useLogSource({
fetch: services.http.fetch,
sourceId,
});
const fields = sourceConfiguration?.configuration.fields;
useMount(() => {
loadSourceConfiguration();
});
if (isLoading) {
return (
<LoadingPage
data-test-subj={`nodeLoadingPage-${nodeType}`}
message={i18n.translate('xpack.infra.redirectToNodeLogs.loadingNodeLogsMessage', {
defaultMessage: 'Loading {nodeType} logs',
values: {
@ -55,13 +55,11 @@ export const RedirectToNodeLogs = ({
})}
/>
);
}
if (!configuration) {
} else if (fields == null) {
return null;
}
const nodeFilter = `${getFieldByNodeType(nodeType, configuration.fields)}: ${nodeId}`;
const nodeFilter = `${findInventoryFields(nodeType, fields).id}: ${nodeId}`;
const userFilter = getFilterFromLocation(location);
const filter = userFilter ? `(${nodeFilter}) and (${userFilter})` : nodeFilter;