[Asset management] Osquery app bug squashing (#102406)

* only display healthy agents to query

* updated toasts to clear on update

* null checking aggBuckets

* properly display expired actions

* clear the error toasts on success

* review comments

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Bryan Clement 2021-06-24 09:31:57 -07:00 committed by GitHub
parent dd20b8adb6
commit 5e898734d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 186 additions and 112 deletions

View file

@ -36,6 +36,7 @@ const StyledEuiCard = styled(EuiCard)`
interface ActionResultsSummaryProps {
actionId: string;
expirationDate: Date;
agentIds?: string[];
isLive?: boolean;
}
@ -48,6 +49,7 @@ const renderErrorMessage = (error: string) => (
const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
actionId,
expirationDate,
agentIds,
isLive,
}) => {
@ -56,6 +58,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
const [pageIndex, setPageIndex] = useState(0);
// @ts-expect-error update types
const [pageSize, setPageSize] = useState(50);
const expired = useMemo(() => expirationDate < new Date(), [expirationDate]);
const {
// @ts-expect-error update types
data: { aggregations, edges },
@ -66,7 +69,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
limit: pageSize,
direction: Direction.asc,
sortField: '@timestamp',
isLive,
isLive: !expired && isLive,
});
const { data: logsResults } = useAllResults({
@ -79,7 +82,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
direction: Direction.asc,
},
],
isLive,
isLive: !expired && isLive,
});
const notRespondedCount = useMemo(() => {
@ -108,9 +111,13 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
description: aggregations.successful,
},
{
title: i18n.translate('xpack.osquery.liveQueryActionResults.summary.pendingLabelText', {
defaultMessage: 'Not yet responded',
}),
title: expired
? i18n.translate('xpack.osquery.liveQueryActionResults.summary.expiredLabelText', {
defaultMessage: 'Expired',
})
: i18n.translate('xpack.osquery.liveQueryActionResults.summary.pendingLabelText', {
defaultMessage: 'Not yet responded',
}),
description: notRespondedCount,
},
{
@ -124,7 +131,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
),
},
],
[agentIds, aggregations.failed, aggregations.successful, notRespondedCount]
[agentIds, aggregations.failed, aggregations.successful, notRespondedCount, expired]
);
const renderAgentIdColumn = useCallback(
@ -158,23 +165,30 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
[logsResults]
);
const renderStatusColumn = useCallback((_, item) => {
if (!item.fields.completed_at) {
return i18n.translate('xpack.osquery.liveQueryActionResults.table.pendingStatusText', {
defaultMessage: 'pending',
});
}
const renderStatusColumn = useCallback(
(_, item) => {
if (!item.fields.completed_at) {
return expired
? i18n.translate('xpack.osquery.liveQueryActionResults.table.expiredStatusText', {
defaultMessage: 'expired',
})
: i18n.translate('xpack.osquery.liveQueryActionResults.table.pendingStatusText', {
defaultMessage: 'pending',
});
}
if (item.fields['error.keyword']) {
return i18n.translate('xpack.osquery.liveQueryActionResults.table.errorStatusText', {
defaultMessage: 'error',
});
}
if (item.fields['error.keyword']) {
return i18n.translate('xpack.osquery.liveQueryActionResults.table.errorStatusText', {
defaultMessage: 'error',
});
}
return i18n.translate('xpack.osquery.liveQueryActionResults.table.successStatusText', {
defaultMessage: 'success',
});
}, []);
return i18n.translate('xpack.osquery.liveQueryActionResults.table.successStatusText', {
defaultMessage: 'success',
});
},
[expired]
);
const columns = useMemo(
() => [
@ -227,7 +241,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<StyledEuiCard title="" description="" textAlign="left">
{notRespondedCount ? <EuiProgress size="xs" position="absolute" /> : null}
{!expired && notRespondedCount ? <EuiProgress size="xs" position="absolute" /> : null}
<EuiDescriptionList
compressed
textStyle="reverse"

View file

@ -23,6 +23,7 @@ import { ESTermQuery } from '../../common/typed_json';
import { queryClient } from '../query_client';
import { generateTablePaginationOptions, getInspectResponse, InspectResponse } from './helpers';
import { useErrorToast } from '../common/hooks/use_error_toast';
export interface ResultsArgs {
results: ResultEdges;
@ -56,10 +57,8 @@ export const useActionResults = ({
skip = false,
isLive = false,
}: UseActionResults) => {
const {
data,
notifications: { toasts },
} = useKibana().services;
const { data } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
['actionResults', { actionId }],
@ -103,9 +102,9 @@ export const useActionResults = ({
aggregations: {
totalResponded,
// @ts-expect-error update types
successful: aggsBuckets.find((bucket) => bucket.key === 'success')?.doc_count ?? 0,
successful: aggsBuckets?.find((bucket) => bucket.key === 'success')?.doc_count ?? 0,
// @ts-expect-error update types
failed: aggsBuckets.find((bucket) => bucket.key === 'error')?.doc_count ?? 0,
failed: aggsBuckets?.find((bucket) => bucket.key === 'error')?.doc_count ?? 0,
},
inspect: getInspectResponse(responseData, {} as InspectResponse),
};
@ -124,8 +123,9 @@ export const useActionResults = ({
refetchInterval: isLive ? 1000 : false,
keepPreviousData: true,
enabled: !skip && !!agentIds?.length,
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.action_results.fetchError', {
defaultMessage: 'Error while fetching action results',
}),

View file

@ -18,6 +18,7 @@ import {
import { ESTermQuery } from '../../common/typed_json';
import { getInspectResponse, InspectResponse } from './helpers';
import { useErrorToast } from '../common/hooks/use_error_toast';
export interface ActionDetailsArgs {
actionDetails: Record<string, string>;
@ -33,10 +34,8 @@ interface UseActionDetails {
}
export const useActionDetails = ({ actionId, filterQuery, skip = false }: UseActionDetails) => {
const {
data,
notifications: { toasts },
} = useKibana().services;
const { data } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
['actionDetails', { actionId, filterQuery }],
@ -61,8 +60,9 @@ export const useActionDetails = ({ actionId, filterQuery, skip = false }: UseAct
},
{
enabled: !skip,
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.action_details.fetchError', {
defaultMessage: 'Error while fetching action details',
}),

View file

@ -21,6 +21,7 @@ import {
import { ESTermQuery } from '../../common/typed_json';
import { generateTablePaginationOptions, getInspectResponse, InspectResponse } from './helpers';
import { useErrorToast } from '../common/hooks/use_error_toast';
export interface ActionsArgs {
actions: ActionEdges;
@ -48,10 +49,8 @@ export const useAllActions = ({
filterQuery,
skip = false,
}: UseAllActions) => {
const {
data,
notifications: { toasts },
} = useKibana().services;
const { data } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
['actions', { activePage, direction, limit, sortField }],
@ -82,8 +81,9 @@ export const useAllActions = ({
{
keepPreviousData: true,
enabled: !skip,
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.all_actions.fetchError', {
defaultMessage: 'Error while fetching actions',
}),

View file

@ -14,12 +14,11 @@ import {
GetAgentPoliciesResponse,
GetAgentPoliciesResponseItem,
} from '../../../fleet/common';
import { useErrorToast } from '../common/hooks/use_error_toast';
export const useAgentPolicies = () => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery<GetAgentPoliciesResponse, unknown, GetAgentPoliciesResponseItem[]>(
['agentPolicies'],
@ -34,8 +33,9 @@ export const useAgentPolicies = () => {
placeholderData: [],
keepPreviousData: true,
select: (response) => response.items,
onSuccess: () => setErrorToast(),
onError: (error) =>
toasts.addError(error as Error, {
setErrorToast(error as Error, {
title: i18n.translate('xpack.osquery.agent_policies.fetchError', {
defaultMessage: 'Error while fetching agent policies',
}),

View file

@ -10,6 +10,7 @@ import { useQuery } from 'react-query';
import { i18n } from '@kbn/i18n';
import { useKibana } from '../common/lib/kibana';
import { agentPolicyRouteService } from '../../../fleet/common';
import { useErrorToast } from '../common/hooks/use_error_toast';
interface UseAgentPolicy {
policyId: string;
@ -17,10 +18,8 @@ interface UseAgentPolicy {
}
export const useAgentPolicy = ({ policyId, skip }: UseAgentPolicy) => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
['agentPolicy', { policyId }],
@ -29,8 +28,9 @@ export const useAgentPolicy = ({ policyId, skip }: UseAgentPolicy) => {
enabled: !skip,
keepPreviousData: true,
select: (response) => response.item,
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.agent_policy_details.fetchError', {
defaultMessage: 'Error while fetching agent policy details',
}),

View file

@ -18,6 +18,7 @@ import {
import { generateTablePaginationOptions, processAggregations } from './helpers';
import { Overlap, Group } from './types';
import { useErrorToast } from '../common/hooks/use_error_toast';
interface UseAgentGroups {
osqueryPolicies: string[];
@ -25,10 +26,8 @@ interface UseAgentGroups {
}
export const useAgentGroups = ({ osqueryPolicies, osqueryPoliciesLoading }: UseAgentGroups) => {
const {
data,
notifications: { toasts },
} = useKibana().services;
const { data } = useKibana().services;
const setErrorToast = useErrorToast();
const { agentPoliciesLoading, agentPolicyById } = useAgentPolicies(osqueryPolicies);
const [platforms, setPlatforms] = useState<Group[]>([]);
@ -100,8 +99,9 @@ export const useAgentGroups = ({ osqueryPolicies, osqueryPoliciesLoading }: UseA
},
{
enabled: !osqueryPoliciesLoading && !agentPoliciesLoading,
onSuccess: () => setErrorToast(),
onError: (error) =>
toasts.addError(error as Error, {
setErrorToast(error as Error, {
title: i18n.translate('xpack.osquery.agent_groups.fetchError', {
defaultMessage: 'Error while fetching agent groups',
}),

View file

@ -10,20 +10,20 @@ import { useQueries, UseQueryResult } from 'react-query';
import { i18n } from '@kbn/i18n';
import { useKibana } from '../common/lib/kibana';
import { agentPolicyRouteService, GetOneAgentPolicyResponse } from '../../../fleet/common';
import { useErrorToast } from '../common/hooks/use_error_toast';
export const useAgentPolicies = (policyIds: string[] = []) => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
const agentResponse = useQueries(
policyIds.map((policyId) => ({
queryKey: ['agentPolicy', policyId],
queryFn: () => http.get(agentPolicyRouteService.getInfoPath(policyId)),
enabled: policyIds.length > 0,
onSuccess: () => setErrorToast(),
onError: (error) =>
toasts.addError(error as Error, {
setErrorToast(error as Error, {
title: i18n.translate('xpack.osquery.action_policy_details.fetchError', {
defaultMessage: 'Error while fetching policy details',
}),

View file

@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
import { useQuery } from 'react-query';
import { GetAgentStatusResponse, agentRouteService } from '../../../fleet/common';
import { useErrorToast } from '../common/hooks/use_error_toast';
import { useKibana } from '../common/lib/kibana';
interface UseAgentStatus {
@ -17,10 +18,8 @@ interface UseAgentStatus {
}
export const useAgentStatus = ({ policyId, skip }: UseAgentStatus) => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery<GetAgentStatusResponse, unknown, GetAgentStatusResponse['results']>(
['agentStatus', policyId],
@ -38,8 +37,9 @@ export const useAgentStatus = ({ policyId, skip }: UseAgentStatus) => {
{
enabled: !skip,
select: (response) => response.results,
onSuccess: () => setErrorToast(),
onError: (error) =>
toasts.addError(error as Error, {
setErrorToast(error as Error, {
title: i18n.translate('xpack.osquery.agent_status.fetchError', {
defaultMessage: 'Error while fetching agent status',
}),

View file

@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
import { useQuery } from 'react-query';
import { GetAgentsResponse, agentRouteService } from '../../../fleet/common';
import { useErrorToast } from '../common/hooks/use_error_toast';
import { useKibana } from '../common/lib/kibana';
interface UseAllAgents {
@ -28,36 +29,30 @@ export const useAllAgents = (
opts: RequestOptions = { perPage: 9000 }
) => {
const { perPage } = opts;
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
const { isLoading: agentsLoading, data: agentData } = useQuery<GetAgentsResponse>(
['agents', osqueryPolicies, searchValue, perPage],
() => {
const kueryFragments: string[] = [];
if (osqueryPolicies.length) {
kueryFragments.push(`${osqueryPolicies.map((p) => `policy_id:${p}`).join(' or ')}`);
}
const policyFragment = osqueryPolicies.map((p) => `policy_id:${p}`).join(' or ');
let kuery = `last_checkin_status: online and (${policyFragment})`;
if (searchValue) {
kueryFragments.push(
`local_metadata.host.hostname:*${searchValue}* or local_metadata.elastic.agent.id:*${searchValue}*`
);
kuery += `and (local_metadata.host.hostname:*${searchValue}* or local_metadata.elastic.agent.id:*${searchValue}*)`;
}
return http.get(agentRouteService.getListPath(), {
query: {
kuery: kueryFragments.map((frag) => `(${frag})`).join(' and '),
kuery,
perPage,
showInactive: true,
},
});
},
{
enabled: !osqueryPoliciesLoading,
enabled: !osqueryPoliciesLoading && osqueryPolicies.length > 0,
onSuccess: () => setErrorToast(),
onError: (error) =>
toasts.addError(error as Error, {
setErrorToast(error as Error, {
title: i18n.translate('xpack.osquery.agents.fetchError', {
defaultMessage: 'Error while fetching agents',
}),

View file

@ -12,12 +12,11 @@ import { i18n } from '@kbn/i18n';
import { useKibana } from '../common/lib/kibana';
import { packagePolicyRouteService, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../fleet/common';
import { OSQUERY_INTEGRATION_NAME } from '../../common';
import { useErrorToast } from '../common/hooks/use_error_toast';
export const useOsqueryPolicies = () => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
const { isLoading: osqueryPoliciesLoading, data: osqueryPolicies = [] } = useQuery(
['osqueryPolicies'],
@ -30,8 +29,9 @@ export const useOsqueryPolicies = () => {
{
select: (response) =>
uniq<string>(response.items.map((p: { policy_id: string }) => p.policy_id)),
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.osquery_policies.fetchError', {
defaultMessage: 'Error while fetching osquery policies',
}),

View file

@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { ErrorToastOptions, Toast } from 'kibana/public';
import { useState } from 'react';
import { useKibana } from '../../common/lib/kibana';
export const useErrorToast = () => {
const [errorToast, setErrorToast] = useState<Toast>();
const {
notifications: { toasts },
} = useKibana().services;
return (error?: unknown, opts?: ErrorToastOptions) => {
if (errorToast) {
toasts.remove(errorToast);
}
if (error) {
// @ts-expect-error update types
setErrorToast(toasts.addError(error, opts));
}
};
};

View file

@ -12,12 +12,11 @@ import { useQuery } from 'react-query';
import { GetPackagesResponse, epmRouteService } from '../../../../fleet/common';
import { OSQUERY_INTEGRATION_NAME } from '../../../common';
import { useKibana } from '../lib/kibana';
import { useErrorToast } from './use_error_toast';
export const useOsqueryIntegration = () => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
'integrations',
@ -31,7 +30,7 @@ export const useOsqueryIntegration = () => {
select: ({ response }: GetPackagesResponse) =>
find(['name', OSQUERY_INTEGRATION_NAME], response),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.osquery_integration.fetchError', {
defaultMessage: 'Error while fetching osquery integration',
}),

View file

@ -19,6 +19,7 @@ import { useKibana } from '../../common/lib/kibana';
import { ResultTabs } from '../../queries/edit/tabs';
import { queryFieldValidation } from '../../common/validations';
import { fieldValidators } from '../../shared_imports';
import { useErrorToast } from '../../common/hooks/use_error_toast';
const FORM_ID = 'liveQueryForm';
@ -35,10 +36,9 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
// onSubmit,
onSuccess,
}) => {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { http } = useKibana().services;
const setErrorToast = useErrorToast();
const {
data,
@ -53,14 +53,20 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
body: JSON.stringify(payload),
}),
{
onSuccess,
onSuccess: () => {
setErrorToast();
if (onSuccess) {
onSuccess();
}
},
onError: (error) => {
// @ts-expect-error update types
toasts.addError(error, { title: error.body.error, toastMessage: error.body.message });
setErrorToast(error);
},
}
);
const expirationDate = useMemo(() => new Date(data?.actions[0].expiration), [data?.actions]);
const formSchema = {
query: {
type: FIELD_TYPES.TEXT,
@ -173,7 +179,12 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
defaultMessage: 'Check results',
}),
children: actionId ? (
<ResultTabs actionId={actionId} agentIds={agentIds} isLive={true} />
<ResultTabs
actionId={actionId}
expirationDate={expirationDate}
agentIds={agentIds}
isLive={true}
/>
) : null,
status: resultsStatus,
},
@ -185,6 +196,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
queryComponentProps,
queryStatus,
queryValueProvided,
expirationDate,
resultsStatus,
submit,
]

View file

@ -14,6 +14,7 @@ import { ActionResultsSummary } from '../../action_results/action_results_summar
interface ResultTabsProps {
actionId: string;
agentIds?: string[];
expirationDate: Date;
isLive?: boolean;
startDate?: string;
endDate?: string;
@ -22,6 +23,7 @@ interface ResultTabsProps {
const ResultTabsComponent: React.FC<ResultTabsProps> = ({
actionId,
agentIds,
expirationDate,
endDate,
isLive,
startDate,
@ -34,7 +36,12 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
content: (
<>
<EuiSpacer />
<ActionResultsSummary actionId={actionId} agentIds={agentIds} isLive={isLive} />
<ActionResultsSummary
expirationDate={expirationDate}
actionId={actionId}
agentIds={agentIds}
isLive={isLive}
/>
</>
),
},
@ -55,7 +62,7 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
),
},
],
[actionId, agentIds, endDate, isLive, startDate]
[actionId, agentIds, endDate, isLive, startDate, expirationDate]
);
return (

View file

@ -21,6 +21,7 @@ import {
import { ESTermQuery } from '../../common/typed_json';
import { generateTablePaginationOptions, getInspectResponse, InspectResponse } from './helpers';
import { useErrorToast } from '../common/hooks/use_error_toast';
export interface ResultsArgs {
results: ResultEdges;
@ -50,10 +51,8 @@ export const useAllResults = ({
skip = false,
isLive = false,
}: UseAllResults) => {
const {
data,
notifications: { toasts },
} = useKibana().services;
const { data } = useKibana().services;
const setErrorToast = useErrorToast();
return useQuery(
['allActionResults', { actionId, activePage, limit, sort }],
@ -81,8 +80,9 @@ export const useAllResults = ({
{
refetchInterval: isLive ? 1000 : false,
enabled: !skip,
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
toasts.addError(error, {
setErrorToast(error, {
title: i18n.translate('xpack.osquery.results.fetchError', {
defaultMessage: 'Error while fetching results',
}),

View file

@ -43,6 +43,10 @@ const LiveQueryDetailsPageComponent = () => {
const liveQueryListProps = useRouterNavigate('live_queries');
const { data } = useActionDetails({ actionId });
const expirationDate = useMemo(() => new Date(data?.actionDetails._source.expiration), [
data?.actionDetails,
]);
const expired = useMemo(() => expirationDate < new Date(), [expirationDate]);
const { data: actionResultsData } = useActionResults({
actionId,
activePage: 0,
@ -78,6 +82,18 @@ const LiveQueryDetailsPageComponent = () => {
[liveQueryListProps]
);
const failed = useMemo(() => {
let result = actionResultsData?.aggregations.failed;
if (expired) {
result = '-';
if (data?.actionDetails?.fields?.agents && actionResultsData?.aggregations) {
result =
data.actionDetails.fields.agents.length - actionResultsData.aggregations.successful;
}
}
return result;
}, [expired, actionResultsData?.aggregations, data?.actionDetails?.fields?.agents]);
const RightColumn = useMemo(
() => (
<EuiFlexGroup justifyContent="flexEnd" direction="row">
@ -114,15 +130,13 @@ const LiveQueryDetailsPageComponent = () => {
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription className="eui-textNoWrap">
<EuiTextColor color={actionResultsData?.aggregations.failed ? 'danger' : 'default'}>
{actionResultsData?.aggregations.failed}
</EuiTextColor>
<EuiTextColor color={failed ? 'danger' : 'default'}>{failed}</EuiTextColor>
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>
),
[actionResultsData?.aggregations.failed, data?.actionDetails?.fields?.agents?.length]
[data?.actionDetails?.fields?.agents?.length, failed]
);
return (
@ -133,6 +147,7 @@ const LiveQueryDetailsPageComponent = () => {
<EuiSpacer />
<ResultTabs
actionId={actionId}
expirationDate={expirationDate}
agentIds={data?.actionDetails?.fields?.agents}
startDate={get(data, ['actionDetails', 'fields', '@timestamp', '0'])}
endDate={get(data, 'actionDetails.fields.expiration[0]')}

View file

@ -21,6 +21,7 @@ import { useKibana } from '../common/lib/kibana';
import { useAgentStatus } from '../agents/use_agent_status';
import { useAgentPolicy } from '../agent_policies/use_agent_policy';
import { ConfirmDeployAgentPolicyModal } from './form/confirmation_modal';
import { useErrorToast } from '../common/hooks/use_error_toast';
const StyledEuiLoadingSpinner = styled(EuiLoadingSpinner)`
margin-right: ${({ theme }) => theme.eui.paddingSizes.s};
@ -36,6 +37,7 @@ const ActiveStateSwitchComponent: React.FC<ActiveStateSwitchProps> = ({ item })
http,
notifications: { toasts },
} = useKibana().services;
const setErrorToast = useErrorToast();
const [confirmationModal, setConfirmationModal] = useState(false);
const hideConfirmationModal = useCallback(() => setConfirmationModal(false), []);
@ -51,6 +53,7 @@ const ActiveStateSwitchComponent: React.FC<ActiveStateSwitchProps> = ({ item })
{
onSuccess: (response) => {
queryClient.invalidateQueries('scheduledQueries');
setErrorToast();
toasts.addSuccess(
response.item.enabled
? i18n.translate(
@ -75,7 +78,7 @@ const ActiveStateSwitchComponent: React.FC<ActiveStateSwitchProps> = ({ item })
},
onError: (error) => {
// @ts-expect-error update types
toasts.addError(error, { title: error.body.error, toastMessage: error.body.message });
setErrorToast(error, { title: error.body.error, toastMessage: error.body.message });
},
}
);

View file

@ -45,6 +45,7 @@ import { PolicyIdComboBoxField } from './policy_id_combobox_field';
import { QueriesField } from './queries_field';
import { ConfirmDeployAgentPolicyModal } from './confirmation_modal';
import { useAgentPolicies } from '../../agent_policies';
import { useErrorToast } from '../../common/hooks/use_error_toast';
const GhostFormField = () => <></>;
@ -68,6 +69,7 @@ const ScheduledQueryGroupFormComponent: React.FC<ScheduledQueryGroupFormProps> =
http,
notifications: { toasts },
} = useKibana().services;
const setErrorToast = useErrorToast();
const [showConfirmationModal, setShowConfirmationModal] = useState(false);
const handleHideConfirmationModal = useCallback(() => setShowConfirmationModal(false), []);
@ -110,6 +112,7 @@ const ScheduledQueryGroupFormComponent: React.FC<ScheduledQueryGroupFormProps> =
return;
}
setErrorToast();
navigateToApp(PLUGIN_ID, { path: `scheduled_query_groups/${data.item.id}` });
toasts.addSuccess(
i18n.translate('xpack.osquery.scheduledQueryGroup.form.updateSuccessToastMessageText', {
@ -122,7 +125,7 @@ const ScheduledQueryGroupFormComponent: React.FC<ScheduledQueryGroupFormProps> =
},
onError: (error) => {
// @ts-expect-error update types
toasts.addError(error, { title: error.body.error, toastMessage: error.body.message });
setErrorToast(error, { title: error.body.error, toastMessage: error.body.message });
},
}
);

View file

@ -63,7 +63,7 @@ export const parseAgentSelection = async (
perPage,
page,
kuery,
showInactive: true,
showInactive: false,
});
return { results: res.agents.map((agent) => agent.id), total: res.total };
});
@ -84,7 +84,7 @@ export const parseAgentSelection = async (
perPage,
page,
kuery,
showInactive: true,
showInactive: false,
});
return { results: res.agents.map((agent) => agent.id), total: res.total };
});