diff --git a/CHANGELOG.md b/CHANGELOG.md index e1d9ebe559..23c0ca5d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,8 @@ All notable changes to the Wazuh app project will be documented in this file. - Move AngularJS controller for management to ReactJS component [#6555](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6555) - Moved the registry data to in-memory cache [#6481](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6481) - Enhance the validation for `enrollment.dns` on App Settings application [#6573](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6573) -- Remove AngularJS controller for manage groups [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) - Remove some branding references across the application. [#6155](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6155) +- Move AngularJS controller for the agent view to ReactJS [#6618](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6618) - Implement new data source feature on MITRE ATT&CK module [#6482](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6482) ### Fixed diff --git a/plugins/main/public/components/agents/export-configuration.js b/plugins/main/public/components/agents/export-configuration.js new file mode 100644 index 0000000000..995a4d23bc --- /dev/null +++ b/plugins/main/public/components/agents/export-configuration.js @@ -0,0 +1,181 @@ +/* + * Wazuh app - React component for exporting the configuration of a group. + * Copyright (C) 2015-2022 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ +import React, { Component } from 'react'; + +import { + EuiPopover, + EuiButton, + EuiCheckboxGroup, + EuiSpacer, + EuiButtonEmpty, +} from '@elastic/eui'; + +import PropTypes from 'prop-types'; +import { UnsupportedComponents } from '../../utils/components-os-support'; +import { WAZUH_AGENTS_OS_TYPE } from '../../../common/constants'; +import { withErrorBoundary } from '../common/hocs'; + +export const ExportConfiguration = withErrorBoundary( + class ExportConfiguration extends Component { + constructor(props) { + super(props); + + this.state = { + buttonDisabled: false, + isPopoverOpen: false, + }; + + const agentOptions = [ + 'Global configuration', + 'Communication', + 'Anti-flooding settings', + 'Labels', + 'Policy monitoring', + { name: 'oscap', desc: 'OpenSCAP' }, + 'CIS-CAT', + 'Osquery', + 'Inventory data', + 'Active response', + 'Commands', + { name: 'docker', desc: 'Docker listener' }, + 'Log collection', + 'Integrity monitoring', + ]; + const groupOptions = ['Configurations', 'Agents in group']; + + this.options = []; + const list = this.props.type === 'agent' ? agentOptions : groupOptions; + list.forEach((x, idx) => { + if ( + typeof x === 'string' || + (x.name && + !( + UnsupportedComponents[this.props.agentPlatform] || + UnsupportedComponents[WAZUH_AGENTS_OS_TYPE.OTHERS] + ).includes(x.name)) + ) { + this.options.push({ id: `${idx}`, label: x.desc || x }); + } + }); + + let initialChecks = {}; + this.options.forEach(x => { + initialChecks[x.id] = true; + }); + this.state.checkboxIdToSelectedMap = initialChecks; + } + + selectAll(flag) { + let newCheckboxIdToSelectedMap = {}; + for (let i = 0; i < this.options.length; i++) { + newCheckboxIdToSelectedMap[`${this.options[i].id}`] = flag; + } + this.setState({ + checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, + buttonDisabled: !flag, + }); + } + + exportClick() { + this.setState({ + isPopoverOpen: !this.state.isPopoverOpen, + }); + } + + closePopover() { + this.setState({ + isPopoverOpen: false, + }); + } + + onChange = optionId => { + const newCheckboxIdToSelectedMap = { + ...this.state.checkboxIdToSelectedMap, + ...{ + [optionId]: !this.state.checkboxIdToSelectedMap[optionId], + }, + }; + let result = false; + for (let i = 0; i < this.options.length; i++) { + if (newCheckboxIdToSelectedMap[`${this.options[i].id}`] === true) { + result = true; + } + } + this.setState({ + checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, + buttonDisabled: !result, + }); + }; + + render() { + const button = ( + + Export PDF + + ); + return ( + + + + {this.options.length > 3 && ( + <> + this.selectAll(true)}> + Select all + + + this.selectAll(false)}> + Unselect all + + + )} + + { + this.closePopover(); + this.props.exportConfiguration( + this.state.checkboxIdToSelectedMap, + ); + }} + fill + > + Generate PDF report + + + ); + } + }, +); + +ExportConfiguration.propTypes = { + exportConfiguration: PropTypes.func, + type: PropTypes.string, + agentPlatform: PropTypes.string, +}; diff --git a/plugins/main/public/components/common/charts/visualizations/basic.tsx b/plugins/main/public/components/common/charts/visualizations/basic.tsx index 2e48e5e734..eaca2e6270 100644 --- a/plugins/main/public/components/common/charts/visualizations/basic.tsx +++ b/plugins/main/public/components/common/charts/visualizations/basic.tsx @@ -160,7 +160,11 @@ export const VisualizationBasicWidgetSelector = ({ return ( <> - + {title && (

diff --git a/plugins/main/public/components/common/welcome/agents-welcome.js b/plugins/main/public/components/common/welcome/agents-welcome.js index cb4b63fb54..43b19f1556 100644 --- a/plugins/main/public/components/common/welcome/agents-welcome.js +++ b/plugins/main/public/components/common/welcome/agents-welcome.js @@ -22,7 +22,6 @@ import { EuiButtonEmpty, EuiPage, EuiPopover, - EuiLoadingChart, EuiToolTip, EuiButtonIcon, EuiPageBody, @@ -39,20 +38,16 @@ import WzReduxProvider from '../../../redux/wz-redux-provider'; import MenuAgent from './components/menu-agent'; import './welcome.scss'; import { WzDatePicker } from '../../../components/wz-date-picker/wz-date-picker'; -import KibanaVis from '../../../kibana-integrations/kibana-vis'; -import { VisFactoryHandler } from '../../../react-services/vis-factory-handler'; -import { AppState } from '../../../react-services/app-state'; -import { FilterHandler } from '../../../utils/filter-handler'; import { TabVisualizations } from '../../../factories/tab-visualizations'; import { showExploreAgentModalGlobal, updateCurrentAgentData, } from '../../../redux/actions/appStateActions'; import { - getAngularModule, getChrome, getCore, getDataPlugin, + getAngularModule, } from '../../../kibana-services'; import { hasAgentSupportModule } from '../../../react-services/wz-agents'; import { @@ -80,6 +75,7 @@ import { malwareDetection, } from '../../../utils/applications'; import { RedirectAppLinks } from '../../../../../../src/plugins/opensearch_dashboards_react/public'; +import { EventsCount } from './dashboard/events-count'; const mapStateToProps = state => ({ agent: state.appStateReducers.currentAgentData, @@ -105,11 +101,11 @@ export const AgentsWelcome = compose( }, ...(agent?.name ? [ - { - text: `${agent.name}`, - truncate: true, - }, - ] + { + text: `${agent.name}`, + truncate: true, + }, + ] : []), ]; }), @@ -150,6 +146,9 @@ export const AgentsWelcome = compose( this.sidebarSizeDefault = 320; + const $injector = getAngularModule().$injector; + this.location = $injector.get('$location'); + this.state = { lastScans: [], isLoading: true, @@ -200,8 +199,8 @@ export const AgentsWelcome = compose( of duplicating it. It was duplicated due to the differences of requirements in the Explore agent button for the modules and agent welcome */ - async removeAgentsFilter() { - await this.props.setAgent(false); + removeAgentsFilter() { + this.props.setAgent(false); const currentAppliedFilters = getDataPlugin().query.filterManager.filters; const agentFilters = currentAppliedFilters.filter(x => { return x.meta.key !== 'agent.id'; @@ -226,8 +225,7 @@ export const AgentsWelcome = compose( tabVisualizations.assign({ welcome: 8, }); - const filterHandler = new FilterHandler(AppState.getCurrentPattern()); - const $injector = getAngularModule().$injector; + this.drawerLokedSubscribtion = getChrome() .getIsNavDrawerLocked$() .subscribe(isLocked => { @@ -235,15 +233,7 @@ export const AgentsWelcome = compose( this.updateWidth(); }); }); - this.router = $injector.get('$route'); - this.location = $injector.get('$location'); window.addEventListener('resize', this.updateWidth); //eslint-disable-line - await VisFactoryHandler.buildAgentsVisualizations( - filterHandler, - 'welcome', - null, - this.props.agent.id, - ); } componentDidUpdate(prevProps) { @@ -268,13 +258,13 @@ export const AgentsWelcome = compose( ) ? JSON.parse(window.localStorage.getItem('wz-menu-agent-apps-pinned')) : [ - // Default pinned applications - threatHunting.id, - fileIntegrityMonitoring.id, - configurationAssessment.id, - mitreAttack.id, - malwareDetection.id, - ]; + // Default pinned applications + threatHunting.id, + fileIntegrityMonitoring.id, + configurationAssessment.id, + mitreAttack.id, + malwareDetection.id, + ]; } // Ensure the pinned applications are supported @@ -354,7 +344,6 @@ export const AgentsWelcome = compose( closePopover={() => { this.setState({ switchModule: false }); }} - switchTab={module => this.props.switchTab(module)} > @@ -366,7 +355,6 @@ export const AgentsWelcome = compose( } renderTitle() { - const notNeedStatus = true; const thereAreAgentSelected = Boolean(this.props.agent?.id); // Calculate if the header buttons should display the name or only the icon to be responsive @@ -411,7 +399,6 @@ export const AgentsWelcome = compose( closePopover={() => { this.setState({ switchModule: false }); }} - switchTab={module => this.props.switchTab(module)} > @@ -460,9 +447,7 @@ export const AgentsWelcome = compose( - this.props.switchTab('syscollector', notNeedStatus) - } + onClick={() => this.props.switchTab('syscollector')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -477,7 +462,7 @@ export const AgentsWelcome = compose( this.props.switchTab('stats', notNeedStatus)} + onClick={() => this.props.switchTab('stats')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -492,9 +477,7 @@ export const AgentsWelcome = compose( - this.props.switchTab('configuration', notNeedStatus) - } + onClick={() => this.props.switchTab('configuration')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -569,50 +552,13 @@ export const AgentsWelcome = compose( } renderEventCountVisualization() { - return ( - - - - -

- -

Events count evolution

-
-

-
-
- -
- - - -
-
- -
-
-
- ); + return ; } renderSCALastScan() { return ( - + ); } @@ -654,8 +600,8 @@ export const AgentsWelcome = compose( }} > {' '} - {/* DatePicker */} - {}} /> + {/* TODO: Replace with SearchBar and replace implementation to get the time range in AgentView component*/} + { }} /> {(this.state.widthWindow < 1150 && ( @@ -688,33 +634,33 @@ export const AgentsWelcome = compose( )) || ( - - - - - - {this.renderMitrePanel()} - - {this.renderCompliancePanel()} - - - - - - - - {' '} - {/* Events count evolution */} - {this.renderEventCountVisualization()} - - {this.renderSCALastScan()} - - - )} + + + + + + {this.renderMitrePanel()} + + {this.renderCompliancePanel()} + + + + + + + + {' '} + {/* Events count evolution */} + {this.renderEventCountVisualization()} + + {this.renderSCALastScan()} + + + )} diff --git a/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts b/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts new file mode 100644 index 0000000000..7d250e7d05 --- /dev/null +++ b/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts @@ -0,0 +1,137 @@ +import { DashboardPanelState } from '../../../../../../../src/plugins/dashboard/public/application'; +import { EmbeddableInput } from '../../../../../../../src/plugins/embeddable/public'; + +const getVisStateEventsCountEvolution = (indexPatternId: string) => ({ + id: 'App-Agents-Welcome-Events-Evolution', + title: 'Events count evolution', + type: 'line', + params: { + type: 'line', + grid: { categoryLines: false }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { type: 'linear' }, + labels: { show: true, filter: true, truncate: 100 }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { type: 'linear', mode: 'normal' }, + labels: { show: true, rotate: 0, filter: false, truncate: 100 }, + title: { text: 'Count' }, + }, + ], + seriesParams: [ + { + show: true, + type: 'line', + mode: 'normal', + data: { label: 'Count', id: '1' }, + valueAxis: 'ValueAxis-1', + drawLinesBetweenPoints: true, + lineWidth: 2, + interpolate: 'linear', + showCircles: true, + }, + ], + addTooltip: true, + addLegend: false, + legendPosition: 'right', + times: [], + addTimeMarker: false, + labels: {}, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: 'full', + color: '#E7664C', + }, + dimensions: { + x: null, + y: [ + { + accessor: 0, + format: { id: 'number' }, + params: {}, + label: 'Count', + aggType: 'count', + }, + ], + }, + }, + uiState: { + vis: { params: { sort: { columnIndex: 2, direction: 'desc' } } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '2', + enabled: true, + type: 'date_histogram', + schema: 'segment', + params: { + field: 'timestamp', + useNormalizedEsInterval: true, + scaleMetricValues: false, + interval: 'auto', + drop_partials: false, + min_doc_count: 1, + extended_bounds: {}, + }, + }, + ], + }, +}); + +export const getDashboardPanels = ( + indexPatternId: string, +): { + [panelId: string]: DashboardPanelState< + EmbeddableInput & { [k: string]: unknown } + >; +} => { + return { + '1': { + gridData: { + w: 48, + h: 12, + x: 0, + y: 0, + i: '1', + }, + type: 'visualization', + explicitInput: { + id: '1', + savedVis: getVisStateEventsCountEvolution(indexPatternId), + }, + }, + }; +}; diff --git a/plugins/main/public/components/common/welcome/dashboard/events-count.tsx b/plugins/main/public/components/common/welcome/dashboard/events-count.tsx new file mode 100644 index 0000000000..e41f399a5f --- /dev/null +++ b/plugins/main/public/components/common/welcome/dashboard/events-count.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { AlertsDataSource } from '../../data-source/pattern/alerts/alerts-data-source'; +import { AlertsDataSourceRepository } from '../../data-source/pattern/alerts/alerts-data-source-repository'; +import { getPlugins } from '../../../../kibana-services'; +import { getDashboardPanels } from './dashboard_panels'; +import { ViewMode } from '../../../../../../../src/plugins/embeddable/public'; +import { useDataSource } from '../../data-source/hooks'; +import { PatternDataSource, tParsedIndexPattern } from '../../data-source'; +import { + EuiPanel, + EuiFlexItem, + EuiFlexGroup, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { useTimeFilter } from '../../hooks'; +import { LoadingSpinner } from '../../loading-spinner/loading-spinner'; + +const plugins = getPlugins(); +const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer; + +export const EventsCount = () => { + const { + dataSource, + fetchFilters, + isLoading: isDataSourceLoading, + } = useDataSource({ + DataSource: AlertsDataSource, + repository: new AlertsDataSourceRepository(), + }); + + const { timeFilter } = useTimeFilter(); + + return ( + + + + +

+ +

Events count evolution

+
+

+
+
+ + {!isDataSourceLoading && dataSource ? ( + + ) : ( + + )} +
+
+ ); +}; diff --git a/plugins/main/public/components/endpoints-summary/agent/index.tsx b/plugins/main/public/components/endpoints-summary/agent/index.tsx new file mode 100644 index 0000000000..c7b88c3ad9 --- /dev/null +++ b/plugins/main/public/components/endpoints-summary/agent/index.tsx @@ -0,0 +1,126 @@ +import React, { useState, useEffect } from 'react'; +import { EuiPage, EuiPageBody, EuiProgress } from '@elastic/eui'; +import { useDispatch } from 'react-redux'; +import { getErrorOrchestrator } from '../../../react-services/common-services'; +import { UI_LOGGER_LEVELS } from '../../../../common/constants'; +import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types'; +import { AgentsWelcome } from '../../common/welcome/agents-welcome'; +import { Agent } from '../types'; +import { + getAngularModule, + getCore, + getDataPlugin, +} from '../../../kibana-services'; +import { MainSyscollector } from '../../agents/syscollector/main'; +import { MainAgentStats } from '../../agents/stats'; +import WzManagementConfiguration from '../../../controllers/management/components/management/configuration/configuration-main.js'; +import { getAgentsService } from '../services'; +import { ShareAgent } from '../../../factories/share-agent'; +import { updateCurrentAgentData } from '../../../redux/actions/appStateActions'; +import { endpointSummary } from '../../../utils/applications'; +import { withErrorBoundary, withReduxProvider } from '../../common/hocs'; +import { compose } from 'redux'; + +export const AgentView = compose( + withErrorBoundary, + withReduxProvider, +)(() => { + //TODO: Replace when implement React router + const $injector = getAngularModule().$injector; + const $router = $injector.get('$route'); + const $commonData = $injector.get('commonData'); + + const shareAgent = new ShareAgent(); + + //TODO: Replace with useDatasource and useSearchBar when replace WzDatePicker with SearchBar in AgentsWelcome component + const savedTimefilter = $commonData.getTimefilter(); + if (savedTimefilter) { + getDataPlugin().query.timefilter.timefilter.setTime(savedTimefilter); + $commonData.removeTimefilter(); + } + + const { agent: agentId } = $router.current.params; + + const [agent, setAgent] = useState(); + const [isLoadingAgent, setIsLoadingAgent] = useState(true); + const [tab, setTab] = useState($commonData.checkTabLocation()); + const dispatch = useDispatch(); + + const getAgent = async () => { + try { + setIsLoadingAgent(true); + + const id = $commonData.checkLocationAgentId( + agentId, + shareAgent.getAgent(), + ); + + if (!id) { + return; + } + + const { affected_items } = await getAgentsService({ + agents: [agentId], + }); + if (!affected_items?.length) { + throw 'Not found'; + } + + const agent = affected_items[0]; + setAgent(agent); + dispatch(updateCurrentAgentData(agent)); + } catch (error) { + const options = { + context: `AgentView.getAgent`, + level: UI_LOGGER_LEVELS.ERROR, + severity: UI_ERROR_SEVERITIES.CRITICAL, + store: true, + error: { + error, + message: error.message || error, + title: `Error getting the agent: ${error.message || error}`, + }, + }; + getErrorOrchestrator().handleError(options); + } finally { + setIsLoadingAgent(false); + } + }; + + useEffect(() => { + getAgent(); + }, [tab]); + + const switchTab = (tab: string) => { + setTab(tab); + getCore().application.navigateToApp(endpointSummary.id, { + path: `#/agents?tab=${tab}&agent=${agent?.id}`, + }); + }; + + if (isLoadingAgent) { + return ( + + + + + + ); + } + + if (tab === 'welcome') { + return ; + } + + if (tab === 'syscollector' && agent) { + return ; + } + + if (tab === 'stats' && agent) { + return ; + } + + if (tab === 'configuration' && agent) { + return ; + } +}); diff --git a/plugins/main/public/components/endpoints-summary/services/get-agents.tsx b/plugins/main/public/components/endpoints-summary/services/get-agents.tsx index ebe67f445e..5040a34335 100644 --- a/plugins/main/public/components/endpoints-summary/services/get-agents.tsx +++ b/plugins/main/public/components/endpoints-summary/services/get-agents.tsx @@ -4,11 +4,13 @@ import { Agent } from '../types'; export const getAgentsService = async ({ filters, + agents, limit, offset, pageSize = 1000, }: { - filters: any; + filters?: any; + agents?: string[]; limit?: number; offset?: number; pageSize?: number; @@ -27,7 +29,8 @@ export const getAgentsService = async ({ params: { limit: queryLimit, offset: queryOffset, - q: filters, + ...(agents?.length ? { agents_list: agents?.join(',') } : {}), + ...(filters ? { q: filters } : {}), wait_for_complete: true, }, })) as IApiResponse; diff --git a/plugins/main/public/controllers/agent/agents.js b/plugins/main/public/controllers/agent/agents.js deleted file mode 100644 index db8249dedc..0000000000 --- a/plugins/main/public/controllers/agent/agents.js +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Wazuh app - Agents controller - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ -import { FilterHandler } from '../../utils/filter-handler'; -import { TabNames } from '../../utils/tab-names'; -import { visualizations } from '../../templates/agents/visualizations'; - -import { ConfigurationHandler } from '../../utils/config-handler'; -import { AppState } from '../../react-services/app-state'; -import { WazuhConfig } from '../../react-services/wazuh-config'; -import { GenericRequest } from '../../react-services/generic-request'; -import { WzRequest } from '../../react-services/wz-request'; -import { - getToasts, - getDataPlugin, - getWazuhCorePlugin, -} from '../../kibana-services'; -import { ShareAgent } from '../../factories/share-agent'; -import { TabVisualizations } from '../../factories/tab-visualizations'; -import { formatUIDate } from '../../react-services/time-service'; -import { hasAgentSupportModule } from '../../react-services/wz-agents'; -import { UI_LOGGER_LEVELS } from '../../../common/constants'; -import { UI_ERROR_SEVERITIES } from '../../react-services/error-orchestrator/types'; -import { getErrorOrchestrator } from '../../react-services/common-services'; -import { updateCurrentAgentData } from '../../redux/actions/appStateActions'; -import store from '../../redux/store'; - -export class AgentsController { - /** - * Class constructor - * @param {Object} $scope - * @param {Object} $location - * @param {Object} $rootScope - * @param {Object} errorHandler - * @param {Object} commonData - * @param {Object} reportingService - * @param {Object} visFactoryService - * @param {Object} csvReq - */ - constructor( - $scope, - $location, - $rootScope, - errorHandler, - commonData, - reportingService, - visFactoryService, - csvReq, - ) { - this.$scope = $scope; - this.$location = $location; - this.$rootScope = $rootScope; - this.errorHandler = errorHandler; - this.tabVisualizations = new TabVisualizations(); - this.$scope.visualizations = visualizations; - this.shareAgent = new ShareAgent(); - this.commonData = commonData; - this.reportingService = reportingService; - this.visFactoryService = visFactoryService; - this.csvReq = csvReq; - this.wazuhConfig = new WazuhConfig(); - this.genericReq = GenericRequest; - - // Config on-demand - this.$scope.isArray = Array.isArray; - this.configurationHandler = new ConfigurationHandler(errorHandler); - this.$scope.currentConfig = null; - this.$scope.configurationTab = ''; - this.$scope.configurationSubTab = ''; - this.$scope.integrations = {}; - this.$scope.selectedItem = 0; - this.targetLocation = null; - this.ignoredTabs = ['syscollector', 'welcome', 'configuration', 'stats']; - - this.$scope.expandArray = [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - ]; - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - } - - /** - * On controller loads - */ - async $onInit() { - const savedTimefilter = this.commonData.getTimefilter(); - if (savedTimefilter) { - getDataPlugin().query.timefilter.timefilter.setTime(savedTimefilter); - this.commonData.removeTimefilter(); - } - - this.$rootScope.reportStatus = false; - - this.$location.search('_a', null); - this.filterHandler = new FilterHandler(AppState.getCurrentPattern()); - this.visFactoryService.clearAll(); - - // Getting possible target location - this.targetLocation = this.shareAgent.getTargetLocation(); - - if (this.targetLocation && typeof this.targetLocation === 'object') { - this.$scope.tabView = this.targetLocation.subTab; - this.$scope.tab = this.targetLocation.tab; - } else { - this.$scope.tabView = this.commonData.checkTabViewLocation(); - this.$scope.tab = this.commonData.checkTabLocation(); - } - this.tabHistory = []; - if (!this.ignoredTabs.includes(this.$scope.tab)) - this.tabHistory.push(this.$scope.tab); - - // Tab names - this.$scope.tabNames = TabNames; - - this.tabVisualizations.assign('agents'); - - /** - * This check if given array of items contais a single given item - * @param {Object} item - * @param {Array} array - */ - this.$scope.inArray = (item, array) => - item && Array.isArray(array) && array.includes(item); - - this.$scope.switchSubtab = async ( - subtab, - force = false, - onlyAgent = false, - ) => this.switchSubtab(subtab, force, onlyAgent); - - this.changeAgent = false; - - this.$scope.switchTab = (tab, force = false) => this.switchTab(tab, force); - this.$scope.getAgent = async newAgentId => this.getAgent(newAgentId); - this.$scope.goGroups = (agent, group) => this.goGroups(agent, group); - - this.$scope.search = (term, specificPath) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificPath, - }); - - this.$scope.searchSyscheckFile = (term, specificFilter) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificFilter, - }); - - this.$scope.searchRootcheck = (term, specificFilter) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificFilter, - }); - - this.$scope.shouldShowComponent = component => - this.shouldShowComponent(component); - - this.$scope.$on('$destroy', () => { - this.visFactoryService.clearAll(); - }); - - this.$scope.isArray = Array.isArray; - - this.$scope.goGroup = () => { - this.shareAgent.setAgent(this.$scope.agent); - this.$location.path('/manager/groups'); - }; - - this.$scope.exportConfiguration = enabledComponents => { - this.reportingService.startConfigReport( - this.$scope.agent, - 'agentConfig', - enabledComponents, - ); - }; - - //Load - try { - this.$scope.getAgent(); - } catch (error) { - const options = { - context: `${AgentsController.name}.$onInit`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: true, - error: { - error: error, - message: error.message || error, - title: `Error getting the agent: ${error.message || error}`, - }, - }; - getErrorOrchestrator().handleError(options); - } - - // Config on demand - this.$scope.getXML = () => this.configurationHandler.getXML(this.$scope); - this.$scope.getJSON = () => this.configurationHandler.getJSON(this.$scope); - this.$scope.isString = item => typeof item === 'string'; - this.$scope.hasSize = obj => - obj && typeof obj === 'object' && Object.keys(obj).length; - this.$scope.offsetTimestamp = (text, time) => - this.offsetTimestamp(text, time); - this.$scope.switchConfigTab = ( - configurationTab, - sections, - navigate = true, - ) => { - this.$scope.navigate = navigate; - try { - this.$scope.configSubTab = JSON.stringify({ - configurationTab: configurationTab, - sections: sections, - }); - if (!this.$location.search().configSubTab) { - AppState.setSessionStorageItem( - 'configSubTab', - this.$scope.configSubTab, - ); - this.$location.search('configSubTab', true); - } - } catch (error) { - const options = { - context: `${AgentsController.name}.switchConfigTab`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: true, - error: { - error: error, - message: error.message || error, - title: `${error.message || error} Set configuration path`, - }, - }; - getErrorOrchestrator().handleError(options); - } - this.configurationHandler.switchConfigTab( - configurationTab, - sections, - this.$scope, - this.$scope.agent.id, - ); - }; - - this.$scope.switchWodle = (wodleName, navigate = true) => { - this.$scope.navigate = navigate; - this.$scope.configWodle = wodleName; - if (!this.$location.search().configWodle) { - this.$location.search('configWodle', this.$scope.configWodle); - } - this.configurationHandler.switchWodle( - wodleName, - this.$scope, - this.$scope.agent.id, - ); - }; - - this.$scope.switchConfigurationTab = (configurationTab, navigate) => { - this.$scope.navigate = navigate; - this.configurationHandler.switchConfigurationTab( - configurationTab, - this.$scope, - ); - if (!this.$scope.navigate) { - const configSubTab = this.$location.search().configSubTab; - if (configSubTab) { - try { - const config = AppState.getSessionStorageItem('configSubTab'); - const configSubTabObj = JSON.parse(config); - this.$scope.switchConfigTab( - configSubTabObj.configurationTab, - configSubTabObj.sections, - false, - ); - } catch (error) { - throw new Error(error); - } - } else { - const configWodle = this.$location.search().configWodle; - if (configWodle) { - this.$scope.switchWodle(configWodle, false); - } - } - } else { - this.$location.search('configSubTab', null); - AppState.removeSessionStorageItem('configSubTab'); - this.$location.search('configWodle', null); - } - }; - this.$scope.switchConfigurationSubTab = configurationSubTab => { - this.configurationHandler.switchConfigurationSubTab( - configurationSubTab, - this.$scope, - ); - if (configurationSubTab === 'pm-sca') { - this.$scope.currentConfig.sca = this.configurationHandler.parseWodle( - this.$scope.currentConfig, - 'sca', - ); - } - }; - this.$scope.updateSelectedItem = i => (this.$scope.selectedItem = i); - this.$scope.getIntegration = list => - this.configurationHandler.getIntegration(list, this.$scope); - - this.$scope.$on('$routeChangeStart', () => { - return AppState.removeSessionStorageItem('configSubTab'); - }); - - this.$scope.expand = i => this.expand(i); - this.setTabs(); - } - - // Switch subtab - async switchSubtab(subtab, force = false, onlyAgent = false) { - try { - if (this.$scope.tabView === subtab && !force) return; - this.tabVisualizations.clearDeadVis(); - this.visFactoryService.clear(onlyAgent); - this.$location.search('tabView', subtab); - if ( - (subtab === 'panels' || - (this.targetLocation && - typeof this.targetLocation === 'object' && - this.targetLocation.subTab === 'discover' && - subtab === 'discover')) && - !this.ignoredTabs.includes(this.$scope.tab) - ) { - await this.visFactoryService.buildAgentsVisualizations( - this.filterHandler, - this.$scope.tab, - subtab, - this.$scope.agent.id, - ); - - this.changeAgent = false; - } else { - this.$scope.$emit('changeTabView', { - tabView: subtab, - tab: this.$scope.tab, - }); - } - this.$scope.tabView = subtab; - } catch (error) { - throw new Error(error); - } - } - - /** - * Switch tab - * @param {*} tab - * @param {*} force - */ - async switchTab(tab, force = false) { - const timefilter = getDataPlugin().query.timefilter.timefilter; - this.tabVisualizations.setTab(tab); - this.$rootScope.rendered = false; - this.$rootScope.$applyAsync(); - this.falseAllExpand(); - if (this.ignoredTabs.includes(tab)) { - this.commonData.setRefreshInterval(timefilter.getRefreshInterval()); - timefilter.setRefreshInterval({ - pause: true, - value: 0, - }); - } else if (this.ignoredTabs.includes(this.$scope.tab)) { - timefilter.setRefreshInterval(this.commonData.getRefreshInterval()); - } - - // Update agent status - if (!force && this.$scope.agent) { - try { - const agentInfo = await WzRequest.apiReq('GET', '/agents', { - params: { - agents_list: this.$scope.agent.id, - select: 'status', - }, - }); - this.$scope.agent.status = - agentInfo?.data?.data?.affected_items?.[0]?.status || - this.$scope.agent.status; - - this.$scope.$applyAsync(); - } catch (error) { - throw new Error(error); - } - } - - try { - if (tab === 'configuration') { - this.$scope.switchConfigurationTab('welcome'); - } else { - this.configurationHandler.reset(this.$scope); - } - - if (!this.ignoredTabs.includes(tab)) this.tabHistory.push(tab); - if (this.tabHistory.length > 2) - this.tabHistory = this.tabHistory.slice(-2); - - if (this.$scope.tab === tab && !force) { - this.$scope.$applyAsync(); - return; - } - - const onlyAgent = this.$scope.tab === tab && force; - const sameTab = this.$scope.tab === tab; - this.$location.search('tab', tab); - const preserveDiscover = - this.tabHistory.length === 2 && - this.tabHistory[0] === this.tabHistory[1] && - !force; - this.$scope.tab = tab; - - const targetSubTab = - this.targetLocation && typeof this.targetLocation === 'object' - ? this.targetLocation.subTab - : 'panels'; - - if (!this.ignoredTabs.includes(this.$scope.tab)) { - this.$scope.switchSubtab( - targetSubTab, - true, - onlyAgent, - sameTab, - preserveDiscover, - ); - } - - this.shareAgent.deleteTargetLocation(); - this.targetLocation = null; - this.$scope.$applyAsync(); - } catch (error) { - const options = { - context: `${AgentsController.name}.switchTab`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.CRITICAL, - store: true, - error: { - error: error, - message: error.message || error, - title: error.message || error, - }, - }; - getErrorOrchestrator().handleError(options); - } - - this.$scope.configurationTabsProps = {}; - this.$scope.buildProps = tabs => { - const cleanTabs = []; - tabs.forEach(x => { - if ( - this.$scope.configurationTab === 'integrity-monitoring' && - x.id === 'fim-whodata' && - x.agent && - x.agent.agentPlatform !== 'linux' - ) - return; - - cleanTabs.push({ - id: x.id, - name: x.name, - }); - }); - this.$scope.configurationTabsProps = { - clickAction: tab => { - this.$scope.switchConfigurationSubTab(tab); - }, - selectedTab: - this.$scope.configurationSubTab || (tabs && tabs.length) - ? tabs[0].id - : '', - tabs: cleanTabs, - }; - }; - - this.setTabs(); - } - - /** - * Filter by Mitre.ID - * @param {*} id - */ - addMitrefilter(id) { - const filter = `{"meta":{"index": ${ - AppState.getCurrentPattern() || - getWazuhCorePlugin().configuration.getSettingValue('pattern') - }},"query":{"match":{"rule.mitre.id":{"query":"${id}","type":"phrase"}}}}`; - this.$rootScope.$emit('addNewKibanaFilter', { - filter: JSON.parse(filter), - }); - } - - /** - * Build the current section tabs - */ - setTabs() { - this.$scope.agentsTabsProps = false; - if (this.$scope.agent) { - this.currentPanel = this.commonData.getCurrentPanel( - this.$scope.tab, - true, - ); - - if (!this.currentPanel) return; - - const tabs = this.commonData.getTabsFromCurrentPanel( - this.currentPanel, - this.$scope.tabNames, - ); - - const cleanTabs = []; - tabs.forEach(x => { - if (!hasAgentSupportModule(this.$scope.agent, x.id)) return; - - cleanTabs.push({ - id: x.id, - name: x.name, - }); - }); - - this.$scope.agentsTabsProps = { - clickAction: tab => { - this.switchTab(tab, true); - }, - selectedTab: - this.$scope.tab || - (this.currentPanel && this.currentPanel.length - ? this.currentPanel[0] - : ''), - tabs: cleanTabs, - }; - this.$scope.$applyAsync(); - } - } - - showToast = (color, title, text, time) => { - getToasts().add({ - color: color, - title: title, - text: text, - toastLifeTimeMs: time, - }); - }; - - // Agent data - - /** - * Checks rootcheck of selected agent - */ - validateRootCheck() { - const result = this.commonData.validateRange(this.$scope.agent.rootcheck); - this.$scope.agent.rootcheck = result; - } - - /** - * Checks syscheck of selected agent - */ - validateSysCheck() { - const result = this.commonData.validateRange(this.$scope.agent.syscheck); - this.$scope.agent.syscheck = result; - } - - /** - * Get the needed data for load syscollector - * @param {*} id - */ - async loadSyscollector(id) { - try { - const syscollectorData = await this.genericReq.request( - 'GET', - `/api/syscollector/${id}`, - ); - this.$scope.syscollector = syscollectorData?.data || {}; - return; - } catch (error) { - throw new Error(error); - } - } - - /** - * Get all data from agent - * @param {*} newAgentId - */ - async getAgent(newAgentId) { - try { - this.$scope.emptyAgent = false; - this.$scope.load = true; - this.changeAgent = true; - - const globalAgent = this.shareAgent.getAgent(); - - const id = this.commonData.checkLocationAgentId(newAgentId, globalAgent); - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - - if (!id) { - this.$scope.load = false; - // We set some properties used by the rendered component to work and allowing - // to manage when there is not selected agent. - await this.$scope.switchTab(this.$scope.tab, true); - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - this.$scope.$applyAsync(); - return; - } - - const data = await WzRequest.apiReq('GET', `/agents`, { - params: { - agents_list: id, - }, - }); - - const agentInfo = data?.data?.data?.affected_items[0] || false; - // Agent - this.$scope.agent = agentInfo; - - if (!this.$scope.agent) return; - - // Sync the selected agent on Redux store - if ( - store.getState().appStateReducers.currentAgentData.id !== - this.$scope.agent.id - ) { - store.dispatch(updateCurrentAgentData(this.$scope.agent)); - } - - if (agentInfo && this.$scope.agent.os) { - this.$scope.agentOS = - this.$scope.agent.os.name + ' ' + this.$scope.agent.os.version; - const isLinux = this.$scope.agent.os.uname.includes('Linux'); - this.$scope.agent.agentPlatform = isLinux - ? 'linux' - : this.$scope.agent.os.platform; - } else { - this.$scope.agentOS = '-'; - this.$scope.agent.agentPlatform = false; - } - - await this.$scope.switchTab(this.$scope.tab, true); - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - this.$scope.load = false; - this.$scope.$applyAsync(); - return; - } catch (error) { - if (!this.$scope.agent) { - if ((error || {}).status === -1) { - this.$scope.emptyAgent = 'API timeout.'; - } - } - if ( - error && - typeof error === 'string' && - error.includes('Agent does not exist') - ) { - this.$location.search('agent', null); - this.$location.path('/agents-preview'); - } - this.$scope.load = false; - this.$scope.$applyAsync(); - throw new Error(error); - } - } - - shouldShowComponent(component) { - return hasAgentSupportModule(this.$scope.agent, component); - } - - setAgent(agent) { - this.$scope.agent = agent; - } - /** - * Get available welcome cards after getting the agent - */ - loadWelcomeCardsProps() { - this.$scope.welcomeCardsProps = { - switchTab: (tab, force) => this.switchTab(tab, force), - agent: this.$scope.agent, - api: AppState.getCurrentAPI(), - setAgent: agent => this.setAgent(agent), - goGroups: (agent, group) => this.goGroups(agent, group), - }; - } - - /** - * This adds timezone offset to a given date - * @param {String} binding_text - * @param {String} date - */ - offsetTimestamp(text, time) { - try { - return text + formatUIDate(time); - } catch (error) { - const options = { - context: `${AgentsController.name}.offsetTimestamp`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: false, - error: { - error: error, - message: error.message || error, - title: error.message || error, - }, - }; - getErrorOrchestrator().handleError(options); - return time !== '-' ? `${text}${time} (UTC)` : time; - } - } - - /** - * Navigate to the groups of an agent - * @param {*} agent - * @param {*} group - */ - goGroups(agent, group) { - AppState.setNavigation({ - status: true, - }); - this.visFactoryService.clearAll(); - this.shareAgent.setAgent(agent, group); - this.$location.search('tab', 'groups'); - this.$location.search('navigation', true); - this.$location.path('/manager'); - } - - falseAllExpand() { - this.$scope.expandArray = [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - ]; - } - - expand(i) { - const oldValue = this.$scope.expandArray[i]; - this.falseAllExpand(); - this.$scope.expandArray[i] = !oldValue; - } -} diff --git a/plugins/main/public/controllers/agent/components/export-configuration.js b/plugins/main/public/controllers/agent/components/export-configuration.js deleted file mode 100644 index 0c3ee40f33..0000000000 --- a/plugins/main/public/controllers/agent/components/export-configuration.js +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Wazuh app - React component for exporting the configuration of a group. - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ -import React, { Component } from 'react'; - -import { - EuiPopover, - EuiButton, - EuiCheckboxGroup, - EuiSpacer, - EuiButtonEmpty -} from '@elastic/eui'; - -import PropTypes from 'prop-types'; -import { UnsupportedComponents } from '../../../utils/components-os-support'; -import { WAZUH_AGENTS_OS_TYPE } from '../../../../common/constants'; -import { withErrorBoundary } from '../../../components/common/hocs'; - -export const ExportConfiguration = withErrorBoundary (class ExportConfiguration extends Component { - constructor(props) { - super(props); - - this.state = { - buttonDisabled: false, - isPopoverOpen: false - }; - - const agentOptions = [ - 'Global configuration', - 'Communication', - 'Anti-flooding settings', - 'Labels', - 'Policy monitoring', - { name: 'oscap', desc: 'OpenSCAP' }, - 'CIS-CAT', - 'Osquery', - 'Inventory data', - 'Active response', - 'Commands', - { name: 'docker', desc: 'Docker listener' }, - 'Log collection', - 'Integrity monitoring' - ]; - const groupOptions = ['Configurations', 'Agents in group']; - - this.options = []; - const list = this.props.type === 'agent' ? agentOptions : groupOptions; - list.forEach((x, idx) => { - if ( - typeof x === 'string' || - (x.name && - !( - UnsupportedComponents[this.props.agentPlatform] || - UnsupportedComponents[WAZUH_AGENTS_OS_TYPE.OTHERS] - ).includes(x.name)) - ) { - this.options.push({ id: `${idx}`, label: x.desc || x }); - } - }); - - let initialChecks = {}; - this.options.forEach(x => { - initialChecks[x.id] = true; - }); - this.state.checkboxIdToSelectedMap = initialChecks; - } - - selectAll(flag) { - let newCheckboxIdToSelectedMap = {}; - for (let i = 0; i < this.options.length; i++) { - newCheckboxIdToSelectedMap[`${this.options[i].id}`] = flag; - } - this.setState({ - checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, - buttonDisabled: !flag - }); - } - - exportClick() { - this.setState({ - isPopoverOpen: !this.state.isPopoverOpen - }); - } - - closePopover() { - this.setState({ - isPopoverOpen: false - }); - } - - onChange = optionId => { - const newCheckboxIdToSelectedMap = { - ...this.state.checkboxIdToSelectedMap, - ...{ - [optionId]: !this.state.checkboxIdToSelectedMap[optionId] - } - }; - let result = false; - for (let i = 0; i < this.options.length; i++) { - if (newCheckboxIdToSelectedMap[`${this.options[i].id}`] === true) { - result = true; - } - } - this.setState({ - checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, - buttonDisabled: !result - }); - }; - - render() { - const button = ( - - Export PDF - - ); - return ( - - - - {this.options.length > 3 && - <> this.selectAll(true)}> - Select all - this.selectAll(false)}> - Unselect all - } - - { - this.closePopover(); - this.props.exportConfiguration(this.state.checkboxIdToSelectedMap); - }} - fill - > - Generate PDF report - - - ); - } -}); - -ExportConfiguration.propTypes = { - exportConfiguration: PropTypes.func, - type: PropTypes.string, - agentPlatform: PropTypes.string -}; diff --git a/plugins/main/public/controllers/agent/index.js b/plugins/main/public/controllers/agent/index.js index 960ac79295..cb75bf45d0 100644 --- a/plugins/main/public/controllers/agent/index.js +++ b/plugins/main/public/controllers/agent/index.js @@ -9,28 +9,16 @@ * * Find more information about this on the LICENSE file. */ -import { AgentsController } from './agents'; import { RegisterAgent } from '../../components/endpoints-summary/register-agent/containers/register-agent/register-agent'; -import { ExportConfiguration } from './components/export-configuration'; -import { AgentsWelcome } from '../../components/common/welcome/agents-welcome'; -import { Mitre } from '../../components/overview'; -import { AgentsTable } from '../../components/endpoints-summary/table/agents-table'; import { MainModule } from '../../components/common/modules/main'; -import { MainSyscollector } from '../../components/agents/syscollector/main'; -import { MainAgentStats } from '../../components/agents/stats'; import { getAngularModule } from '../../kibana-services'; import { MainEndpointsSummary } from '../../components/endpoints-summary'; +import { AgentView } from '../../components/endpoints-summary/agent'; const app = getAngularModule(); app - .controller('agentsController', AgentsController) .value('RegisterAgent', RegisterAgent) - .value('ExportConfiguration', ExportConfiguration) - .value('AgentsWelcome', AgentsWelcome) - .value('Mitre', Mitre) - .value('AgentsTable', AgentsTable) - .value('MainSyscollector', MainSyscollector) - .value('MainAgentStats', MainAgentStats) + .value('AgentView', AgentView) .value('MainModule', MainModule) .value('MainEndpointsSummary', MainEndpointsSummary); diff --git a/plugins/main/public/controllers/management/components/files-group-table.js b/plugins/main/public/controllers/management/components/files-group-table.js index 5736923a07..61ff65dd56 100644 --- a/plugins/main/public/controllers/management/components/files-group-table.js +++ b/plugins/main/public/controllers/management/components/files-group-table.js @@ -21,10 +21,10 @@ import { EuiTitle, EuiButtonEmpty, EuiText, - EuiToolTip + EuiToolTip, } from '@elastic/eui'; -import { ExportConfiguration } from '../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../components/agents/export-configuration'; import { ReportingService } from '../../../react-services/reporting'; export class FilesInGroupTable extends Component { @@ -36,7 +36,7 @@ export class FilesInGroupTable extends Component { groupName: this.props.group.name || 'Group', files: [], originalfiles: [], - isLoading: false + isLoading: false, }; this.filters = { name: 'search', value: '' }; @@ -47,7 +47,7 @@ export class FilesInGroupTable extends Component { const files = await this.props.getFilesFromGroup(this.props.group.name); this.setState({ files: files, - originalfiles: files + originalfiles: files, }); } catch (error) { console.error('error mounting the component ', error); @@ -66,7 +66,7 @@ export class FilesInGroupTable extends Component { : this.state.originalfiles; this.setState({ isLoading: false, - files: items + files: items, }); } }; @@ -80,7 +80,7 @@ export class FilesInGroupTable extends Component { const files = await this.props.getFilesFromGroup(this.props.group.name); this.setState({ originalfiles: files, - refreshingFiles: false + refreshingFiles: false, }); } catch (error) { this.setState({ refreshingFiles: false }); @@ -93,45 +93,45 @@ export class FilesInGroupTable extends Component { { field: 'filename', name: 'File', - sortable: true + sortable: true, }, { field: 'hash', name: 'Checksum', - sortable: true + sortable: true, }, { name: 'Actions', render: item => { return ( - + + aria-label='See file content' + onClick={() => this.props.openFileContent( this.state.groupName, - item.filename + item.filename, ) } - iconType="eye" + iconType='eye' /> ); - } - } + }, + }, ]; const search = { onChange: this.onQueryChange, box: { incremental: this.state.incremental, - schema: true - } + schema: true, + }, }; return ( - + @@ -144,8 +144,8 @@ export class FilesInGroupTable extends Component { this.props.editConfig()} > Edit group configuration @@ -157,7 +157,7 @@ export class FilesInGroupTable extends Component { this.reportingService.startConfigReport( this.props.state.itemDetail, 'groupConfig', - enabledComponents + enabledComponents, ) } type='group' @@ -165,7 +165,7 @@ export class FilesInGroupTable extends Component { await this.props.export(this.state.groupName, [this.filters]) } @@ -174,21 +174,21 @@ export class FilesInGroupTable extends Component { - this.refresh()}> + this.refresh()}> Refresh - + From here you can list and see your group files, also, you can edit the group configuration )) || )} @@ -493,12 +492,12 @@ export default compose( props.agent.id === '000' ? { action: 'manager:read', resource: '*:*:*' } : [ - { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, - ...(props.agent.group || []).map(group => ({ - action: 'agent:read', - resource: `agent:group:${group}`, - })), - ], + { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, + ...(props.agent.group || []).map(group => ({ + action: 'agent:read', + resource: `agent:group:${group}`, + })), + ], ]), //TODO: this need cluster:read permission but manager/cluster is managed in WzConfigurationSwitch component withRenderIfOrWrapped( props => props.agent.status === API_NAME_AGENT_STATUS.NEVER_CONNECTED, diff --git a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js index fa3ffc0a7d..4f3d377178 100644 --- a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js +++ b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js @@ -18,7 +18,7 @@ import { connect } from 'react-redux'; import { updateShowAddAgents } from '../../../../../redux/actions/groupsActions'; import GroupsHandler from './utils/groups-handler'; -import { ExportConfiguration } from '../../../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../../../components/agents/export-configuration'; import { ReportingService } from '../../../../../react-services/reporting'; class WzGroupsActionButtonsAgents extends Component { diff --git a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js index 32a7bec71c..cfb6defa34 100644 --- a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js +++ b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js @@ -18,7 +18,7 @@ import { connect } from 'react-redux'; import { updateFileContent } from '../../../../../redux/actions/groupsActions'; import GroupsHandler from './utils/groups-handler'; -import { ExportConfiguration } from '../../../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../../../components/agents/export-configuration'; import { WzButtonPermissions } from '../../../../../components/common/permissions/button'; import { ReportingService } from '../../../../../react-services/reporting'; diff --git a/plugins/main/public/templates/agents/dashboards.html b/plugins/main/public/templates/agents/dashboards.html index 33fe5c8c5e..93330667b7 100644 --- a/plugins/main/public/templates/agents/dashboards.html +++ b/plugins/main/public/templates/agents/dashboards.html @@ -1,138 +1 @@ - -
-
- -
- - - -
-
-
- -
-
-
- - -
-
- -
-
-
-
- -
-
-
- -
- -
- - -
-
-
- - - - - - -
-
{{loadingStatus}}
-
-
- - -
-
-
- - - - - - -
-
{{reportStatus}}
-
-
-
- -
- -
- - -
-
- -
-
-
- - -
- -
- - -
- -
- - -
+ diff --git a/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts b/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts index 27db0c5f70..20e62748bd 100644 --- a/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts +++ b/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts @@ -24,7 +24,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -57,7 +62,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -105,7 +116,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -138,7 +154,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -186,7 +208,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -219,7 +246,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -267,7 +300,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -300,7 +338,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -348,7 +392,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -381,7 +430,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -429,7 +484,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -462,7 +522,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -496,106 +562,4 @@ export default [ }, }, }, - { - _id: 'Wazuh-App-Agents-Welcome-Events-Evolution', - _type: 'visualization', - _source: { - title: 'Events evolution', - visState: JSON.stringify({ - title: 'event evolution', - type: 'line', - params: { - type: 'line', - grid: { categoryLines: false }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', - show: true, - style: {}, - scale: { type: 'linear' }, - labels: { show: true, filter: true, truncate: 100 }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: 'value', - position: 'left', - show: true, - style: {}, - scale: { type: 'linear', mode: 'normal' }, - labels: { show: true, rotate: 0, filter: false, truncate: 100 }, - title: { text: 'Count' }, - }, - ], - seriesParams: [ - { - show: true, - type: 'line', - mode: 'normal', - data: { label: 'Count', id: '1' }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - lineWidth: 2, - interpolate: 'linear', - showCircles: true, - }, - ], - addTooltip: true, - addLegend: false, - legendPosition: 'right', - times: [], - addTimeMarker: false, - labels: {}, - thresholdLine: { show: false, value: 10, width: 1, style: 'full', color: '#E7664C' }, - dimensions: { - x: null, - y: [ - { - accessor: 0, - format: { id: 'number' }, - params: {}, - label: 'Count', - aggType: 'count', - }, - ], - }, - }, - aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, - { - id: '2', - enabled: true, - type: 'date_histogram', - schema: 'segment', - params: { - field: 'timestamp', - useNormalizedEsInterval: true, - scaleMetricValues: false, - interval: 'auto', - drop_partials: false, - min_doc_count: 1, - extended_bounds: {}, - }, - }, - ], - }), - uiStateJSON: JSON.stringify({ - vis: { params: { sort: { columnIndex: 2, direction: 'desc' } } }, - }), - description: '', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'wazuh-alerts', - query: { query: '', language: 'lucene' }, - filter: [], - }), - }, - }, - }, ];