Skip to content
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

Consistency in the non-core visualizations and agent status #4166

Merged
merged 6 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ All notable changes to the Wazuh app project will be documented in this file.

## Wazuh v4.3.4 - Kibana 7.10.2, 7.16.x, 7.17.x - Revision 4305

### Added

- Added the `pending` agent status to some sections that was missing [#4166](https://github.com/wazuh/wazuh-kibana-app/pull/4166)

### Changed

- Replaced the visualization of `Status` panel in `Agents` [#4166](https://github.com/wazuh/wazuh-kibana-app/pull/4166)
- Replaced the visualization of policy in `Modules/Security configuration assessment/Inventory` [#4166](https://github.com/wazuh/wazuh-kibana-app/pull/4166)
- Consistency in the colors and labels used for the agent status [#4166](https://github.com/wazuh/wazuh-kibana-app/pull/4166)
- Replaced how the full and partial scan dates are displayed in the `Details` panel of `Vulnerabilities/Inventory` [#4169](https://github.com/wazuh/wazuh-kibana-app/pull/4169)

### Fixed
Expand All @@ -15,7 +22,7 @@ All notable changes to the Wazuh app project will be documented in this file.
## Wazuh v4.3.3 - Kibana 7.10.2, 7.16.x, 7.17.x - Revision 4304

### Fixed

- Fixed that the platform visualizations didn't use some definitions related to the UI on Kibana 7.10.2 [#4166](https://github.com/wazuh/wazuh-kibana-app/pull/4166)
- Fixed Wazuh Dashboard troubleshooting url [#4150](https://github.com/wazuh/wazuh-kibana-app/pull/4150)

## Wazuh v4.3.2 - Kibana 7.10.2 , 7.16.x, 7.17.x - Revision 4303
Expand Down
31 changes: 31 additions & 0 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,34 @@ export const PLUGIN_PLATFORM_URL_GUIDE_TITLE = 'Elastic guide';
export const PLUGIN_PLATFORM_REQUEST_HEADERS = {
'kbn-xsrf': 'kibana'
};

// UI
export const API_NAME_AGENT_STATUS = {
ACTIVE: 'active',
DISCONNECTED: 'disconnected',
PENDING: 'pending',
NEVER_CONNECTED: 'never_connected',
} as const;

export const UI_COLOR_AGENT_STATUS = {
[API_NAME_AGENT_STATUS.ACTIVE]: '#007871',
[API_NAME_AGENT_STATUS.DISCONNECTED]: '#BD271E',
[API_NAME_AGENT_STATUS.PENDING]: '#FEC514',
[API_NAME_AGENT_STATUS.NEVER_CONNECTED]: '#646A77',
default: '#000000'
} as const;

export const UI_LABEL_NAME_AGENT_STATUS = {
[API_NAME_AGENT_STATUS.ACTIVE]: 'Active',
[API_NAME_AGENT_STATUS.DISCONNECTED]: 'Disconnected',
[API_NAME_AGENT_STATUS.PENDING]: 'Pending',
[API_NAME_AGENT_STATUS.NEVER_CONNECTED]: 'Never connected',
default: 'Unknown'
} as const

export const UI_ORDER_AGENT_STATUS = [
API_NAME_AGENT_STATUS.ACTIVE,
API_NAME_AGENT_STATUS.DISCONNECTED,
API_NAME_AGENT_STATUS.PENDING,
API_NAME_AGENT_STATUS.NEVER_CONNECTED
]
14 changes: 14 additions & 0 deletions common/services/wz_agent_status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { UI_COLOR_AGENT_STATUS, UI_LABEL_NAME_AGENT_STATUS, API_NAME_AGENT_STATUS } from '../constants';

type TAgentStatus = typeof API_NAME_AGENT_STATUS[keyof typeof API_NAME_AGENT_STATUS];

type TAgentStatusColor = typeof UI_COLOR_AGENT_STATUS[keyof typeof UI_COLOR_AGENT_STATUS];
type TAgentStatusLabel = typeof UI_LABEL_NAME_AGENT_STATUS[keyof typeof UI_LABEL_NAME_AGENT_STATUS];

export function agentStatusColorByAgentStatus(status: TAgentStatus): TAgentStatusColor{
return UI_COLOR_AGENT_STATUS[status] || UI_COLOR_AGENT_STATUS.default;
}

export function agentStatusLabelByAgentStatus(status: TAgentStatus): TAgentStatusLabel{
return UI_LABEL_NAME_AGENT_STATUS[status] || UI_LABEL_NAME_AGENT_STATUS.default;
}
19 changes: 19 additions & 0 deletions public/components/agents/agent_status.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { mount } from 'enzyme';
import { AgentStatus } from './agent_status';
import { API_NAME_AGENT_STATUS, UI_COLOR_AGENT_STATUS, UI_LABEL_NAME_AGENT_STATUS, UI_ORDER_AGENT_STATUS } from '../../../common/constants';

describe('AgentStatus component', () => {
test.each(UI_ORDER_AGENT_STATUS.map(status => ({ status, color: UI_COLOR_AGENT_STATUS[status], label: UI_LABEL_NAME_AGENT_STATUS[status] })))('Renders status indicator with the its color and the label in lower case - %j', (input) => {
const wrapper = mount(<AgentStatus status={input.status} />);
expect(wrapper.find('svg').prop('style')).toHaveProperty('color', input.color);
expect(wrapper.find('.euiFlexGroup > span.euiFlexItem.euiFlexItem--flexGrowZero').text()).toEqual(input.label.toLowerCase())
});

it(`Renders status indicator with the its color and a custom label - status: ${API_NAME_AGENT_STATUS.ACTIVE}`, () => {
const label = 'custom_agent';
const wrapper = mount(<AgentStatus status={API_NAME_AGENT_STATUS.ACTIVE}>{label}</AgentStatus>);
expect(wrapper.find('svg').prop('style')).toHaveProperty('color', UI_COLOR_AGENT_STATUS[API_NAME_AGENT_STATUS.ACTIVE]);
expect(wrapper.find('.euiFlexGroup > span.euiFlexItem.euiFlexItem--flexGrowZero').text()).toEqual(label);
});
});
Desvelao marked this conversation as resolved.
Show resolved Hide resolved
16 changes: 16 additions & 0 deletions public/components/agents/agent_status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { EuiToolTip } from '@elastic/eui';
import { agentStatusColorByAgentStatus, agentStatusLabelByAgentStatus } from '../../../common/services/wz_agent_status';

export const AgentStatus = ({ status, children = null, labelProps = {}, style = {} }) => (
<span className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow" style={style}>
<EuiToolTip position="top" content={agentStatusLabelByAgentStatus(status).toLowerCase()}>
<span className="euiFlexItem euiFlexItem--flexGrowZero">
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" className={`euiIcon euiIcon--medium`} style={{ color: agentStatusColorByAgentStatus(status) }} focusable="false" role="img" aria-hidden="true">
<circle cx="8" cy="8" r="4"></circle>
</svg>
</span>
</EuiToolTip>
<span className="euiFlexItem euiFlexItem--flexGrowZero" {...labelProps}>{children || agentStatusLabelByAgentStatus(status).toLowerCase()}</span>
</span>
)
Comment on lines +1 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run formatter

3 changes: 2 additions & 1 deletion public/components/agents/fim/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { PromptNoActiveAgent, PromptNoSelectedAgent } from '../prompts';
import { compose } from 'redux';
import { withAgentSupportModule, withGuard, withUserAuthorizationPrompt } from '../../common/hocs';
import { API_NAME_AGENT_STATUS } from '../../../../common/constants';

const mapStateToProps = (state) => ({
currentAgentData: state.appStateReducers.currentAgentData,
Expand All @@ -23,7 +24,7 @@ export const MainFim = compose(
(props) => {
const agentData =
props.currentAgentData && props.currentAgentData.id ? props.currentAgentData : props.agent;
return agentData.status !== 'active';
return agentData.status !== API_NAME_AGENT_STATUS.ACTIVE;
},
() => <PromptNoActiveAgent />
),
Expand Down
66 changes: 32 additions & 34 deletions public/components/agents/sca/inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/

import React, { Component, Fragment } from 'react';
import { Pie } from "../../d3/pie";
import {
EuiFlexItem,
EuiFlexGroup,
Expand Down Expand Up @@ -47,16 +46,16 @@ import {
UIErrorSeverity,
UILogLevel,
} from '../../../react-services/error-orchestrator/types';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { API_NAME_AGENT_STATUS, UI_LOGGER_LEVELS } from '../../../../common/constants';
import { getErrorOrchestrator } from '../../../react-services/common-services';
import { VisualizationBasic } from '../../common/charts/visualizations/basic';

export class Inventory extends Component {
_isMount = false;
constructor(props) {
super(props);
const { agent } = this.props;
this.state = { agent, items: [], itemIdToExpandedRowMap: {}, showMoreInfo: false, loading: false, filters: [], pageTableChecks: {pageIndex: 0} }
this.policies = [];
this.state = { agent, items: [], itemIdToExpandedRowMap: {}, showMoreInfo: false, loading: false, filters: [], pageTableChecks: {pageIndex: 0}, policies: [] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatter here

this.suggestions = {};
this.columnsPolicies = [
{
Expand Down Expand Up @@ -272,31 +271,14 @@ export class Inventory extends Component {
try {
this._isMount && this.setState({ loading: true });
this.lookingPolicy = false;
const policies = await WzRequest.apiReq(
const {data: {data: {affected_items: policies}}} = await WzRequest.apiReq(
'GET',
`/sca/${this.props.agent.id}`,
{}
);
this.policies = (((policies || {}).data || {}).data || {}).affected_items || [];
const models = [];
for (let i = 0; i < this.policies.length; i++) {
models.push({
name: this.policies[i].name,
status: [
{ id: 'pass', label: 'Pass', value: this.policies[i].pass },
{ id: 'fail', label: 'Fail', value: this.policies[i].fail },
{
id: 'invalid',
label: 'Not applicable',
value: this.policies[i].invalid
}
]
});
}
this._isMount && this.setState({ data: models, loading: false });
this._isMount && this.setState({ loading: false, policies });
} catch (error) {
this.setState({ loading: false });
this.policies = [];
this.setState({ loading: false, policies: []});

const options: UIErrorLog = {
context: `${Inventory.name}.initialize`,
Expand Down Expand Up @@ -501,40 +483,56 @@ export class Inventory extends Component {
)}
</div>
<EuiPage>
{((this.props.agent && (this.props.agent || {}).status !== 'never_connected' && !(this.policies || []).length && !this.state.loading) &&
{((this.props.agent && (this.props.agent || {}).status !== API_NAME_AGENT_STATUS.NEVER_CONNECTED && !this.state.policies.length && !this.state.loading) &&
<EuiCallOut title="No scans available" iconType="iInCircle">
<EuiButton color="primary" onClick={() => this.initialize()}>
Refresh
</EuiButton>
</EuiButton>
</EuiCallOut>
)}

{((this.props.agent && (this.props.agent || {}).status === 'never_connected' && !this.state.loading) &&
{((this.props.agent && (this.props.agent || {}).status === API_NAME_AGENT_STATUS.NEVER_CONNECTED && !this.state.loading) &&
<EuiCallOut title="Agent has never connected" style={{ width: "100%" }} iconType="iInCircle">
<EuiButton color="primary" onClick={() => this.initialize()}>
Refresh
</EuiButton>
</EuiCallOut>
)}
{((this.props.agent && (this.props.agent || {}).os && !this.state.lookingPolicy && (this.policies || []).length > 0 && !this.state.loading) &&
{((this.props.agent && (this.props.agent || {}).os && !this.state.lookingPolicy && this.state.policies.length > 0 && !this.state.loading) &&
<div>
{((this.state.data || []).length &&
{this.state.policies.length &&
<EuiFlexGroup style={{ 'marginTop': 0 }}>
{(this.state.data || []).map((pie, idx) => (
{this.state.policies.map((policy, idx) => (
<EuiFlexItem key={idx} grow={false}>
<EuiCard title description betaBadgeLabel={pie.name} style={{ paddingBottom: 0 }}>
<Pie width={325} height={130} data={pie.status} colors={['#00a69b', '#ff645c', '#5c6773']} />
<EuiCard title description betaBadgeLabel={policy.name} style={{ paddingBottom: 0 }}>
<VisualizationBasic
type='donut'
size={{ width: '100%', height: '150px' }}
data={[
{ label: 'Pass', value: policy.pass, color: '#00a69b' },
{ label: 'Fail', value: policy.fail, color: '#ff645c' },
{
label: 'Not applicable',
value: policy.invalid,
color: '#5c6773'
}
]}
showLegend
noDataTitle='No results'
noDataMessage='No results were found.'
/>
<EuiSpacer size="m" />
</EuiCard>
</EuiFlexItem>
))}
</EuiFlexGroup>
)}
}
<EuiSpacer size="m" />
<EuiPanel paddingSize="l">
<EuiFlexGroup>
<EuiFlexItem>
<EuiBasicTable
items={this.policies}
items={this.state.policies}
columns={this.columnsPolicies}
rowProps={getPoliciesRowProps}
/>
Expand Down
5 changes: 3 additions & 2 deletions public/components/agents/sca/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { connect } from 'react-redux';
import { compose } from 'redux';
import { PromptSelectAgent, PromptNoSelectedAgent } from '../prompts';
import { withGuard, withUserAuthorizationPrompt, withAgentSupportModule } from '../../common/hocs';
import { API_NAME_AGENT_STATUS } from '../../../../common/constants';

const mapStateToProps = (state) => ({
currentAgentData: state.appStateReducers.currentAgentData,
Expand Down Expand Up @@ -43,10 +44,10 @@ export const MainSca = compose(
withGuard(
({ currentAgentData, agent }) => {
const agentData = currentAgentData && currentAgentData.id ? currentAgentData : agent;
return agentData.status === 'never_connected';
return agentData.status === API_NAME_AGENT_STATUS.NEVER_CONNECTED;
},
() => (
<PromptSelectAgent title="Agent never connected" body="The agent has never been connected please select another" />
<PromptSelectAgent title="Agent has never connected" body="The agent has never been connected please select another" />
)
),
withUserAuthorizationPrompt((props) => {
Expand Down
4 changes: 2 additions & 2 deletions public/components/agents/stats/agent-stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
UILogLevel,
UIErrorSeverity,
} from '../../../react-services/error-orchestrator/types';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { API_NAME_AGENT_STATUS, UI_LOGGER_LEVELS } from '../../../../common/constants';
import { getErrorOrchestrator } from '../../../react-services/common-services';

const tableColumns = [
Expand Down Expand Up @@ -107,7 +107,7 @@ export const MainAgentStats = compose(
{action: 'agent:read', resource: `agent:id:${agent.id}`},
...(agent.group || []).map(group => ({ action: 'agent:read', resource: `agent:group:${group}` }))
]]),
withGuard(({agent}) => agent.status !== 'active', PromptNoActiveAgentWithoutSelect),
withGuard(({agent}) => agent.status !== API_NAME_AGENT_STATUS.ACTIVE, PromptNoActiveAgentWithoutSelect),
withGuard(({agent}) => {
const [major, minor, patch] = agent.version.replace('Wazuh v','').split('.').map(value => parseInt(value));
return !(major >= 4 && minor >= 2 && patch >= 0)
Expand Down
5 changes: 3 additions & 2 deletions public/components/agents/syscollector/inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { EuiEmptyPrompt, EuiButton, EuiFlexGroup, EuiFlexItem, EuiCallOut } from
import { InventoryMetrics } from './components/syscollector-metrics';
import { SyscollectorTable } from './components/syscollector-table';
import { processColumns, portsColumns, packagesColumns } from './columns';
import { API_NAME_AGENT_STATUS } from '../../../../common/constants';

export function SyscollectorInventory({ agent }) {
if (agent && agent.status === 'never_connected') {
if (agent && agent.status === API_NAME_AGENT_STATUS.NEVER_CONNECTED) {
return (
<EuiEmptyPrompt
iconType="securitySignalDetected"
Expand Down Expand Up @@ -72,7 +73,7 @@ export function SyscollectorInventory({ agent }) {

return (
<div style={{ overflow: 'hidden' }}>
{agent && agent.status === 'disconnected' && (
{agent && agent.status === API_NAME_AGENT_STATUS.DISCONNECTED && (
<EuiCallOut
style={{ margin: '8px 16px 8px 16px' }}
title="This agent is currently disconnected, the data may be outdated."
Expand Down
8 changes: 5 additions & 3 deletions public/components/common/charts/visualizations/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type VisualizationBasicProps = ChartDonutProps & {
noDataMessage?: string | (() => React.node)
errorTitle?: string
errorMessage?: string | (() => React.node)
error?: {message: string}
}

const chartTypes = {
Expand All @@ -32,7 +33,8 @@ export const VisualizationBasic = ({
noDataTitle = 'No data',
noDataMessage,
errorTitle = 'Error',
errorMessage
errorMessage,
error
}: VisualizationBasicProps) => {
const { width, height } = typeof size === 'object' ? size : { width: size, height: size };

Expand All @@ -44,12 +46,12 @@ export const VisualizationBasic = ({
<EuiLoadingChart size="xl" style={{top: '50%', transform:'translate(-50%, -50%)', position: 'absolute'}}/>
</div>
)
}else if(errorMessage){
}else if(errorMessage || error?.message){
visualization = (
<EuiEmptyPrompt
iconType="alert"
title={<h4>{errorTitle}</h4>}
body={errorMessage}
body={errorMessage || error?.message}
/>
)
}else if(!data || (Array.isArray(data) && !data.length)){
Expand Down
6 changes: 0 additions & 6 deletions public/components/common/modules/main-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,6 @@ export class MainModuleAgent extends Component {
this.setState({ showAgentInfo: !this.state.showAgentInfo });
}

color = (status, hex = false) => {
if (status.toLowerCase() === 'active') { return hex ? '#017D73' : 'success'; }
else if (status.toLowerCase() === 'disconnected') { return hex ? '#BD271E' : 'danger'; }
else if (status.toLowerCase() === 'never connected') { return hex ? '#98A2B3' : 'subdued'; }
}

async startReport() {
this.setState({ loadingReport: true });
const syscollectorFilters: any[] = [];
Expand Down
10 changes: 0 additions & 10 deletions public/components/common/modules/main-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,6 @@ export const MainModuleOverview = connect(mapStateToProps)(class MainModuleOverv
};
}

getBadgeColor(agentStatus) {
if (agentStatus.toLowerCase() === 'active') {
return 'secondary';
} else if (agentStatus.toLowerCase() === 'disconnected') {
return '#BD271E';
} else if (agentStatus.toLowerCase() === 'never connected') {
return 'default';
}
}

setGlobalBreadcrumb() {
const currentAgent = store.getState().appStateReducers.currentAgentData;
if (WAZUH_MODULES[this.props.section]) {
Expand Down
Loading