-
Notifications
You must be signed in to change notification settings - Fork 8.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial pass at agents list #47177
Initial pass at agents list #47177
Changes from 2 commits
f9a41ba
d6d8f80
6693fa1
c6f4d39
731a41c
8531d26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* 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 React from 'react'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { EuiHealth } from '@elastic/eui'; | ||
|
||
interface Props { | ||
agent: any; | ||
} | ||
|
||
export const AgentHealth: React.SFC<Props> = ({ agent }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a simplified component for now as the information returned doesn't contain detailed status information, only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is due to the events API being added secondary to this. Active has nothing to do with the status though. An unenrolled agent becomes active:false There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The status needs to be derived from the (events of an agent) + (last checkin with the timeout of the last checkin based on the agent type, with ephemeral agents having not been seen in X time having no effect to the status , temporary showing in just an nuteral offline state if not seen in polling time from policy * 3 with the default polling time being 30sec, permanent is in a degraded status if not seen in 2x polling time, and an error status of offline if not seen in 4x) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Until we have events flowing in, just using the calculation of the last checkin time should be fine |
||
if (agent.active) { | ||
return ( | ||
<EuiHealth color="success"> | ||
<FormattedMessage id="xpack.fleet.agentHealth.onlineStatusText" defaultMessage="Online" /> | ||
</EuiHealth> | ||
); | ||
} | ||
return ( | ||
<EuiHealth color="subdued"> | ||
<FormattedMessage id="xpack.fleet.agentHealth.offlineStatusText" defaultMessage="Offline" /> | ||
</EuiHealth> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/* | ||
* 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 React, { useState, useEffect } from 'react'; | ||
import { | ||
EuiInMemoryTable, | ||
EuiPageBody, | ||
EuiPageContent, | ||
EuiTitle, | ||
EuiSpacer, | ||
EuiText, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiButton, | ||
EuiEmptyPrompt, | ||
EuiLink, | ||
} from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { FrontendLibs } from '../../lib/types'; | ||
import { AgentHealth } from '../../components/agent_health'; | ||
|
||
interface RouterProps { | ||
libs: FrontendLibs; | ||
} | ||
|
||
export const AgentListPage: React.SFC<RouterProps> = ({ libs }) => { | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
const [agents, setAgents] = useState<any[]>([]); | ||
|
||
const fetchAgents = async () => { | ||
setIsLoading(true); | ||
setAgents(await libs.agents.getAll()); | ||
setIsLoading(false); | ||
}; | ||
|
||
// Load agents | ||
useEffect(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should prob use a timer, and poll every X seconds There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed, I will change this when I do the refactoring work to support manual pagination. with EuiInMemoryTable, refreshing data resets the table state! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah true I forgot it did that |
||
fetchAgents(); | ||
}, []); | ||
|
||
// Some agents retrieved, set up table props | ||
const columns = [ | ||
{ | ||
field: 'local_metadata.host', | ||
name: i18n.translate('xpack.fleet.agentList.hostColumnTitle', { | ||
defaultMessage: 'Host', | ||
}), | ||
truncateText: true, | ||
sortable: true, | ||
}, | ||
// { | ||
// field: 'id', | ||
// name: i18n.translate('xpack.fleet.agentList.metaColumnTitle', { | ||
// defaultMessage: 'Meta', | ||
// }), | ||
// truncateText: true, | ||
// sortable: true, | ||
// render: () => <span>some-region</span>, | ||
// }, | ||
{ | ||
field: 'policy_id', | ||
name: i18n.translate('xpack.fleet.agentList.policyColumnTitle', { | ||
defaultMessage: 'Policy', | ||
}), | ||
truncateText: true, | ||
sortable: true, | ||
}, | ||
// { | ||
// field: 'event_rate', | ||
// name: i18n.translate('xpack.fleet.agentList.eventsColumnTitle', { | ||
// defaultMessage: 'Events (24h)', | ||
// }), | ||
// truncateText: true, | ||
// sortable: true, | ||
// render: () => <span>34</span>, | ||
// }, | ||
{ | ||
field: 'active', | ||
name: i18n.translate('xpack.fleet.agentList.statusColumnTitle', { | ||
defaultMessage: 'Status', | ||
}), | ||
truncateText: true, | ||
sortable: true, | ||
render: (active: boolean, agent: any) => <AgentHealth agent={agent} />, | ||
}, | ||
{ | ||
name: i18n.translate('xpack.fleet.agentList.actionsColumnTitle', { | ||
defaultMessage: 'Actions', | ||
}), | ||
actions: [ | ||
{ | ||
render: () => { | ||
return ( | ||
<EuiLink color="primary" onClick={() => {}}> | ||
<FormattedMessage | ||
id="xpack.fleet.agentList.viewActionLinkText" | ||
defaultMessage="view" | ||
/> | ||
</EuiLink> | ||
); | ||
}, | ||
}, | ||
], | ||
width: '100px', | ||
}, | ||
]; | ||
|
||
const sorting = { | ||
sort: { | ||
field: 'last_checkin', | ||
direction: 'asc', | ||
}, | ||
}; | ||
|
||
const pagination = { | ||
initialPageSize: 20, | ||
pageSizeOptions: [10, 20, 50], | ||
}; | ||
|
||
const search = { | ||
box: { | ||
incremental: true, | ||
schema: true, | ||
}, | ||
filters: [ | ||
{ | ||
type: 'field_value_selection', | ||
field: 'policy_id', | ||
name: i18n.translate('xpack.fleet.agentList.policyFilterLabel', { | ||
defaultMessage: 'Policy', | ||
}), | ||
multiSelect: true, | ||
options: [...new Set(agents.map(agent => agent.policy_id))].map(policy => ({ | ||
value: policy, | ||
})), | ||
}, | ||
], | ||
toolsRight: ( | ||
<EuiFlexGroup gutterSize="m" justifyContent="spaceAround"> | ||
<EuiFlexItem> | ||
<EuiButton color="secondary" iconType="refresh" onClick={fetchAgents}> | ||
<FormattedMessage id="xpack.fleet.agentList.reloadButton" defaultMessage="Reload" /> | ||
</EuiButton> | ||
</EuiFlexItem> | ||
<EuiFlexItem> | ||
<EuiButton fill iconType="plusInCircle"> | ||
<FormattedMessage | ||
id="xpack.fleet.agentList.addButton" | ||
defaultMessage="Install new agent" | ||
/> | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
), | ||
}; | ||
|
||
const emptyPrompt = ( | ||
<EuiEmptyPrompt | ||
title={ | ||
<h2> | ||
<FormattedMessage | ||
id="xpack.fleet.agentList.noAgentsPrompt" | ||
defaultMessage="No agents installed" | ||
/> | ||
</h2> | ||
} | ||
actions={ | ||
<EuiButton fill iconType="plusInCircle"> | ||
<FormattedMessage | ||
id="xpack.fleet.agentList.addButton" | ||
defaultMessage="Install new agent" | ||
/> | ||
</EuiButton> | ||
} | ||
/> | ||
); | ||
|
||
return ( | ||
<EuiPageBody> | ||
<EuiPageContent> | ||
<EuiTitle size="l"> | ||
<h1> | ||
<FormattedMessage id="xpack.fleet.agentList.pageTitle" defaultMessage="Elastic Fleet" /> | ||
</h1> | ||
</EuiTitle> | ||
<EuiSpacer size="s" /> | ||
<EuiTitle size="s"> | ||
<EuiText color="subdued"> | ||
<FormattedMessage | ||
id="xpack.fleet.agentList.pageDescription" | ||
defaultMessage="Use agents to faciliate data collection for your Elastic stack." | ||
/> | ||
</EuiText> | ||
</EuiTitle> | ||
<EuiSpacer size="m" /> | ||
<EuiInMemoryTable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not really familiar with elastic components but it is ok to load all the agents? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this component has built in pagination but will likely run into performance problems once there are thousands of items. my intention is to refactor this into EuiBasicTable with manual pagination after this week since I see that we intend to support pagination in the API endpoints via |
||
loading={isLoading} | ||
message={ | ||
isLoading | ||
? i18n.translate('xpack.fleet.agentList.loadingAgentsMessage', { | ||
defaultMessage: 'Loading agents…', | ||
}) | ||
: agents.length === 0 | ||
? emptyPrompt | ||
: i18n.translate('xpack.fleet.agentList.noFilteredAgentsPrompt', { | ||
defaultMessage: 'No agents found', | ||
}) | ||
} | ||
items={agents} | ||
itemId="id" | ||
columns={columns} | ||
search={search} | ||
sorting={sorting} | ||
pagination={pagination} | ||
/> | ||
</EuiPageContent> | ||
</EuiPageBody> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this type should be
Agent
but the response doesn't return that type atm, so just usingany
for nowThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should be Agent less access_token and enrollment_token... we prob need to adjust these types a bit / create a new type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I re adjusted the type for the agent detail page, I can create a PR with it later tonight