diff --git a/plugins/main/public/components/common/modules/modules-defaults.tsx b/plugins/main/public/components/common/modules/modules-defaults.tsx
index 9dffb7e294..a340bb86a8 100644
--- a/plugins/main/public/components/common/modules/modules-defaults.tsx
+++ b/plugins/main/public/components/common/modules/modules-defaults.tsx
@@ -18,7 +18,11 @@ import { ComplianceTable } from '../../overview/compliance-table';
import { ButtonModuleGenerateReport } from '../modules/buttons';
import { OfficePanel } from '../../overview/office/panel';
import { GitHubPanel } from '../../overview/github/panel';
-import { DashboardVuls, InventoryVuls } from '../../overview/vulnerabilities';
+// import { InventoryVuls } from '../../overview/vulnerabilities';
+import {
+ DashboardVuls,
+ InventoryVuls,
+} from '../../overview/poc-dashboards-by-reference/dashboards';
import { DashboardMITRE } from '../../overview/mitre/dashboard';
import { withModuleNotForAgent } from '../hocs';
import {
@@ -86,7 +90,6 @@ const renderDiscoverTab = (props: WazuhDiscoverProps) => {
component: () => ,
};
};
-
export const ModulesDefaults = {
general: {
init: 'events',
@@ -245,6 +248,23 @@ export const ModulesDefaults = {
vuls: {
init: 'dashboard',
tabs: [
+ // {
+ // id: 'dashboard',
+ // name: 'Dashboard',
+ // component: DashboardSavedObject,
+ // /* For ButtonExploreAgent to insert correctly according to the module's index pattern, the moduleIndexPatternTitle parameter is added. By default it applies the index patternt wazuh-alerts-* */
+ // buttons: [
+ // (...props) => {
+ // console.log('ButtonExploreAgent Props in vuls:', props);
+ // return (
+ //
+ // );
+ // },
+ // ],
+ // },
{
id: 'dashboard',
name: 'Dashboard',
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/check-module-enabled.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/check-module-enabled.tsx
new file mode 100644
index 0000000000..f254dbde95
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/check-module-enabled.tsx
@@ -0,0 +1,115 @@
+import React, { useEffect, useState } from 'react';
+import {
+ clusterReq,
+ clusterNodes,
+} from '../../../../../controllers/management/components/management/configuration/utils/wz-fetch';
+import { WzRequest } from '../../../../../react-services';
+import { webDocumentationLink } from '../../../../../../common/services/web_documentation';
+import { EuiCallOut, EuiLink } from '@elastic/eui';
+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 { useUserPermissionsRequirements } from '../../../../common/hooks';
+
+async function checkVDIsEnabledCluster() {
+ // Get nodes
+ const responseNodes = await clusterNodes();
+
+ const nodes = responseNodes.data.data.affected_items.map(({ name }) => name);
+
+ // Check if at least some of the nodes has the module enabled
+ for (const node of nodes) {
+ const responseNodeWmodules = await WzRequest.apiReq(
+ 'GET',
+ `/cluster/${node}/configuration/wmodules/wmodules`,
+ {},
+ );
+ const vdConfiguration =
+ responseNodeWmodules.data.data?.affected_items?.[0]?.wmodules?.find(
+ ({ ['vulnerability-detection']: wmodule }) => wmodule,
+ );
+ if (vdConfiguration?.['vulnerability-detection']?.enabled === 'yes') {
+ return true;
+ }
+ }
+ return false;
+}
+
+async function checkVDIsEnabledManager() {
+ const responseWmodules = await WzRequest.apiReq(
+ 'GET',
+ `/manager/configuration/wmodules/wmodules`,
+ {},
+ );
+
+ const vdConfiguration =
+ responseWmodules.data.data?.affected_items?.[0]?.wmodules?.find(
+ ({ ['vulnerability-detection']: wmodule }) => wmodule,
+ );
+ return vdConfiguration?.['vulnerability-detection']?.enabled === 'yes';
+}
+
+export const ModuleEnabledCheck = () => {
+ const [data, setData] = useState<{ enabled: boolean } | null>(null);
+ const [userPermissionRequirements] = useUserPermissionsRequirements([
+ { action: 'cluster:status', resource: '*:*:*' },
+ { action: 'cluster:read', resource: 'node:id:*' },
+ { action: 'manager:read', resource: '*:*:*' },
+ ]);
+
+ const checkVDIsEnabled = async () => {
+ try {
+ // Check cluster status
+ setData(null);
+ const clusterStatus = await clusterReq();
+
+ // Check if the module is enabled
+ const enabled =
+ clusterStatus.data.data.enabled === 'yes' &&
+ clusterStatus.data.data.running === 'yes'
+ ? await checkVDIsEnabledCluster()
+ : await checkVDIsEnabledManager();
+ setData({ enabled });
+ } catch (error) {
+ const options = {
+ context: `${ModuleEnabledCheck.name}.useEffect`,
+ level: UI_LOGGER_LEVELS.ERROR,
+ severity: UI_ERROR_SEVERITIES.BUSINESS,
+ error: {
+ error: error,
+ message: error.message || error,
+ title: 'Error checking if the module is enabled',
+ },
+ };
+ getErrorOrchestrator().handleError(options);
+ }
+ };
+
+ useEffect(() => {
+ /* Only check if the module is enabled if the user has the expected permissions to
+ do the API requests */
+ if (!userPermissionRequirements) {
+ checkVDIsEnabled();
+ }
+ }, [userPermissionRequirements]);
+
+ return data?.enabled === false ? (
+
+
+ Vulnerabilies detection module is not enabled. You can learn to how to
+ configure following the{' '}
+
+ documentation
+
+ .
+
+
+ ) : null;
+};
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/document-view-table-and-json.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/document-view-table-and-json.tsx
new file mode 100644
index 0000000000..c82e73eef8
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/document-view-table-and-json.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { EuiFlexItem, EuiCodeBlock, EuiTabbedContent } from '@elastic/eui';
+import { IndexPattern } from '../../../../../../../../src/plugins/data/common';
+import DocViewer from '../../../../common/doc-viewer/doc-viewer';
+import { useDocViewer } from '../../../../common/doc-viewer';
+
+export const DocumentViewTableAndJson = ({ document, indexPattern }) => {
+ const docViewerProps = useDocViewer({
+ doc: document,
+ indexPattern: indexPattern as IndexPattern,
+ });
+
+ return (
+
+ ,
+ },
+ {
+ id: 'json',
+ name: 'JSON',
+ content: (
+
+ {JSON.stringify(document, null, 2)}
+
+ ),
+ },
+ ]}
+ />
+
+ );
+};
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.scss b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.scss
new file mode 100644
index 0000000000..051ab642c1
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.scss
@@ -0,0 +1,4 @@
+.discoverNoResults {
+ display: flex;
+ align-items: center;
+}
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.tsx
new file mode 100644
index 0000000000..7f505e6167
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/loading_spinner.tsx
@@ -0,0 +1,21 @@
+import './loading_spinner.scss';
+import React from 'react';
+import { EuiTitle, EuiPanel, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui';
+import { FormattedMessage } from '@osd/i18n/react';
+
+export function LoadingSpinner() {
+ return (
+
+ }
+ title={
+
+
+
+
+
+ }
+ />
+
+ );
+}
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/no_results.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/no_results.tsx
new file mode 100644
index 0000000000..babfd51d32
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/components/no_results.tsx
@@ -0,0 +1,60 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ *
+ * Any modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { FormattedMessage, I18nProvider } from '@osd/i18n/react';
+
+import { EuiCallOut, EuiPanel } from '@elastic/eui';
+
+interface Props {
+ message?: string;
+}
+
+export const DiscoverNoResults = ({ message }: Props) => {
+ return (
+
+
+
+ )
+ }
+ color='warning'
+ iconType='help'
+ data-test-subj='discoverNoResults'
+ />
+
+
+ );
+};
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hocs/validate-vulnerabilities-states-index-pattern.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hocs/validate-vulnerabilities-states-index-pattern.tsx
new file mode 100644
index 0000000000..c5c819eab2
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hocs/validate-vulnerabilities-states-index-pattern.tsx
@@ -0,0 +1,161 @@
+import React from 'react';
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import { withGuardAsync } from '../../../../common/hocs';
+import { getSavedObjects } from '../../../../../kibana-services';
+import { SavedObject } from '../../../../../react-services';
+import { NOT_TIME_FIELD_NAME_INDEX_PATTERN } from '../../../../../../common/constants';
+import { EuiButton, EuiEmptyPrompt, EuiLink } from '@elastic/eui';
+import { webDocumentationLink } from '../../../../../../common/services/web_documentation';
+import { vulnerabilityDetection } from '../../../../../utils/applications';
+import { LoadingSpinnerDataSource } from '../../../../common/loading/loading-spinner-data-source';
+import NavigationService from '../../../../../react-services/navigation-service';
+
+const INDEX_PATTERN_CREATION_NO_INDEX = 'INDEX_PATTERN_CREATION_NO_INDEX';
+
+async function checkExistenceIndexPattern(indexPatternID: string) {
+ return await getSavedObjects().client.get('index-pattern', indexPatternID);
+}
+
+async function checkExistenceIndices(indexPatternId: string) {
+ try {
+ const fields = await SavedObject.getIndicesFields(indexPatternId);
+ return { exist: true, fields };
+ } catch (error) {
+ return { exist: false };
+ }
+}
+
+async function createIndexPattern(indexPattern, fields: any) {
+ try {
+ await SavedObject.createSavedObject(
+ 'index-pattern',
+ indexPattern,
+ {
+ attributes: {
+ title: indexPattern,
+ timeFieldName: NOT_TIME_FIELD_NAME_INDEX_PATTERN,
+ },
+ },
+ fields,
+ );
+ await SavedObject.validateIndexPatternSavedObjectCanBeFound([indexPattern]);
+ } catch (error) {
+ return { error: error.message };
+ }
+}
+
+export async function validateVulnerabilitiesStateDataSources({
+ vulnerabilitiesStatesindexPatternID: indexPatternID,
+}) {
+ try {
+ // Check the existence of related index pattern
+ const existIndexPattern = await checkExistenceIndexPattern(indexPatternID);
+ let indexPattern = existIndexPattern;
+
+ // If the idnex pattern does not exist, then check the existence of index
+ if (existIndexPattern?.error?.statusCode === 404) {
+ // Check the existence of indices
+ const { exist, fields } = await checkExistenceIndices(indexPatternID);
+
+ if (!exist) {
+ return {
+ ok: true,
+ data: {
+ error: {
+ title:
+ 'Vulnerability detection seems to be disabled or has a problem',
+ type: INDEX_PATTERN_CREATION_NO_INDEX,
+ },
+ },
+ };
+ }
+ // If the some index match the index pattern, then create the index pattern
+ const resultCreateIndexPattern = await createIndexPattern(
+ indexPatternID,
+ fields,
+ );
+ if (resultCreateIndexPattern?.error) {
+ return {
+ ok: true,
+ data: {
+ error: {
+ title: 'There was a problem creating the index pattern',
+ message: resultCreateIndexPattern?.error,
+ },
+ },
+ };
+ }
+ /* WORKAROUND: Redirect to the root of Vulnerabilities Detection application that should
+ redirects to the Dashboard tab. We want to redirect to this view, because we need the
+ component is visible (visualizations) to ensure the process that defines the filters for the
+ Events tab is run when the Dashboard component is unmounted. This workaround solves a
+ problem in the Events tabs related there are no implicit filters when accessing if the HOC
+ that protect the view is passed.
+ */
+ NavigationService.getInstance().navigateToApp(vulnerabilityDetection.id);
+ }
+ return {
+ ok: false,
+ data: { indexPattern },
+ };
+ } catch (error) {
+ return {
+ ok: true,
+ data: {
+ error: { title: 'There was a problem', message: error.message },
+ },
+ };
+ }
+}
+
+const errorPromptBody = {
+ INDEX_PATTERN_CREATION_NO_INDEX: (
+
+ Please check the cluster status. Also, you can check the{' '}
+
+ vulnerability detection documentation.
+
+
+ ),
+};
+
+export const PromptCheckIndex = props => {
+ const { refresh } = props;
+ const { title, message } = props?.error;
+ const body = errorPromptBody?.[props?.error?.type] || {message}
;
+
+ return (
+ {title}}
+ body={body}
+ actions={
+
+ Refresh
+
+ }
+ />
+ );
+};
+
+const mapStateToProps = state => ({
+ vulnerabilitiesStatesindexPatternID:
+ state.appConfig.data['vulnerabilities.pattern'],
+});
+
+export const withVulnerabilitiesStateDataSource = compose(
+ connect(mapStateToProps),
+ withGuardAsync(
+ validateVulnerabilitiesStateDataSources,
+ ({ error, check }) => ,
+ () => ,
+ ),
+);
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hooks/useCheckIndexFields.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hooks/useCheckIndexFields.tsx
new file mode 100644
index 0000000000..c8ba68c25f
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/common/hooks/useCheckIndexFields.tsx
@@ -0,0 +1,46 @@
+import { useState, useEffect } from 'react';
+import { SavedObject } from '../../../../../react-services';
+
+interface UseCheckIndexFieldsResult {
+ isLoading: boolean;
+ isSuccess: boolean;
+ isError: boolean;
+ error: Error | null;
+ resultIndexData: any;
+}
+
+const useCheckIndexFields = (indexPatternId: string, indexType: string) => {
+ const [isError, setIsError] = useState(false);
+ const [error, setError] = useState(null);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ if (indexPatternId) {
+ const checkIndexFields = async () => {
+ try {
+ // Check that the index exists
+ await SavedObject.getIndicesFields(indexPatternId, indexType);
+ setIsSuccess(true);
+ setIsLoading(false);
+ } catch (error) {
+ setError(error);
+ setIsError(true);
+ setIsSuccess(false);
+ setIsLoading(false);
+ }
+ };
+
+ checkIndexFields();
+ }
+ }, [indexPatternId, indexType]);
+
+ return {
+ isError,
+ error,
+ isSuccess,
+ isLoading,
+ } as UseCheckIndexFieldsResult;
+};
+
+export default useCheckIndexFields;
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/index.ts b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/index.ts
new file mode 100644
index 0000000000..a3071fa116
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/index.ts
@@ -0,0 +1,2 @@
+export * from './overview';
+export * from './inventory';
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/config/index.ts b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/config/index.ts
new file mode 100644
index 0000000000..c0c9506fbe
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/config/index.ts
@@ -0,0 +1,24 @@
+import { EuiDataGridColumn } from '@elastic/eui';
+
+export const MAX_ENTRIES_PER_QUERY = 10000;
+
+export const inventoryTableDefaultColumns: EuiDataGridColumn[] = [
+ {
+ id: 'agent.name',
+ },
+ {
+ id: 'package.name',
+ },
+ {
+ id: 'package.version',
+ },
+ {
+ id: 'vulnerability.description',
+ },
+ {
+ id: 'vulnerability.severity',
+ },
+ {
+ id: 'vulnerability.id',
+ },
+];
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/index.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/index.tsx
new file mode 100644
index 0000000000..ddb0742f5e
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/index.tsx
@@ -0,0 +1 @@
+export * from './inventory';
\ No newline at end of file
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.scss b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.scss
new file mode 100644
index 0000000000..4844141f13
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.scss
@@ -0,0 +1,27 @@
+.vulsInventoryContainer {
+ height: calc(100vh - 104px);
+
+ .euiDataGrid__virtualized {
+ height: max-content !important;
+ }
+
+ // This makes the table not generate an unnecessary scroll when filtering data from 1 page and then do another search for more pages.
+ .vulsInventoryDataGrid {
+ height: calc(100vh - 216px) !important;
+ }
+
+ .euiDataGrid--fullScreen {
+ height: calc(100vh - 49px);
+ bottom: 0;
+ top: auto;
+
+ .euiDataGrid__virtualized {
+ height: calc(100vh - 147px) !important;
+ width: 100% !important;
+ }
+ }
+}
+
+.headerIsExpanded .vulsInventoryContainer {
+ height: calc(100vh - 153px);
+}
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.tsx
new file mode 100644
index 0000000000..2bb5edc065
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/inventory/inventory.tsx
@@ -0,0 +1,275 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { IntlProvider } from 'react-intl';
+import {
+ EuiDataGrid,
+ EuiPageTemplate,
+ EuiToolTip,
+ EuiButtonIcon,
+ EuiDataGridCellValueElementProps,
+ EuiFlexGroup,
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiTitle,
+ EuiButtonEmpty,
+ EuiPanel,
+} from '@elastic/eui';
+import { SearchResponse } from '../../../../../../../../src/core/server';
+import { HitsCounter } from '../../../../../kibana-integrations/discover/application/components/hits_counter/hits_counter';
+import { formatNumWithCommas } from '../../../../../kibana-integrations/discover/application/helpers';
+import { getWazuhCorePlugin } from '../../../../../kibana-services';
+import {
+ ErrorHandler,
+ ErrorFactory,
+ HttpError,
+} from '../../../../../react-services/error-management';
+import './inventory.scss';
+import { MAX_ENTRIES_PER_QUERY, inventoryTableDefaultColumns } from './config';
+import { DiscoverNoResults } from '../../common/components/no_results';
+import { LoadingSpinner } from '../../common/components/loading_spinner';
+// common components/hooks
+import useSearchBar from '../../../../common/search-bar/use-search-bar';
+import { useDataGrid } from '../../../../common/data-grid/use-data-grid';
+import { useDocViewer } from '../../../../common/doc-viewer/use-doc-viewer';
+import { withErrorBoundary } from '../../../../common/hocs';
+import { exportSearchToCSV } from '../../../../common/data-grid/data-grid-service';
+import { compose } from 'redux';
+import { withVulnerabilitiesStateDataSource } from '../../common/hocs/validate-vulnerabilities-states-index-pattern';
+import { ModuleEnabledCheck } from '../../common/components/check-module-enabled';
+
+import {
+ VulnerabilitiesDataSourceRepository,
+ VulnerabilitiesDataSource,
+ tParsedIndexPattern,
+ PatternDataSource,
+} from '../../../../common/data-source';
+import { useDataSource } from '../../../../common/data-source/hooks';
+import { IndexPattern } from '../../../../../../../../src/plugins/data/public';
+import { DocumentViewTableAndJson } from '../../common/components/document-view-table-and-json';
+import { wzDiscoverRenderColumns } from '../../../../common/wazuh-discover/render-columns';
+import { WzSearchBar } from '../../../../common/search-bar';
+
+const InventoryVulsComponent = () => {
+ const {
+ dataSource,
+ filters,
+ fetchFilters,
+ isLoading: isDataSourceLoading,
+ fetchData,
+ setFilters,
+ } = useDataSource({
+ DataSource: VulnerabilitiesDataSource,
+ repository: new VulnerabilitiesDataSourceRepository(),
+ });
+ const { searchBarProps } = useSearchBar({
+ indexPattern: dataSource?.indexPattern as IndexPattern,
+ filters,
+ setFilters,
+ });
+ const { query } = searchBarProps;
+
+ const [results, setResults] = useState({} as SearchResponse);
+ const [inspectedHit, setInspectedHit] = useState(undefined);
+ const [indexPattern, setIndexPattern] = useState(
+ undefined,
+ );
+ const [isExporting, setIsExporting] = useState(false);
+
+ const sideNavDocked = getWazuhCorePlugin().hooks.useDockedSideNav();
+
+ const onClickInspectDoc = useMemo(
+ () => (index: number) => {
+ const rowClicked = results.hits.hits[index];
+ setInspectedHit(rowClicked);
+ },
+ [results],
+ );
+
+ const DocViewInspectButton = ({
+ rowIndex,
+ }: EuiDataGridCellValueElementProps) => {
+ const inspectHintMsg = 'Inspect vulnerability details';
+ return (
+
+ onClickInspectDoc(rowIndex)}
+ iconType='inspect'
+ aria-label={inspectHintMsg}
+ />
+
+ );
+ };
+
+ const dataGridProps = useDataGrid({
+ ariaLabelledBy: 'Vulnerabilities Inventory Table',
+ defaultColumns: inventoryTableDefaultColumns,
+ renderColumns: wzDiscoverRenderColumns,
+ results,
+ indexPattern: indexPattern as IndexPattern,
+ DocViewInspectButton,
+ });
+
+ const { pagination, sorting, columnVisibility } = dataGridProps;
+
+ const docViewerProps = useDocViewer({
+ doc: inspectedHit,
+ indexPattern: indexPattern as IndexPattern,
+ });
+
+ const onClickExportResults = async () => {
+ const params = {
+ indexPattern: indexPattern as IndexPattern,
+ filters: fetchFilters,
+ query,
+ fields: columnVisibility.visibleColumns,
+ pagination: {
+ pageIndex: 0,
+ pageSize: results.hits.total,
+ },
+ sorting,
+ };
+ try {
+ setIsExporting(true);
+ await exportSearchToCSV(params);
+ } catch (error) {
+ const searchError = ErrorFactory.create(HttpError, {
+ error,
+ message: 'Error downloading csv report',
+ });
+ ErrorHandler.handleError(searchError);
+ } finally {
+ setIsExporting(false);
+ }
+ };
+
+ useEffect(() => {
+ if (isDataSourceLoading) {
+ return;
+ }
+ setIndexPattern(dataSource?.indexPattern);
+ fetchData({ query, pagination, sorting })
+ .then(results => {
+ setResults(results);
+ })
+ .catch(error => {
+ const searchError = ErrorFactory.create(HttpError, {
+ error,
+ message: 'Error fetching vulnerabilities',
+ });
+ ErrorHandler.handleError(searchError);
+ });
+ }, [
+ JSON.stringify(fetchFilters),
+ JSON.stringify(query),
+ JSON.stringify(pagination),
+ JSON.stringify(sorting),
+ ]);
+ console.log('hola');
+ return (
+
+ <>
+
+
+ <>
+ {isDataSourceLoading ? (
+
+ ) : (
+
+ )}
+ {!isDataSourceLoading && results?.hits?.total === 0 ? (
+
+ ) : null}
+ {!isDataSourceLoading && results?.hits?.total > 0 ? (
+
+
+
+ MAX_ENTRIES_PER_QUERY
+ ? {
+ ariaLabel: 'Warning',
+ content: `The query results has exceeded the limit of 10,000 hits. To provide a better experience the table only shows the first ${formatNumWithCommas(
+ MAX_ENTRIES_PER_QUERY,
+ )} hits.`,
+ iconType: 'alert',
+ position: 'top',
+ }
+ : undefined
+ }
+ />
+
+ Export Formated
+
+ >
+ ),
+ }}
+ />
+
+
+ ) : null}
+ {inspectedHit && (
+ setInspectedHit(undefined)} size='m'>
+
+
+ Vulnerability details
+
+
+
+
+
+
+
+
+ )}
+ >
+
+ >
+
+ );
+};
+
+export const InventoryVuls = compose(
+ withErrorBoundary,
+ withVulnerabilitiesStateDataSource,
+)(InventoryVulsComponent);
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard-saved-object.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard-saved-object.tsx
new file mode 100644
index 0000000000..a53b2ae176
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard-saved-object.tsx
@@ -0,0 +1,80 @@
+import React, { useState, useEffect } from 'react';
+import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public';
+import { GenericRequest } from '../../../../../react-services/generic-request';
+import { getPlugins } from '../../../../../kibana-services';
+
+const DashboardByRenderer =
+ getPlugins().dashboard.DashboardContainerByValueRenderer;
+
+const transformPanelsJSON = ({ panelsJSON, references }) =>
+ Object.fromEntries(
+ JSON.parse(panelsJSON).map(({ gridData, panelIndex, panelRefName }) => [
+ panelIndex,
+ {
+ gridData: gridData,
+ type: 'visualization',
+ explicitInput: {
+ id: panelIndex,
+ savedObjectId: references.find(({ name }) => name === panelRefName)
+ .id,
+ },
+ },
+ ]),
+ );
+
+const transform = spec => {
+ const options = JSON.parse(spec.attributes.optionsJSON);
+ return {
+ title: spec.attributes.title,
+ panels: transformPanelsJSON({
+ panelsJSON: spec.attributes.panelsJSON,
+ references: spec.references,
+ }),
+ useMargins: options.useMargins,
+ hidePanelTitles: options.hidePanelTitles,
+ description: spec.attributes.description,
+ id: spec.id,
+ };
+};
+
+export const DashboardSavedObject = ({ savedObjectId, ...props }) => {
+ const [dashboardSpecForComponent, setDashboardSpecForComponent] = useState<
+ null | string
+ >(null);
+ useEffect(() => {
+ // Get dashboard saved object specification
+ (async () => {
+ console.log({ props }, 'randadsa');
+ const { data } = await GenericRequest.request(
+ 'GET',
+ `/api/saved_objects/dashboard/${savedObjectId}`,
+ );
+
+ // Tranform to the expected by the render component
+ const dashboardSpecRenderer = transform(data);
+
+ setDashboardSpecForComponent(dashboardSpecRenderer);
+ console.log(dashboardSpecRenderer, 'dashboardSpecRenderer');
+ })();
+ }, []);
+ return dashboardSpecForComponent ? (
+
+ ) : null;
+};
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard.tsx
new file mode 100644
index 0000000000..b2a14f8a66
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/dashboard.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+import { DashboardSavedObject } from './dashboard-saved-object';
+
+export const DashboardVuls = () => {
+ const savedObjectId = 'c69f6ea0-3893-11ef-a08d-93dcf854882b';
+ return ;
+};
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/index.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/index.tsx
new file mode 100644
index 0000000000..b58b6c9229
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/dashboards/overview/index.tsx
@@ -0,0 +1 @@
+export * from './dashboard';
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/events/vulnerabilities-columns.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/events/vulnerabilities-columns.tsx
new file mode 100644
index 0000000000..e4d0a53548
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/events/vulnerabilities-columns.tsx
@@ -0,0 +1,22 @@
+import { tDataGridColumn } from '../../../common/data-grid';
+
+export const vulnerabilitiesColumns: tDataGridColumn[] = [
+ {
+ id: 'timestamp',
+ },
+ {
+ id: 'agent.name',
+ },
+ {
+ id: 'data.vulnerability.package.name',
+ },
+ {
+ id: 'data.vulnerability.cve',
+ },
+ {
+ id: 'data.vulnerability.severity',
+ },
+ {
+ id: 'data.vulnerability.status',
+ },
+];
diff --git a/plugins/main/public/components/overview/poc-dashboards-by-reference/index.tsx b/plugins/main/public/components/overview/poc-dashboards-by-reference/index.tsx
new file mode 100644
index 0000000000..d46e147b8e
--- /dev/null
+++ b/plugins/main/public/components/overview/poc-dashboards-by-reference/index.tsx
@@ -0,0 +1 @@
+export * from './dashboards';
\ No newline at end of file