Skip to content

Commit

Permalink
[Fleet] Update agent listing for better status reporting (#84798) (#8…
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored Dec 10, 2020
1 parent 0968676 commit b711c55
Show file tree
Hide file tree
Showing 19 changed files with 752 additions and 515 deletions.
10 changes: 9 additions & 1 deletion x-pack/plugins/fleet/common/services/agent_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export function buildKueryForOfflineAgents() {
}s AND not (${buildKueryForErrorAgents()})`;
}

export function buildKueryForUpdatingAgents() {
export function buildKueryForUpgradingAgents() {
return `${AGENT_SAVED_OBJECT_TYPE}.upgrade_started_at:*`;
}

export function buildKueryForUpdatingAgents() {
return `(${buildKueryForUpgradingAgents()}) or (${buildKueryForEnrollingAgents()}) or (${buildKueryForUnenrollingAgents()})`;
}

export function buildKueryForInactiveAgents() {
return `${AGENT_SAVED_OBJECT_TYPE}.active:false`;
}
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export type AgentStatus =
| 'updating'
| 'degraded';

export type SimplifiedAgentStatus = 'healthy' | 'unhealthy' | 'updating' | 'offline' | 'inactive';

export type AgentActionType =
| 'POLICY_CHANGE'
| 'UNENROLL'
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/types/rest_spec/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export interface UpdateAgentRequest {

export interface GetAgentStatusRequest {
query: {
kuery?: string;
policyId?: string;
};
}
Expand Down
206 changes: 66 additions & 140 deletions x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState, useEffect } from 'react';
import { IFieldType } from 'src/plugins/data/public';
// @ts-ignore
import { EuiSuggest, EuiSuggestItemProps } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useDebounce, useStartServices } from '../hooks';
import React, { useState, useEffect, useMemo } from 'react';
import {
QueryStringInput,
IFieldType,
esKuery,
} from '../../../../../../../src/plugins/data/public';
import { useStartServices } from '../hooks';
import { INDEX_NAME, AGENT_SAVED_OBJECT_TYPE } from '../constants';

const DEBOUNCE_SEARCH_MS = 150;
const HIDDEN_FIELDS = [`${AGENT_SAVED_OBJECT_TYPE}.actions`];

interface Suggestion {
label: string;
description: string;
value: string;
type: {
color: string;
iconType: string;
};
start: number;
end: number;
}

interface Props {
value: string;
fieldPrefix: string;
onChange: (newValue: string) => void;
onChange: (newValue: string, submit?: boolean) => void;
placeholder?: string;
}

Expand All @@ -40,135 +28,73 @@ export const SearchBar: React.FunctionComponent<Props> = ({
onChange,
placeholder,
}) => {
const { suggestions } = useSuggestions(fieldPrefix, value);

// TODO fix type when correctly typed in EUI
const onAutocompleteClick = (suggestion: any) => {
onChange(
[value.slice(0, suggestion.start), suggestion.value, value.slice(suggestion.end, -1)].join('')
);
};
// TODO fix type when correctly typed in EUI
const onChangeSearch = (e: any) => {
onChange(e.value);
};

return (
<EuiSuggest
// TODO fix when correctly typed
// @ts-ignore
value={value}
icon={'search'}
placeholder={
placeholder ||
i18n.translate('xpack.fleet.defaultSearchPlaceholderText', {
defaultMessage: 'Search',
})
}
onInputChange={onChangeSearch}
onItemClick={onAutocompleteClick}
suggestions={suggestions.map((suggestion) => {
return {
...suggestion,
// For type
onClick: () => {},
descriptionDisplay: 'wrap',
labelWidth: '40',
};
})}
/>
);
};

export function transformSuggestionType(type: string): { iconType: string; color: string } {
switch (type) {
case 'field':
return { iconType: 'kqlField', color: 'tint4' };
case 'value':
return { iconType: 'kqlValue', color: 'tint0' };
case 'conjunction':
return { iconType: 'kqlSelector', color: 'tint3' };
case 'operator':
return { iconType: 'kqlOperand', color: 'tint1' };
default:
return { iconType: 'kqlOther', color: 'tint1' };
}
}

function useSuggestions(fieldPrefix: string, search: string) {
const { data } = useStartServices();
const [indexPatternFields, setIndexPatternFields] = useState<IFieldType[]>();

const debouncedSearch = useDebounce(search, DEBOUNCE_SEARCH_MS);
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
const isQueryValid = useMemo(() => {
if (!value || value === '') {
return true;
}

const fetchSuggestions = async () => {
try {
const res = (await data.indexPatterns.getFieldsForWildcard({
pattern: INDEX_NAME,
})) as IFieldType[];
if (!data || !data.autocomplete) {
throw new Error('Missing data plugin');
}
const query = debouncedSearch || '';
// @ts-ignore
const esSuggestions = (
await data.autocomplete.getQuerySuggestions({
language: 'kuery',
indexPatterns: [
{
title: INDEX_NAME,
fields: res,
},
],
boolFilter: [],
query,
selectionStart: query.length,
selectionEnd: query.length,
})
)
.filter((suggestion) => {
if (suggestion.type === 'conjunction') {
return true;
}
if (suggestion.type === 'value') {
return true;
}
if (suggestion.type === 'operator') {
return true;
}
esKuery.fromKueryExpression(value);
return true;
} catch (e) {
return false;
}
}, [value]);

if (fieldPrefix && suggestion.text.startsWith(fieldPrefix)) {
useEffect(() => {
const fetchFields = async () => {
try {
const _fields: IFieldType[] = await data.indexPatterns.getFieldsForWildcard({
pattern: INDEX_NAME,
});
const fields = (_fields || []).filter((field) => {
if (fieldPrefix && field.name.startsWith(fieldPrefix)) {
for (const hiddenField of HIDDEN_FIELDS) {
if (suggestion.text.startsWith(hiddenField)) {
if (field.name.startsWith(hiddenField)) {
return false;
}
}
return true;
}
});
setIndexPatternFields(fields);
} catch (err) {
setIndexPatternFields(undefined);
}
};
fetchFields();
}, [data.indexPatterns, fieldPrefix]);

return false;
})
.map((suggestion: any) => ({
label: suggestion.text,
description: suggestion.description || '',
type: transformSuggestionType(suggestion.type),
start: suggestion.start,
end: suggestion.end,
value: suggestion.text,
}));

setSuggestions(esSuggestions);
} catch (err) {
setSuggestions([]);
}
};

useEffect(() => {
fetchSuggestions();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedSearch]);

return {
suggestions,
};
}
return (
<QueryStringInput
iconType="search"
disableLanguageSwitcher={true}
indexPatterns={
indexPatternFields
? [
{
title: INDEX_NAME,
fields: indexPatternFields,
},
]
: []
}
query={{
query: value,
language: 'kuery',
}}
isInvalid={!isQueryValid}
disableAutoFocus={true}
placeholder={placeholder}
onChange={(newQuery) => {
onChange(newQuery.query as string);
}}
onSubmit={(newQuery) => {
onChange(newQuery.query as string, true);
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,10 @@ export function useGetAgents(query: GetAgentsRequest['query'], options?: Request
});
}

export function sendGetAgentStatus(
query: GetAgentStatusRequest['query'],
options?: RequestOptions
) {
return sendRequest<GetAgentStatusResponse>({
export function sendGetAgents(query: GetAgentsRequest['query'], options?: RequestOptions) {
return sendRequest<GetAgentsResponse>({
method: 'get',
path: agentRouteService.getStatusPath(),
path: agentRouteService.getListPath(),
query,
...options,
});
Expand All @@ -83,6 +80,18 @@ export function useGetAgentStatus(query: GetAgentStatusRequest['query'], options
});
}

export function sendGetAgentStatus(
query: GetAgentStatusRequest['query'],
options?: RequestOptions
) {
return sendRequest<GetAgentStatusResponse>({
method: 'get',
path: agentRouteService.getStatusPath(),
query,
...options,
});
}

export function sendPutAgentReassign(
agentId: string,
body: PutAgentReassignRequest['body'],
Expand Down
Loading

0 comments on commit b711c55

Please sign in to comment.