Skip to content

Commit

Permalink
Ensure alerts management page can access and load source config / sta…
Browse files Browse the repository at this point in the history
…tus data
  • Loading branch information
Kerry350 committed Apr 28, 2020
1 parent 2fba7ed commit c2c2d95
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export const AlertFlyout = (props: Props) => {
{triggersActionsUI && (
<AlertsContextProvider
value={{
metadata: {},
metadata: {
isInternal: true,
},
toastNotifications: services.notifications?.toasts,
http: services.http,
docLinks: services.docLinks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

import React, { useCallback, useMemo, useEffect, useState } from 'react';
import { EuiButtonEmpty } from '@elastic/eui';
import { useMount } from 'react-use';
import { FormattedMessage } from '@kbn/i18n/react';
import {
ForLastExpression,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../../../../triggers_actions_ui/public/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context';
import { useSource } from '../../../../containers/source';
import {
LogDocumentCountAlertParams,
Expand All @@ -21,18 +24,25 @@ import {
} from '../../../../../common/alerting/logs/types';
import { DocumentCount } from './document_count';
import { Criteria } from './criteria';
import { useSourceId } from '../../../../containers/source_id';
import { LogSourceProvider, useLogSourceContext } from '../../../../containers/logs/log_source';

export interface ExpressionCriteria {
field?: string;
comparator?: Comparator;
value?: string | number;
}

interface LogsContextMeta {
isInternal?: boolean;
}

interface Props {
errors: IErrorObject;
alertParams: Partial<LogDocumentCountAlertParams>;
setAlertParams(key: string, value: any): void;
setAlertProperty(key: string, value: any): void;
alertsContext: AlertsContextValue<LogsContextMeta>;
}

const DEFAULT_CRITERIA = { field: 'log.level', comparator: Comparator.EQ, value: 'error' };
Expand All @@ -48,32 +58,68 @@ const DEFAULT_EXPRESSION = {
};

export const ExpressionEditor: React.FC<Props> = props => {
const isInternal = props.alertsContext.metadata?.isInternal;
const [sourceId] = useSourceId();

return (
<>
{isInternal ? (
<SourceConfigStatus {...props}>
<Editor {...props} />
</SourceConfigStatus>
) : (
<LogSourceProvider sourceId={sourceId} fetch={props.alertsContext.http.fetch}>
<SourceConfigStatus {...props}>
<Editor {...props} />
</SourceConfigStatus>
</LogSourceProvider>
)}
</>
);
};

export const SourceConfigStatus: React.FC<Props> = props => {
const { initialize, isLoading, isUninitialized, hasFailedLoadingSource } = useLogSourceContext();
const { children } = props;

useMount(() => {
initialize();
});

return (
<>
{isLoading || isUninitialized
? 'Loading source data'
: hasFailedLoadingSource
? 'Error loading source data'
: children}
</>
);
};

export const Editor: React.FC<Props> = props => {
const { setAlertParams, alertParams, errors } = props;
const { createDerivedIndexPattern } = useSource({ sourceId: 'default' });
const [timeSize, setTimeSize] = useState<number | undefined>(1);
const [timeUnit, setTimeUnit] = useState<TimeUnit>('m');
const [hasSetDefaults, setHasSetDefaults] = useState<boolean>(false);
const derivedIndexPattern = useMemo(() => createDerivedIndexPattern('logs'), [
createDerivedIndexPattern,
]);
const { sourceStatus } = useLogSourceContext();

useMount(() => {
for (const [key, value] of Object.entries(DEFAULT_EXPRESSION)) {
setAlertParams(key, value);
setHasSetDefaults(true);
}
});

const supportedFields = useMemo(() => {
if (derivedIndexPattern?.fields) {
return derivedIndexPattern.fields.filter(field => {
if (sourceStatus?.logIndexFields) {
return sourceStatus.logIndexFields.filter(field => {
return (field.type === 'string' || field.type === 'number') && field.searchable;
});
} else {
return [];
}
}, [derivedIndexPattern]);

// Set the default expression (disables exhaustive-deps as we only want to run this once on mount)
useEffect(() => {
for (const [key, value] of Object.entries(DEFAULT_EXPRESSION)) {
setAlertParams(key, value);
setHasSetDefaults(true);
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps
}, [sourceStatus]);

const updateCount = useCallback(
countParams => {
Expand Down Expand Up @@ -127,7 +173,7 @@ export const ExpressionEditor: React.FC<Props> = props => {
);

// Wait until field info has loaded
if (supportedFields.length === 0) return null;
// if (supportedFields.length === 0) return null;
// Wait until the alert param defaults have been set
if (!hasSetDefaults) return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HttpSetup } from 'src/core/public';
import {
getLogSourceConfigurationPath,
getLogSourceConfigurationSuccessResponsePayloadRT,
} from '../../../../../common/http_api/log_sources';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { npStart } from '../../../../legacy_singletons';

export const callFetchLogSourceConfigurationAPI = async (sourceId: string) => {
const response = await npStart.http.fetch(getLogSourceConfigurationPath(sourceId), {
export const callFetchLogSourceConfigurationAPI = async (
sourceId: string,
fetch: HttpSetup['fetch']
) => {
const response = await fetch(getLogSourceConfigurationPath(sourceId), {
method: 'GET',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HttpSetup } from 'src/core/public';
import {
getLogSourceStatusPath,
getLogSourceStatusSuccessResponsePayloadRT,
} from '../../../../../common/http_api/log_sources';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { npStart } from '../../../../legacy_singletons';

export const callFetchLogSourceStatusAPI = async (sourceId: string) => {
const response = await npStart.http.fetch(getLogSourceStatusPath(sourceId), {
export const callFetchLogSourceStatusAPI = async (sourceId: string, fetch: HttpSetup['fetch']) => {
const response = await fetch(getLogSourceStatusPath(sourceId), {
method: 'GET',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HttpSetup } from 'src/core/public';
import {
getLogSourceConfigurationPath,
patchLogSourceConfigurationSuccessResponsePayloadRT,
patchLogSourceConfigurationRequestBodyRT,
LogSourceConfigurationPropertiesPatch,
} from '../../../../../common/http_api/log_sources';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { npStart } from '../../../../legacy_singletons';

export const callPatchLogSourceConfigurationAPI = async (
sourceId: string,
patchedProperties: LogSourceConfigurationPropertiesPatch
patchedProperties: LogSourceConfigurationPropertiesPatch,
fetch: HttpSetup['fetch']
) => {
const response = await npStart.http.fetch(getLogSourceConfigurationPath(sourceId), {
const response = await fetch(getLogSourceConfigurationPath(sourceId), {
method: 'PATCH',
body: JSON.stringify(
patchLogSourceConfigurationRequestBodyRT.encode({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import createContainer from 'constate';
import { useState, useMemo, useCallback } from 'react';
import { HttpSetup } from 'src/core/public';
import {
LogSourceConfiguration,
LogSourceStatus,
Expand All @@ -23,8 +24,15 @@ export {
LogSourceConfigurationPropertiesPatch,
LogSourceStatus,
};

export const useLogSource = ({ sourceId }: { sourceId: string }) => {
import { npStart } from '../../../../legacy_singletons';

export const useLogSource = ({
sourceId,
fetch,
}: {
sourceId: string;
fetch: HttpSetup['fetch'];
}) => {
const [sourceConfiguration, setSourceConfiguration] = useState<
LogSourceConfiguration | undefined
>(undefined);
Expand All @@ -35,40 +43,40 @@ export const useLogSource = ({ sourceId }: { sourceId: string }) => {
{
cancelPreviousOn: 'resolution',
createPromise: async () => {
return await callFetchLogSourceConfigurationAPI(sourceId);
return await callFetchLogSourceConfigurationAPI(sourceId, fetch);
},
onResolve: ({ data }) => {
setSourceConfiguration(data);
},
},
[sourceId]
[sourceId, fetch]
);

const [updateSourceConfigurationRequest, updateSourceConfiguration] = useTrackedPromise(
{
cancelPreviousOn: 'resolution',
createPromise: async (patchedProperties: LogSourceConfigurationPropertiesPatch) => {
return await callPatchLogSourceConfigurationAPI(sourceId, patchedProperties);
return await callPatchLogSourceConfigurationAPI(sourceId, patchedProperties, fetch);
},
onResolve: ({ data }) => {
setSourceConfiguration(data);
loadSourceStatus();
},
},
[sourceId]
[sourceId, fetch]
);

const [loadSourceStatusRequest, loadSourceStatus] = useTrackedPromise(
{
cancelPreviousOn: 'resolution',
createPromise: async () => {
return await callFetchLogSourceStatusAPI(sourceId);
return await callFetchLogSourceStatusAPI(sourceId, fetch);
},
onResolve: ({ data }) => {
setSourceStatus(data);
},
},
[sourceId]
[sourceId, fetch]
);

const logIndicesExist = useMemo(() => (sourceStatus?.logIndexNames?.length ?? 0) > 0, [
Expand Down
5 changes: 3 additions & 2 deletions x-pack/plugins/infra/public/pages/logs/page_providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
*/

import React from 'react';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { LogAnalysisCapabilitiesProvider } from '../../containers/logs/log_analysis';
import { LogSourceProvider } from '../../containers/logs/log_source';
// import { SourceProvider } from '../../containers/source';
import { useSourceId } from '../../containers/source_id';

export const LogsPageProviders: React.FunctionComponent = ({ children }) => {
const [sourceId] = useSourceId();

const { services } = useKibana();
return (
<LogSourceProvider sourceId={sourceId}>
<LogSourceProvider sourceId={sourceId} fetch={services.http.fetch}>
<LogAnalysisCapabilitiesProvider>{children}</LogAnalysisCapabilitiesProvider>
</LogSourceProvider>
);
Expand Down

0 comments on commit c2c2d95

Please sign in to comment.