From 793730e52fccf48aea0f2e1507dde0dddb843763 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Fri, 29 Sep 2023 09:35:07 -0300 Subject: [PATCH 01/17] Add APIs table version status --- .../components/settings/about/appInfo.tsx | 10 +- .../components/settings/about/index.tsx | 22 +-- plugins/wazuh-check-updates/common/types.ts | 6 +- .../components/apis-update-status/columns.tsx | 101 ++++++++++++ .../components/apis-update-status/index.tsx | 147 ++++++++++++++++++ .../apis-update-status/update-details.tsx | 93 +++++++++++ plugins/wazuh-check-updates/public/plugin.ts | 8 +- plugins/wazuh-check-updates/public/types.ts | 6 +- .../server/routes/updates/get-updates.ts | 16 +- .../server/services/updates/get-updates.ts | 4 +- .../translations/en-US.json | 13 +- 11 files changed, 373 insertions(+), 53 deletions(-) create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx diff --git a/plugins/main/public/components/settings/about/appInfo.tsx b/plugins/main/public/components/settings/about/appInfo.tsx index 2881bd9bf0..5352facf5c 100644 --- a/plugins/main/public/components/settings/about/appInfo.tsx +++ b/plugins/main/public/components/settings/about/appInfo.tsx @@ -16,11 +16,10 @@ interface SettingsAboutAppInfoProps { installationDate: string; revision: string; }; - setCurrentUpdate: (update: Update | undefined) => void; } -export const SettingsAboutAppInfo = ({ appInfo, setCurrentUpdate }: SettingsAboutAppInfoProps) => { - const { UpToDateStatus, DismissNotificationCheck } = getWazuhCheckUpdatesPlugin(); +export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) => { + const { APIsUpdateStatus } = getWazuhCheckUpdatesPlugin(); return ( <> @@ -39,9 +38,6 @@ export const SettingsAboutAppInfo = ({ appInfo, setCurrentUpdate }: SettingsAbou - - - @@ -58,7 +54,7 @@ export const SettingsAboutAppInfo = ({ appInfo, setCurrentUpdate }: SettingsAbou - + ); }; diff --git a/plugins/main/public/components/settings/about/index.tsx b/plugins/main/public/components/settings/about/index.tsx index f52998041c..16ca9c2fea 100644 --- a/plugins/main/public/components/settings/about/index.tsx +++ b/plugins/main/public/components/settings/about/index.tsx @@ -1,9 +1,7 @@ -import React, { useState } from 'react'; +import React from 'react'; import { EuiLoadingContent, EuiPage, EuiPageBody, EuiPanel, EuiSpacer } from '@elastic/eui'; import { SettingsAboutAppInfo } from './appInfo'; import { SettingsAboutGeneralInfo } from './generalInfo'; -import { Update } from '../../../../../wazuh-check-updates/common/types'; -import { getWazuhCheckUpdatesPlugin } from '../../../kibana-services'; interface SettingsAboutProps { appInfo?: { @@ -17,10 +15,6 @@ interface SettingsAboutProps { export const SettingsAbout = (props: SettingsAboutProps) => { const { appInfo, pluginAppName } = props; - const [currentUpdate, setCurrentUpdate] = useState(); - - const { CurrentUpdateDetails } = getWazuhCheckUpdatesPlugin(); - const isLoading = !appInfo; return ( @@ -29,19 +23,7 @@ export const SettingsAbout = (props: SettingsAboutProps) => { - {isLoading ? ( - - ) : ( - <> - - {currentUpdate ? ( - <> - - - - ) : null} - - )} + {isLoading ? : } diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index 9723d7ea3f..89be10eaa9 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -1,4 +1,8 @@ export interface AvailableUpdates { + [apiId: string]: APIAvailableUpdates; +} + +export interface APIAvailableUpdates { mayor: Update[]; minor: Update[]; patch: Update[]; @@ -26,4 +30,4 @@ export interface CheckUpdatesSettings { schedule?: string; } -export type savedObjectType = AvailableUpdates | UserPreferences | CheckUpdatesSettings; +export type savedObjectType = APIAvailableUpdates | UserPreferences | CheckUpdatesSettings; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx new file mode 100644 index 0000000000..86bd311958 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiIconTip } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; +import { formatUIDate } from '../../utils'; +import { APIAvailableUpdates } from '../../../common/types'; + +export const apisUpdateStatusColumns = [ + { + field: 'apiId', + name: 'ID', + width: '150px', + }, + { + field: 'version', + name: 'Version', + width: '150px', + }, + { + field: 'upToDate', + name: 'Update status', + width: '200px', + render: (isUpToDate: boolean, item: any) => { + const getI18nMessageId = () => { + if (isUpToDate) { + return 'upToDate'; + } + return 'availableUpdates'; + }; + + const getDefaultMessage = () => { + if (isUpToDate) { + return 'Up to date'; + } + return 'Available updates'; + }; + + const getColor = () => { + if (isUpToDate) { + return 'success'; + } + return 'warning'; + }; + + return ( + + + + + + + + + } + content={ + item.availableUpdates.last_check + ? formatUIDate(new Date(item.availableUpdates.last_check)) + : '-' + } + iconProps={{ + className: 'eui-alignTop', + }} + /> + + + ); + }, + }, + { + field: 'availableUpdates', + name: 'Available updates', + render: (availableUpdates: APIAvailableUpdates, item: any) => + item.upToDate ? null : ( + + {availableUpdates.minor.map((version) => ( + + + {version.tag} + + + + ))} + + ), + }, +]; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx new file mode 100644 index 0000000000..df290c1e6d --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -0,0 +1,147 @@ +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiGlobalToastList, + EuiHealth, + EuiIconTip, + EuiInMemoryTable, + EuiLoadingSpinner, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; +import { useAvailableUpdates } from '../../hooks'; +import { formatUIDate, getCurrentAvailableUpdate } from '../../utils'; +import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; +import { DismissNotificationCheck } from '../dismiss-notification-check'; +import { apisUpdateStatusColumns } from './columns'; + +let toastId = 0; + +export const APIsUpdateStatus = () => { + const [toasts, setToasts] = useState([]); + + const addToastHandler = (error: any) => { + const toast = { + id: `${toastId++}`, + title: ( + + ), + color: 'danger', + iconType: 'alert', + text: error?.body?.message, + } as Toast; + setToasts(toasts.concat(toast)); + }; + + const removeToast = (removedToast: Toast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + // const { availableUpdates, isLoading, refreshAvailableUpdates, error } = useAvailableUpdates(); + + const handleOnClick = async () => { + // const response = await refreshAvailableUpdates(true, true); + // if (response instanceof Error) { + // addToastHandler(response); + // } + }; + + // useEffect(() => { + // setCurrentUpdate(getCurrentAvailableUpdate(availableUpdates)); + // }, [availableUpdates]); + + const availableUpdates = { + mayor: [], + minor: [ + { + description: + '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', + published_date: '2022-05-05T16:06:52Z', + semver: { + mayor: 4, + minor: 3, + patch: 0, + }, + tag: 'v4.3.0', + title: 'Wazuh v4.3.0', + }, + { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + mayor: 4, + minor: 3, + patch: 1, + }, + tag: 'v4.3.1', + title: 'Wazuh v4.3.1', + }, + { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-06-20T13:20:11Z', + semver: { + mayor: 4, + minor: 3, + patch: 2, + }, + tag: 'v4.3.2', + title: 'Wazuh v4.3.2', + }, + ], + patch: [], + last_check: '2023-09-28 12:32', + }; + + const items = [ + { apiId: 'imposter', version: '3.7.2', upToDate: false, availableUpdates }, + { apiId: 'manager', version: '4.8.0', upToDate: true, availableUpdates }, + { apiId: 'api', version: '4.3.5', upToDate: false, availableUpdates }, + ]; + + const isLoading = false; + + return ( + + + + +

+ +

+
+
+ + + + + + + + +
+ + + +
+ ); +}; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx new file mode 100644 index 0000000000..3b6bd5d241 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { + EuiAccordion, + EuiBadge, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiHeaderLink, + EuiText, + EuiSpacer, +} from '@elastic/eui'; +import { Update } from '../../../common/types'; +import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; + +export interface UpdateDetailsProps { + update: Update; +} + +export const UpdateDetails = ({ update }: UpdateDetailsProps) => { + const release = `${update?.semver.mayor}.${update?.semver.minor}`; + const releaseNotesUrl = `https://documentation.wazuh.com/${release}/release-notes/release-${update.semver.mayor}-${update.semver.minor}-${update.semver.patch}.html`; + const upgradeGuideUrl = `https://documentation.wazuh.com/${release}/upgrade-guide/index.html`; + + return ( + + + + + + + {update.tag} + + + } + color="warning" + iconType="bell" + > + + + + + + + + + + + + + + + } + paddingSize="m" + > + + {update.description.split('\r\n').map((line, index) => ( +

{line}

+ ))} +
+
+
+
+ ); +}; diff --git a/plugins/wazuh-check-updates/public/plugin.ts b/plugins/wazuh-check-updates/public/plugin.ts index f19f8eaa7d..1d702193f4 100644 --- a/plugins/wazuh-check-updates/public/plugin.ts +++ b/plugins/wazuh-check-updates/public/plugin.ts @@ -1,10 +1,8 @@ import { CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; import { WazuhCheckUpdatesPluginSetup, WazuhCheckUpdatesPluginStart } from './types'; import { UpdatesNotification } from './components/updates-notification'; -import { UpToDateStatus } from './components/up-to-date-status'; import { setCore, setUiSettings } from './plugin-services'; -import { CurrentUpdateDetails } from './components/current-update-details'; -import { DismissNotificationCheck } from './components/dismiss-notification-check'; +import { APIsUpdateStatus } from './components/apis-update-status'; export class WazuhCheckUpdatesPlugin implements Plugin { @@ -18,9 +16,7 @@ export class WazuhCheckUpdatesPlugin return { UpdatesNotification, - UpToDateStatus, - CurrentUpdateDetails, - DismissNotificationCheck, + APIsUpdateStatus, }; } diff --git a/plugins/wazuh-check-updates/public/types.ts b/plugins/wazuh-check-updates/public/types.ts index 75c61366fb..adc434b40e 100644 --- a/plugins/wazuh-check-updates/public/types.ts +++ b/plugins/wazuh-check-updates/public/types.ts @@ -1,14 +1,10 @@ import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; -import { CurrentUpdateDetailsProps } from './components/current-update-details'; -import { UpToDateStatusProps } from './components/up-to-date-status'; export interface WazuhCheckUpdatesPluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface WazuhCheckUpdatesPluginStart { UpdatesNotification: () => JSX.Element | null; - UpToDateStatus: (props: UpToDateStatusProps) => JSX.Element | null; - CurrentUpdateDetails: (props: CurrentUpdateDetailsProps) => JSX.Element | null; - DismissNotificationCheck: () => JSX.Element | null; + APIsUpdateStatus: () => JSX.Element; } export interface AppPluginStartDependencies { diff --git a/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts b/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts index 1e593a1d07..6f2de7bbd5 100644 --- a/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts @@ -8,14 +8,18 @@ import { getSavedObject } from '../../services/saved-object'; export const getUpdatesRoute = (router: IRouter) => { router.get( { - path: routes.checkUpdates, + path: `${routes.checkUpdates}/{apiId}`, validate: { + params: schema.object({ + apiId: schema.string(), + }), query: schema.object({ checkAvailableUpdates: schema.maybe(schema.string()), }), }, }, - async (context, request, response) => { + async (context, { query, params }, response) => { + const { apiId } = params; try { const defaultValues = { mayor: [], @@ -23,8 +27,8 @@ export const getUpdatesRoute = (router: IRouter) => { patch: [], }; - if (request.query.checkAvailableUpdates === 'true') { - const updates = await getUpdates(); + if (query.checkAvailableUpdates === 'true') { + const updates = await getUpdates(apiId); return response.ok({ body: { ...defaultValues, @@ -33,7 +37,7 @@ export const getUpdatesRoute = (router: IRouter) => { }); } - const result = (await getSavedObject(SAVED_OBJECT_UPDATES)) as AvailableUpdates; + const result = (await getSavedObject(SAVED_OBJECT_UPDATES, apiId)) as AvailableUpdates; return response.ok({ body: { @@ -47,7 +51,7 @@ export const getUpdatesRoute = (router: IRouter) => { ? error : typeof error === 'string' ? new Error(error) - : new Error('Error trying to get available updates'); + : new Error(`Error trying to get available updates for API ${apiId}`); return response.customError({ statusCode: 503, diff --git a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts index 3a3ba248df..cd364b9a79 100644 --- a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts @@ -6,7 +6,7 @@ import { SAVED_OBJECT_UPDATES } from '../../../common/constants'; import { setSavedObject } from '../saved-object'; import { log } from '../../lib/logger'; -export const getUpdates = async (): Promise => { +export const getUpdates = async (apiId: string): Promise => { const mock = new MockAdapter(axios); try { @@ -20,7 +20,7 @@ export const getUpdates = async (): Promise => { const updatesToSave = { ...updates, last_check: new Date() }; - await setSavedObject(SAVED_OBJECT_UPDATES, updatesToSave); + await setSavedObject(SAVED_OBJECT_UPDATES, updatesToSave, apiId); return updatesToSave; } catch (error) { diff --git a/plugins/wazuh-check-updates/translations/en-US.json b/plugins/wazuh-check-updates/translations/en-US.json index 75cab75567..95ef8e4cdf 100644 --- a/plugins/wazuh-check-updates/translations/en-US.json +++ b/plugins/wazuh-check-updates/translations/en-US.json @@ -80,12 +80,13 @@ "wazuhCheckUpdates.updatesNotification.linkText": "Go to the release notes for details", "wazuhCheckUpdates.updatesNotification.dismissCheckText": "Disable updates notifications", "wazuhCheckUpdates.updatesNotification.closeButtonText": "Close", - "wazuhCheckUpdates.upToDateStatus.upToDate": "Up to date", - "wazuhCheckUpdates.upToDateStatus.availableUpdates": "Available updates", - "wazuhCheckUpdates.upToDateStatus.getAvailableUpdatesError": "Error trying to get available updates", - "wazuhCheckUpdates.upToDateStatus.lastCheck": "Last check", - "wazuhCheckUpdates.upToDateStatus.buttonText": "Check updates", - "wazuhCheckUpdates.upToDateStatus.onClickButtonError": "Error trying to get updates", + "wazuhCheckUpdates.apisUpdateStatus.upToDate": "Up to date", + "wazuhCheckUpdates.apisUpdateStatus.availableUpdates": "Available updates", + "wazuhCheckUpdates.apisUpdateStatus.getAvailableUpdatesError": "Error trying to get available updates", + "wazuhCheckUpdates.apisUpdateStatus.lastCheck": "Last check", + "wazuhCheckUpdates.apisUpdateStatus.buttonText": "Check updates", + "wazuhCheckUpdates.apisUpdateStatus.onClickButtonError": "Error trying to get updates", + "wazuhCheckUpdates.apisUpdateStatus.tableTitle": "Wazuh APIs version", "wazuhCheckUpdates.currentUpdateDetails.releaseNotesLink": "Release notes", "wazuhCheckUpdates.currentUpdateDetails.title": "Wazuh new release is available now!", "wazuhCheckUpdates.currentUpdateDetails.upgradeGuideLink": "Upgrade guide", From 54a49f2b44cb947225862322a55508f1a52264e6 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Fri, 29 Sep 2023 15:26:56 -0300 Subject: [PATCH 02/17] Add available updates columns --- .../components/settings/about/appInfo.tsx | 45 +++++++++------- .../components/apis-update-status/columns.tsx | 52 +++++++++++++++++-- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/plugins/main/public/components/settings/about/appInfo.tsx b/plugins/main/public/components/settings/about/appInfo.tsx index 5352facf5c..5552184769 100644 --- a/plugins/main/public/components/settings/about/appInfo.tsx +++ b/plugins/main/public/components/settings/about/appInfo.tsx @@ -1,13 +1,12 @@ import { - EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiLoadingSpinner, EuiText, EuiSpacer, + EuiTitle, + EuiHorizontalRule, } from '@elastic/eui'; import React from 'react'; -import { Update } from '../../../../../wazuh-check-updates/common/types'; import { getWazuhCheckUpdatesPlugin } from '../../../kibana-services'; interface SettingsAboutAppInfoProps { @@ -23,37 +22,43 @@ export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) => return ( <> + +

Wazuh Dashboard version

+
+
- {'App version: '} + {'Version: '} {appInfo['app-version']}
+ + +
+ {'Revision: '} + {appInfo['revision']} +
+
+
+ + +
+ {'Install date: '} + {appInfo['installationDate']} +
+
+
- - -
- {'App revision: '} - {appInfo['revision']} -
-
- - -
- {'Install date: '} - {appInfo['installationDate']} -
-
- + ); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx index 86bd311958..70a68df756 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx @@ -76,12 +76,58 @@ export const apisUpdateStatusColumns = [ }, }, { - field: 'availableUpdates', - name: 'Available updates', + field: 'majorAvailableUpdates', + name: 'Major available updates', render: (availableUpdates: APIAvailableUpdates, item: any) => item.upToDate ? null : ( - {availableUpdates.minor.map((version) => ( + {item.availableUpdates.minor.map((version) => ( + + + {version.tag} + + + + ))} + + ), + }, + { + field: 'minorAvailableUpdates', + name: 'Minor available updates', + render: (availableUpdates: APIAvailableUpdates, item: any) => + item.upToDate ? null : ( + + {item.availableUpdates.minor.map((version) => ( + + + {version.tag} + + + + ))} + + ), + }, + { + field: 'patchAvailableUpdates', + name: 'Patch available updates', + render: (availableUpdates: APIAvailableUpdates, item: any) => + item.upToDate ? null : ( + + {item.availableUpdates.minor.map((version) => ( {version.tag} From a9498e73ed2635724a08eb4de2340a0fcb86ff36 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Wed, 4 Oct 2023 18:18:24 -0300 Subject: [PATCH 03/17] Add changes to show one mayor, one minor and one patch update per API --- .../components/settings/about/appInfo.tsx | 55 ++++--- .../wazuh-check-updates/common/constants.ts | 2 +- plugins/wazuh-check-updates/common/types.ts | 27 ++- .../opensearch_dashboards.json | 2 +- .../components/apis-update-status/columns.tsx | 147 ----------------- .../components/apis-update-status/index.tsx | 154 ++++++++---------- .../table/columns/index.tsx | 74 +++++++++ .../table/columns/update-badge.tsx | 116 +++++++++++++ .../apis-update-status/table/index.tsx | 21 +++ .../public/hooks/available-updates.ts | 21 +-- plugins/wazuh-check-updates/public/plugin.ts | 4 +- plugins/wazuh-check-updates/public/types.ts | 2 +- .../get-current-available-update.test.ts | 76 --------- .../utils/get-current-available-update.ts | 18 -- .../wazuh-check-updates/public/utils/index.ts | 1 - .../server/routes/updates/get-updates.ts | 38 +---- .../saved-object/types/available-updates.ts | 24 ++- .../server/services/updates/get-updates.ts | 39 ++++- .../server/services/updates/mocks.ts | 80 ++++++--- .../translations/en-US.json | 7 +- 20 files changed, 454 insertions(+), 454 deletions(-) delete mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx delete mode 100644 plugins/wazuh-check-updates/public/utils/get-current-available-update.test.ts delete mode 100644 plugins/wazuh-check-updates/public/utils/get-current-available-update.ts diff --git a/plugins/main/public/components/settings/about/appInfo.tsx b/plugins/main/public/components/settings/about/appInfo.tsx index 5552184769..e40880886b 100644 --- a/plugins/main/public/components/settings/about/appInfo.tsx +++ b/plugins/main/public/components/settings/about/appInfo.tsx @@ -5,6 +5,7 @@ import { EuiSpacer, EuiTitle, EuiHorizontalRule, + EuiDescriptionList, } from '@elastic/eui'; import React from 'react'; import { getWazuhCheckUpdatesPlugin } from '../../../kibana-services'; @@ -18,7 +19,7 @@ interface SettingsAboutAppInfoProps { } export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) => { - const { APIsUpdateStatus } = getWazuhCheckUpdatesPlugin(); + const { ApisUpdateStatus } = getWazuhCheckUpdatesPlugin(); return ( <> @@ -26,40 +27,40 @@ export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) =>

Wazuh Dashboard version

- + - -
- {'Version: '} - {appInfo['app-version']} -
-
+
- -
- {'Revision: '} - {appInfo['revision']} -
-
+
- -
- {'Install date: '} - {appInfo['installationDate']} -
-
+
- + ); }; diff --git a/plugins/wazuh-check-updates/common/constants.ts b/plugins/wazuh-check-updates/common/constants.ts index 29c6695ffd..38de2b9ac6 100644 --- a/plugins/wazuh-check-updates/common/constants.ts +++ b/plugins/wazuh-check-updates/common/constants.ts @@ -7,7 +7,7 @@ export const SAVED_OBJECT_UPDATES = 'wazuh-check-updates-available-updates'; export const SAVED_OBJECT_SETTINGS = 'wazuh-check-updates-settings'; export const SAVED_OBJECT_USER_PREFERENCES = 'wazuh-check-updates-user-preferences'; -export const DEFAULT_SCHEDULE = '* */12 * * *'; +export const DEFAULT_SCHEDULE = '* */24 * * *'; export enum routes { checkUpdates = '/api/wazuh-check-updates/updates', diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index 89be10eaa9..6086d3ac3d 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -1,14 +1,22 @@ -export interface AvailableUpdates { - [apiId: string]: APIAvailableUpdates; +export enum API_UPDATES_STATUS { + UP_TO_DATE = 'upToDate', + AVAILABLE_UPDATES = 'availableUpdates', + ERROR = 'error', } -export interface APIAvailableUpdates { - mayor: Update[]; - minor: Update[]; - patch: Update[]; +export interface ResponseApiAvailableUpdates { + apiId: string; + version: string; + lastMayor?: Update; + lastMinor?: Update; + lastPatch?: Update; last_check?: Date | string | undefined; } +export interface ApiAvailableUpdates extends ResponseApiAvailableUpdates { + status: API_UPDATES_STATUS; +} + export interface Update { description: string; published_date: string; @@ -30,4 +38,9 @@ export interface CheckUpdatesSettings { schedule?: string; } -export type savedObjectType = APIAvailableUpdates | UserPreferences | CheckUpdatesSettings; +export interface AvailableUpdates { + apiAvailableUpdates: ApiAvailableUpdates[]; + last_check: Date; +} + +export type savedObjectType = AvailableUpdates | UserPreferences | CheckUpdatesSettings; diff --git a/plugins/wazuh-check-updates/opensearch_dashboards.json b/plugins/wazuh-check-updates/opensearch_dashboards.json index 1590d742da..99fa10c54f 100644 --- a/plugins/wazuh-check-updates/opensearch_dashboards.json +++ b/plugins/wazuh-check-updates/opensearch_dashboards.json @@ -4,6 +4,6 @@ "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["navigation", "opensearchDashboardsUtils"], + "requiredPlugins": ["navigation", "opensearchDashboardsUtils", "opensearchDashboardsReact"], "optionalPlugins": ["securityDashboards"] } diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx deleted file mode 100644 index 70a68df756..0000000000 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/columns.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import React from 'react'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiIconTip } from '@elastic/eui'; -import { FormattedMessage } from '@osd/i18n/react'; -import { formatUIDate } from '../../utils'; -import { APIAvailableUpdates } from '../../../common/types'; - -export const apisUpdateStatusColumns = [ - { - field: 'apiId', - name: 'ID', - width: '150px', - }, - { - field: 'version', - name: 'Version', - width: '150px', - }, - { - field: 'upToDate', - name: 'Update status', - width: '200px', - render: (isUpToDate: boolean, item: any) => { - const getI18nMessageId = () => { - if (isUpToDate) { - return 'upToDate'; - } - return 'availableUpdates'; - }; - - const getDefaultMessage = () => { - if (isUpToDate) { - return 'Up to date'; - } - return 'Available updates'; - }; - - const getColor = () => { - if (isUpToDate) { - return 'success'; - } - return 'warning'; - }; - - return ( - - - - - - - - - } - content={ - item.availableUpdates.last_check - ? formatUIDate(new Date(item.availableUpdates.last_check)) - : '-' - } - iconProps={{ - className: 'eui-alignTop', - }} - /> - - - ); - }, - }, - { - field: 'majorAvailableUpdates', - name: 'Major available updates', - render: (availableUpdates: APIAvailableUpdates, item: any) => - item.upToDate ? null : ( - - {item.availableUpdates.minor.map((version) => ( - - - {version.tag} - - - - ))} - - ), - }, - { - field: 'minorAvailableUpdates', - name: 'Minor available updates', - render: (availableUpdates: APIAvailableUpdates, item: any) => - item.upToDate ? null : ( - - {item.availableUpdates.minor.map((version) => ( - - - {version.tag} - - - - ))} - - ), - }, - { - field: 'patchAvailableUpdates', - name: 'Patch available updates', - render: (availableUpdates: APIAvailableUpdates, item: any) => - item.upToDate ? null : ( - - {item.availableUpdates.minor.map((version) => ( - - - {version.tag} - - - - ))} - - ), - }, -]; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx index df290c1e6d..0b500e71e7 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -1,26 +1,24 @@ import { EuiButton, + EuiCallOut, + EuiDescriptionList, EuiFlexGroup, EuiFlexItem, EuiGlobalToastList, - EuiHealth, - EuiIconTip, - EuiInMemoryTable, - EuiLoadingSpinner, EuiSpacer, EuiTitle, } from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { useAvailableUpdates } from '../../hooks'; -import { formatUIDate, getCurrentAvailableUpdate } from '../../utils'; import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; import { DismissNotificationCheck } from '../dismiss-notification-check'; -import { apisUpdateStatusColumns } from './columns'; +import { ApisUpdateTable } from './table'; +import { formatUIDate } from '../../utils'; let toastId = 0; -export const APIsUpdateStatus = () => { +export const ApisUpdateStatus = () => { const [toasts, setToasts] = useState([]); const addToastHandler = (error: any) => { @@ -43,87 +41,48 @@ export const APIsUpdateStatus = () => { setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); }; - // const { availableUpdates, isLoading, refreshAvailableUpdates, error } = useAvailableUpdates(); + const { + apiAvailableUpdates, + isLoading, + refreshAvailableUpdates, + error, + lastCheck, + } = useAvailableUpdates(); - const handleOnClick = async () => { - // const response = await refreshAvailableUpdates(true, true); - // if (response instanceof Error) { - // addToastHandler(response); - // } - }; - - // useEffect(() => { - // setCurrentUpdate(getCurrentAvailableUpdate(availableUpdates)); - // }, [availableUpdates]); + if (error) { + return ( + + } + /> + ); + } - const availableUpdates = { - mayor: [], - minor: [ - { - description: - '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', - published_date: '2022-05-05T16:06:52Z', - semver: { - mayor: 4, - minor: 3, - patch: 0, - }, - tag: 'v4.3.0', - title: 'Wazuh v4.3.0', - }, - { - description: - '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-05-18T10:12:43Z', - semver: { - mayor: 4, - minor: 3, - patch: 1, - }, - tag: 'v4.3.1', - title: 'Wazuh v4.3.1', - }, - { - description: - '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-06-20T13:20:11Z', - semver: { - mayor: 4, - minor: 3, - patch: 2, - }, - tag: 'v4.3.2', - title: 'Wazuh v4.3.2', - }, - ], - patch: [], - last_check: '2023-09-28 12:32', + const handleOnClick = async () => { + const response = await refreshAvailableUpdates(true, true); + if (response instanceof Error) { + addToastHandler(response); + } }; - const items = [ - { apiId: 'imposter', version: '3.7.2', upToDate: false, availableUpdates }, - { apiId: 'manager', version: '4.8.0', upToDate: true, availableUpdates }, - { apiId: 'api', version: '4.3.5', upToDate: false, availableUpdates }, - ]; - - const isLoading = false; - return ( + +

+ +

+
+ - - -

- -

-
-
- - - { /> + {lastCheck ? ( + + + ), + description: formatUIDate(new Date(lastCheck)), + }, + ]} + /> + + ) : null} + + +
- - + +
); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx new file mode 100644 index 0000000000..4926504e8d --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { EuiHealth } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; +import { ApiAvailableUpdates, API_UPDATES_STATUS, Update } from '../../../../../common/types'; +import { UpdateBadge } from './update-badge'; + +export const getApisUpdateStatusColumns = () => { + const baseColumns = [ + { + field: 'apiId', + name: 'ID', + width: '100px', + }, + { + field: 'version', + name: 'Version', + width: '100px', + }, + { + field: 'status', + name: 'Update status', + width: '200px', + render: (status: API_UPDATES_STATUS, api: ApiAvailableUpdates) => { + const getDefaultMessage = () => { + if (status === API_UPDATES_STATUS.UP_TO_DATE) { + return 'Up to date'; + } + if (status === API_UPDATES_STATUS.AVAILABLE_UPDATES) { + return 'Available updates'; + } + return 'Error checking updates'; + }; + + const getColor = () => { + if (status === API_UPDATES_STATUS.UP_TO_DATE) { + return 'success'; + } + if (status === API_UPDATES_STATUS.AVAILABLE_UPDATES) { + return 'warning'; + } + return 'danger'; + }; + + return ( + + + + ); + }, + }, + ]; + + const updatesColumn = (field: string, name: string) => ({ + field, + name, + width: '200px', + render: (lastUpdate: Update, api: ApiAvailableUpdates) => + api.status !== API_UPDATES_STATUS.ERROR && lastUpdate ? ( + + ) : null, + }); + + const finalColumns = [ + ...baseColumns, + updatesColumn('lastMayor', 'Last major'), + updatesColumn('lastMinor', 'Last minor'), + updatesColumn('lastPatch', 'Last patch'), + ]; + + return finalColumns; +}; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx new file mode 100644 index 0000000000..d784892e24 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx @@ -0,0 +1,116 @@ +import React, { useState, MouseEvent } from 'react'; +import { Update } from '../../../../../common/types'; +import { + EuiBadge, + EuiButtonEmpty, + EuiDescriptionList, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiOverlayMask, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiLink, +} from '@elastic/eui'; +import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; +import { Markdown } from '../../../../../../../src/plugins/opensearch_dashboards_react/public'; +import { formatUIDate } from '../../../../utils'; + +export interface UpdateProps { + update: Update; +} + +export const UpdateBadge = ({ update }: UpdateProps) => { + const { title, description, tag, semver, published_date } = update; + + const [isModalVisible, setIsModalVisible] = useState(false); + + const handleOnClickBadge = () => { + setIsModalVisible(true); + }; + + const handleOnCloseModal = () => { + setIsModalVisible(false); + }; + + const minorVersion = `${semver.mayor}.${semver.minor}`; + const releaseNotesUrl = `https://documentation.wazuh.com/${minorVersion}/release-notes/release-${semver.mayor}-${semver.minor}-${semver.patch}.html`; + const upgradeGuideUrl = `https://documentation.wazuh.com/${minorVersion}/upgrade-guide/index.html`; + + return ( + + ) => { + e.stopPropagation(); + }} + onClick={(e: MouseEvent) => { + e.stopPropagation(); + handleOnClickBadge(); + }} + style={{ maxWidth: 'max-content' }} + > + {tag} + + {isModalVisible ? ( + + + + {title} + + + + + ), + description: formatUIDate(new Date(published_date)), + }, + ]} + /> + + + + + + + + + + + + + + + + + + + + + + + + + ) : null} + + ); +}; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx new file mode 100644 index 0000000000..6cb0c2996f --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx @@ -0,0 +1,21 @@ +import { EuiInMemoryTable } from '@elastic/eui'; +import React from 'react'; +import { getApisUpdateStatusColumns } from './columns'; +import { ApiAvailableUpdates } from '../../../../common/types'; + +export interface ApisUpdateTableProps { + isLoading: boolean; + apiAvailableUpdates: ApiAvailableUpdates[]; +} + +export const ApisUpdateTable = ({ isLoading, apiAvailableUpdates }: ApisUpdateTableProps) => { + return ( + + ); +}; diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.ts index 9d85fda2c3..01bd58af0e 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.ts @@ -1,18 +1,11 @@ import { useState, useEffect } from 'react'; -import { AvailableUpdates } from '../../common/types'; +import { ApiAvailableUpdates } from '../../common/types'; import { routes } from '../../common/constants'; import { getCore } from '../plugin-services'; export const useAvailableUpdates = () => { - const defaultAvailableUpdates = { - mayor: [], - minor: [], - patch: [], - }; - - const [availableUpdates, setAvailableUpdates] = useState( - defaultAvailableUpdates - ); + const [apiAvailableUpdates, setApiAvailableUpdates] = useState([]); + const [lastCheck, setLastCheck] = useState(); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); @@ -20,15 +13,15 @@ export const useAvailableUpdates = () => { const refreshAvailableUpdates = async (forceUpdate = false, returnError = false) => { try { setIsLoading(true); - const response = await getCore().http.get(`${routes.checkUpdates}`, { + const response = await getCore().http.get(routes.checkUpdates, { query: { checkAvailableUpdates: forceUpdate, }, }); - setAvailableUpdates(response); + setApiAvailableUpdates(response?.apiAvailableUpdates || []); + setLastCheck(response?.last_check); setError(undefined); } catch (error: any) { - setAvailableUpdates(defaultAvailableUpdates); setError(error); if (returnError) { return error instanceof Error @@ -46,5 +39,5 @@ export const useAvailableUpdates = () => { refreshAvailableUpdates(); }, []); - return { isLoading, availableUpdates, refreshAvailableUpdates, error }; + return { isLoading, apiAvailableUpdates, refreshAvailableUpdates, error, lastCheck }; }; diff --git a/plugins/wazuh-check-updates/public/plugin.ts b/plugins/wazuh-check-updates/public/plugin.ts index 1d702193f4..b3f5f2d393 100644 --- a/plugins/wazuh-check-updates/public/plugin.ts +++ b/plugins/wazuh-check-updates/public/plugin.ts @@ -2,7 +2,7 @@ import { CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; import { WazuhCheckUpdatesPluginSetup, WazuhCheckUpdatesPluginStart } from './types'; import { UpdatesNotification } from './components/updates-notification'; import { setCore, setUiSettings } from './plugin-services'; -import { APIsUpdateStatus } from './components/apis-update-status'; +import { ApisUpdateStatus } from './components/apis-update-status'; export class WazuhCheckUpdatesPlugin implements Plugin { @@ -16,7 +16,7 @@ export class WazuhCheckUpdatesPlugin return { UpdatesNotification, - APIsUpdateStatus, + ApisUpdateStatus, }; } diff --git a/plugins/wazuh-check-updates/public/types.ts b/plugins/wazuh-check-updates/public/types.ts index adc434b40e..ecac2cdfa7 100644 --- a/plugins/wazuh-check-updates/public/types.ts +++ b/plugins/wazuh-check-updates/public/types.ts @@ -4,7 +4,7 @@ export interface WazuhCheckUpdatesPluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface WazuhCheckUpdatesPluginStart { UpdatesNotification: () => JSX.Element | null; - APIsUpdateStatus: () => JSX.Element; + ApisUpdateStatus: () => JSX.Element; } export interface AppPluginStartDependencies { diff --git a/plugins/wazuh-check-updates/public/utils/get-current-available-update.test.ts b/plugins/wazuh-check-updates/public/utils/get-current-available-update.test.ts deleted file mode 100644 index 6b33e78f4a..0000000000 --- a/plugins/wazuh-check-updates/public/utils/get-current-available-update.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { getCurrentAvailableUpdate } from './get-current-available-update'; - -describe('getCurrentAvailableUpdate function', () => { - test('should return an available update', () => { - const mockAvailabeUpdates = { - mayor: [], - minor: [ - { - description: - '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', - published_date: '2022-05-05T16:06:52Z', - semver: { - mayor: 4, - minor: 3, - patch: 0, - }, - tag: 'v4.3.0', - title: 'Wazuh v4.3.0', - }, - { - description: - '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-05-18T10:12:43Z', - semver: { - mayor: 4, - minor: 3, - patch: 1, - }, - tag: 'v4.3.1', - title: 'Wazuh v4.3.1', - }, - { - description: - '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-06-20T13:20:11Z', - semver: { - mayor: 4, - minor: 3, - patch: 2, - }, - tag: 'v4.3.2', - title: 'Wazuh v4.3.2', - }, - ], - patch: [], - }; - - const currentUpdate = getCurrentAvailableUpdate(mockAvailabeUpdates); - expect(currentUpdate).toBeDefined(); - expect(currentUpdate).toEqual({ - description: - '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-06-20T13:20:11Z', - semver: { - mayor: 4, - minor: 3, - patch: 2, - }, - tag: 'v4.3.2', - title: 'Wazuh v4.3.2', - }); - }); - test('should return undefined', () => { - const mockNoAvailableUpdates = { - mayor: [], - minor: [], - patch: [], - }; - const currentUpdate = getCurrentAvailableUpdate(mockNoAvailableUpdates); - expect(currentUpdate).toBeUndefined(); - }); - test('should return undefined', () => { - const currentUpdate = getCurrentAvailableUpdate(); - expect(currentUpdate).toBeUndefined(); - }); -}); diff --git a/plugins/wazuh-check-updates/public/utils/get-current-available-update.ts b/plugins/wazuh-check-updates/public/utils/get-current-available-update.ts deleted file mode 100644 index 730f05eb29..0000000000 --- a/plugins/wazuh-check-updates/public/utils/get-current-available-update.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { AvailableUpdates } from '../../common/types'; - -export const getCurrentAvailableUpdate = (availableUpdates: Partial = {}) => { - const { patch, minor, mayor } = availableUpdates; - - //TODO: Check real service to determinate the current update - - if (patch?.length) { - return patch[patch.length - 1]; - } - if (minor?.length) { - return minor[minor.length - 1]; - } - if (mayor?.length) { - return mayor[mayor.length - 1]; - } - return undefined; -}; diff --git a/plugins/wazuh-check-updates/public/utils/index.ts b/plugins/wazuh-check-updates/public/utils/index.ts index 7036afbe8f..b2b8c8fe08 100644 --- a/plugins/wazuh-check-updates/public/utils/index.ts +++ b/plugins/wazuh-check-updates/public/utils/index.ts @@ -1,2 +1 @@ -export { getCurrentAvailableUpdate } from './get-current-available-update'; export { formatUIDate } from './time'; diff --git a/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts b/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts index 6f2de7bbd5..b7652cb87e 100644 --- a/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/routes/updates/get-updates.ts @@ -1,49 +1,23 @@ import { IRouter } from 'opensearch-dashboards/server'; import { schema } from '@osd/config-schema'; -import { routes, SAVED_OBJECT_UPDATES } from '../../../common/constants'; -import { AvailableUpdates } from '../../../common/types'; +import { routes } from '../../../common/constants'; import { getUpdates } from '../../services/updates'; -import { getSavedObject } from '../../services/saved-object'; export const getUpdatesRoute = (router: IRouter) => { router.get( { - path: `${routes.checkUpdates}/{apiId}`, + path: routes.checkUpdates, validate: { - params: schema.object({ - apiId: schema.string(), - }), query: schema.object({ checkAvailableUpdates: schema.maybe(schema.string()), }), }, }, - async (context, { query, params }, response) => { - const { apiId } = params; + async (context, request, response) => { try { - const defaultValues = { - mayor: [], - minor: [], - patch: [], - }; - - if (query.checkAvailableUpdates === 'true') { - const updates = await getUpdates(apiId); - return response.ok({ - body: { - ...defaultValues, - ...updates, - }, - }); - } - - const result = (await getSavedObject(SAVED_OBJECT_UPDATES, apiId)) as AvailableUpdates; - + const updates = await getUpdates(request.query?.checkAvailableUpdates === 'true'); return response.ok({ - body: { - ...defaultValues, - ...result, - }, + body: updates, }); } catch (error) { const finalError = @@ -51,7 +25,7 @@ export const getUpdatesRoute = (router: IRouter) => { ? error : typeof error === 'string' ? new Error(error) - : new Error(`Error trying to get available updates for API ${apiId}`); + : new Error(`Error trying to get available updates`); return response.customError({ statusCode: 503, diff --git a/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts b/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts index 4f1692d252..47ba8cb062 100644 --- a/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts +++ b/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts @@ -2,7 +2,6 @@ import { SavedObjectsFieldMapping, SavedObjectsType } from 'opensearch-dashboard import { SAVED_OBJECT_UPDATES } from '../../../../common/constants'; const updateObjectType: SavedObjectsFieldMapping = { - type: 'nested', properties: { description: { type: 'text', @@ -42,9 +41,26 @@ export const availableUpdatesObject: SavedObjectsType = { last_check: { type: 'date', }, - mayor: updateObjectType, - minor: updateObjectType, - patch: updateObjectType, + apiAvailableUpdates: { + type: 'nested', + properties: { + apiId: { + type: 'text', + }, + version: { + type: 'text', + }, + status: { + type: 'text', + }, + last_check: { + type: 'date', + }, + lastMayor: updateObjectType, + lastMinor: updateObjectType, + lastPatch: updateObjectType, + }, + }, }, }, migrations: {}, diff --git a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts index cd364b9a79..0c83914540 100644 --- a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts @@ -1,28 +1,53 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { mockSuccessResponse } from './mocks'; -import { AvailableUpdates } from '../../../common/types'; +import { + API_UPDATES_STATUS, + AvailableUpdates, + ResponseApiAvailableUpdates, +} from '../../../common/types'; import { SAVED_OBJECT_UPDATES } from '../../../common/constants'; -import { setSavedObject } from '../saved-object'; +import { getSavedObject, setSavedObject } from '../saved-object'; import { log } from '../../lib/logger'; -export const getUpdates = async (apiId: string): Promise => { +export const getUpdates = async (checkAvailableUpdates?: boolean): Promise => { const mock = new MockAdapter(axios); try { + if (!checkAvailableUpdates) { + const availableUpdates = (await getSavedObject(SAVED_OBJECT_UPDATES)) as AvailableUpdates; + + return availableUpdates; + } + const updatesServiceUrl = `/api/updates`; mock.onGet(updatesServiceUrl).reply(200, mockSuccessResponse); const updatesResponse = await axios.get(updatesServiceUrl); - const updates = updatesResponse?.data?.data || {}; + const updates = (updatesResponse?.data?.data || []) as ResponseApiAvailableUpdates[]; + + const apiAvailableUpdates = updates?.map((update) => { + const status = + update.lastMayor || update.lastMinor || update.lastPatch + ? API_UPDATES_STATUS.AVAILABLE_UPDATES + : API_UPDATES_STATUS.UP_TO_DATE; + + return { + ...update, + status, + }; + }); - const updatesToSave = { ...updates, last_check: new Date() }; + const savedObject = { + apiAvailableUpdates, + last_check: new Date(), + }; - await setSavedObject(SAVED_OBJECT_UPDATES, updatesToSave, apiId); + await setSavedObject(SAVED_OBJECT_UPDATES, savedObject); - return updatesToSave; + return savedObject; } catch (error) { const message = error instanceof Error diff --git a/plugins/wazuh-check-updates/server/services/updates/mocks.ts b/plugins/wazuh-check-updates/server/services/updates/mocks.ts index 778d488476..db16f65228 100644 --- a/plugins/wazuh-check-updates/server/services/updates/mocks.ts +++ b/plugins/wazuh-check-updates/server/services/updates/mocks.ts @@ -1,48 +1,78 @@ -import { AvailableUpdates } from '../../../common/types'; +import { ResponseApiAvailableUpdates } from '../../../common/types'; -export const mockSuccessResponse: { data: Omit } = { - data: { - mayor: [], - minor: [ - { +export const mockSuccessResponse: { data: ResponseApiAvailableUpdates[] } = { + data: [ + { + apiId: 'api 1', + version: '3.7.2', + last_check: '2022-05-05T16:06:52Z', + lastMayor: { description: - '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', + '|Part of Epic|\r\n|---|\r\n|#84|\r\n## Description\r\nThe wazuh-check-updates plugin should expose a table with information about the status of updates for each API.\r\nAdditionally, the check for updates button must perform verification for each API.\r\n## Tasks\r\n- [x] **[wazuh-check-updates Backend]** Expose an endpoint to query the new updates and their details **for each API**. The endpoint should consult the Wazuh API. **Initially the response from the Wazuh API will be mocked**\r\n- [x] **[wazuh-check-updates Backend]** Manage saved objects to save available updates **for each API**.\r\n- [ ] **[wazuh-check-updates Backend]** Run a cron job to periodically check for available updates **for each API**.\r\n- [ ] **[wazuh-check-updates Frontend]** Expose a table to show the update status **for each API** and the details of each available update.\r\n- [ ] **[wazuh-check-updates Frontend]** It must use i18n.\r\n- [ ] **[wazuh Frontend]** Consume the frontend components in the About page.\r\n- [ ] Unit tests for each development\r\n## About page mockup\r\n![image (3)](https://github.com/wazuh/wazuh-dashboard/assets/103193307/65ab3494-6c76-4197-8a25-59bd9d0723aa)\r\n', published_date: '2022-05-05T16:06:52Z', semver: { mayor: 4, - minor: 3, + minor: 0, patch: 0, }, - tag: 'v4.3.0', - title: 'Wazuh v4.3.0', + tag: 'v4.4.0', + title: 'Wazuh v4.4.0', + }, + lastMinor: { + description: + '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', + published_date: '2022-05-05T16:06:52Z', + semver: { + mayor: 3, + minor: 8, + patch: 0, + }, + tag: 'v3.8.0', + title: 'Wazuh v3.8.0', + }, + lastPatch: { + description: + '## Manager\r\n\r\n### Added\r\n\r\n- Added support for Arch Linux OS in Vulnerability Detector...', + published_date: '2022-05-05T16:06:52Z', + semver: { + mayor: 3, + minor: 7, + patch: 3, + }, + tag: 'v3.7.3', + title: 'Wazuh v3.7.3', }, - { + }, + { + apiId: 'api 2', + version: '4.1.0', + last_check: '2022-05-05T16:06:52Z', + lastMinor: { description: '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-05-18T10:12:43Z', + published_date: '2022-06-20T13:20:11Z', semver: { mayor: 4, - minor: 3, - patch: 1, + minor: 2, + patch: 0, }, - tag: 'v4.3.1', - title: 'Wazuh v4.3.1', + tag: 'v4.2.0', + title: 'Wazuh v4.2.0', }, - { + lastPatch: { description: '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', - published_date: '2022-06-20T13:20:11Z', + published_date: '2022-05-18T10:12:43Z', semver: { mayor: 4, - minor: 3, - patch: 2, + minor: 1, + patch: 1, }, - tag: 'v4.3.2', - title: 'Wazuh v4.3.2', + tag: 'v4.1.1', + title: 'Wazuh v4.1.1', }, - ], - patch: [], - }, + }, + ], }; export const mockErrorResponse = { diff --git a/plugins/wazuh-check-updates/translations/en-US.json b/plugins/wazuh-check-updates/translations/en-US.json index 95ef8e4cdf..f9153a52cb 100644 --- a/plugins/wazuh-check-updates/translations/en-US.json +++ b/plugins/wazuh-check-updates/translations/en-US.json @@ -87,10 +87,15 @@ "wazuhCheckUpdates.apisUpdateStatus.buttonText": "Check updates", "wazuhCheckUpdates.apisUpdateStatus.onClickButtonError": "Error trying to get updates", "wazuhCheckUpdates.apisUpdateStatus.tableTitle": "Wazuh APIs version", + "wazuhCheckUpdates.apisUpdateStatus.errorCallOut": "Error trying to get updates", "wazuhCheckUpdates.currentUpdateDetails.releaseNotesLink": "Release notes", "wazuhCheckUpdates.currentUpdateDetails.title": "Wazuh new release is available now!", "wazuhCheckUpdates.currentUpdateDetails.upgradeGuideLink": "Upgrade guide", "wazuhCheckUpdates.currentUpdateDetails.showDetails": "Show details", - "wazuhCheckUpdates.dismissNotificationCheck.checkText": "Disable updates notifications" + "wazuhCheckUpdates.dismissNotificationCheck.checkText": "Disable updates notifications", + "wazuhCheckUpdates.updateModal.closeModal": "Close", + "wazuhCheckUpdates.updateModal.publishedDate": "Published", + "wazuhCheckUpdates.updateModal.releaseNotesLink": "Release notes", + "wazuhCheckUpdates.updateModal.upgradeGuideLink": "Upgrade guide" } } From 9533c592659155f91851c6258ffca0356e6aeba6 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Thu, 5 Oct 2023 12:37:25 -0300 Subject: [PATCH 04/17] Improve messages --- .../components/settings/about/appInfo.tsx | 23 +- .../components/apis-update-status/index.tsx | 17 +- .../apis-update-status/table/index.tsx | 6 +- .../components/dismiss-notification-check.tsx | 22 +- .../components/up-to-date-status.test.tsx | 202 ------------------ .../public/components/up-to-date-status.tsx | 144 ------------- .../public/hooks/available-updates.ts | 6 +- plugins/wazuh-check-updates/public/types.ts | 3 +- .../server/cronjob/job-scheduler-run.ts | 5 +- .../translations/en-US.json | 9 +- 10 files changed, 65 insertions(+), 372 deletions(-) delete mode 100644 plugins/wazuh-check-updates/public/components/up-to-date-status.test.tsx delete mode 100644 plugins/wazuh-check-updates/public/components/up-to-date-status.tsx diff --git a/plugins/main/public/components/settings/about/appInfo.tsx b/plugins/main/public/components/settings/about/appInfo.tsx index e40880886b..d47a9c6473 100644 --- a/plugins/main/public/components/settings/about/appInfo.tsx +++ b/plugins/main/public/components/settings/about/appInfo.tsx @@ -1,14 +1,15 @@ import { EuiFlexGroup, EuiFlexItem, - EuiText, EuiSpacer, EuiTitle, EuiHorizontalRule, EuiDescriptionList, + EuiCallOut, } from '@elastic/eui'; -import React from 'react'; +import React, { useState } from 'react'; import { getWazuhCheckUpdatesPlugin } from '../../../kibana-services'; +import { ApiAvailableUpdates } from '../../../../../wazuh-check-updates/common/types'; interface SettingsAboutAppInfoProps { appInfo: { @@ -19,8 +20,14 @@ interface SettingsAboutAppInfoProps { } export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) => { + const [apisAvailableUpdates, setApisAvailableUpdates] = useState(); + const { ApisUpdateStatus } = getWazuhCheckUpdatesPlugin(); + const showVersionWarning = !!apisAvailableUpdates?.find( + (apiAvailableUpdates) => apiAvailableUpdates.version !== appInfo['app-version'] + ); + return ( <> @@ -59,8 +66,18 @@ export const SettingsAboutAppInfo = ({ appInfo }: SettingsAboutAppInfoProps) => />
+ {showVersionWarning ? ( + <> + + + + ) : null} - + ); }; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx index 0b500e71e7..5d4c83ea5a 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -8,17 +8,22 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { useAvailableUpdates } from '../../hooks'; import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; import { DismissNotificationCheck } from '../dismiss-notification-check'; import { ApisUpdateTable } from './table'; import { formatUIDate } from '../../utils'; +import { ApiAvailableUpdates } from '../../../common/types'; + +export interface ApisUpdateStatusProps { + setApisAvailableUpdates: (apisAvailableUpdates: ApiAvailableUpdates[]) => void; +} let toastId = 0; -export const ApisUpdateStatus = () => { +export const ApisUpdateStatus = ({ setApisAvailableUpdates }: ApisUpdateStatusProps) => { const [toasts, setToasts] = useState([]); const addToastHandler = (error: any) => { @@ -42,13 +47,17 @@ export const ApisUpdateStatus = () => { }; const { - apiAvailableUpdates, + apisAvailableUpdates, isLoading, refreshAvailableUpdates, error, lastCheck, } = useAvailableUpdates(); + useEffect(() => { + setApisAvailableUpdates(apisAvailableUpdates); + }, [apisAvailableUpdates]); + if (error) { return ( { - + ); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx index 6cb0c2996f..f7eb0fd827 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx @@ -5,13 +5,13 @@ import { ApiAvailableUpdates } from '../../../../common/types'; export interface ApisUpdateTableProps { isLoading: boolean; - apiAvailableUpdates: ApiAvailableUpdates[]; + apisAvailableUpdates: ApiAvailableUpdates[]; } -export const ApisUpdateTable = ({ isLoading, apiAvailableUpdates }: ApisUpdateTableProps) => { +export const ApisUpdateTable = ({ isLoading, apisAvailableUpdates }: ApisUpdateTableProps) => { return ( { + + {' '} + + } + > + + + } checked={dismissFutureUpdates} onChange={(e) => handleOnChange(e.target.checked)} diff --git a/plugins/wazuh-check-updates/public/components/up-to-date-status.test.tsx b/plugins/wazuh-check-updates/public/components/up-to-date-status.test.tsx deleted file mode 100644 index 839c4267e0..0000000000 --- a/plugins/wazuh-check-updates/public/components/up-to-date-status.test.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import React from 'react'; -import { render, waitFor } from '@testing-library/react'; -import { userEvent } from '@testing-library/user-event'; -import '@testing-library/jest-dom'; -import { UpToDateStatus } from './up-to-date-status'; -import { useAvailableUpdates } from '../hooks'; - -jest.mock( - '../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', - () => ({ - htmlIdGenerator: () => () => 'htmlId', - }) -); - -const mockedUseAvailabeUpdates = useAvailableUpdates as jest.Mock; -jest.mock('../hooks/available-updates'); - -jest.mock('../utils/get-current-available-update', () => ({ - getCurrentAvailableUpdate: jest.fn().mockReturnValue({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - }), -})); - -jest.mock('../utils/time', () => ({ - formatUIDate: jest.fn().mockReturnValue('2023-09-18T14:00:00.000Z'), -})); - -describe('UpToDateStatus component', () => { - test('should render a initial state with a loader and a loader button', () => { - mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: true })); - - const { container, getByRole } = render( - ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - })} - /> - ); - - expect(container).toMatchSnapshot(); - - const loaders = container.getElementsByClassName('euiLoadingSpinner'); - expect(loaders.length).toBe(2); - - const checkUpdatesButton = getByRole('button', { name: 'Check updates' }); - expect(checkUpdatesButton).toBeInTheDocument(); - }); - - test('should render the available updates status with a tooltip and a button to check updates without loaders', async () => { - mockedUseAvailabeUpdates.mockImplementation(() => ({ - availableUpdates: { - last_check: '2023-09-18T14:00:00.000Z', - mayor: [ - { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - }, - ], - minor: [], - patch: [], - }, - isLoading: false, - refreshAvailableUpdates: jest.fn().mockResolvedValue({}), - })); - - const { container, getByRole, getByText } = render( - ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - })} - /> - ); - - expect(container).toMatchSnapshot(); - - const checkUpdatesButton = getByRole('button', { name: 'Check updates' }); - expect(checkUpdatesButton).toBeInTheDocument(); - - const availableUpdates = getByText('Available updates'); - expect(availableUpdates).toBeInTheDocument(); - - const helpIcon = container.getElementsByClassName('euiToolTipAnchor'); - - await userEvent.hover(helpIcon[0]); - waitFor(() => { - expect(getByText('Last check')).toBeInTheDocument(); - expect(getByText('2023-09-18T14:00:00.000Z')).toBeInTheDocument(); - }); - - const loaders = container.getElementsByClassName('euiLoadingSpinner'); - expect(loaders.length).toBe(0); - }); - - test('should retrieve available updates when click the button', async () => { - mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: true })); - - const { container, getByRole, getByText } = render( - ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - })} - /> - ); - - expect(container).toMatchSnapshot(); - - const checkUpdatesButton = getByRole('button', { name: 'Check updates' }); - expect(checkUpdatesButton).toBeInTheDocument(); - await userEvent.click(checkUpdatesButton); - waitFor(async () => { - const availableUpdates = getByText('Available updates'); - expect(availableUpdates).toBeInTheDocument(); - - const helpIcon = container.getElementsByClassName('euiToolTipAnchor'); - - await userEvent.hover(helpIcon[0]); - waitFor(() => { - expect(getByText('Last check')).toBeInTheDocument(); - expect(getByText('2023-09-18T14:00:00.000Z')).toBeInTheDocument(); - }); - - const loaders = container.getElementsByClassName('euiLoadingSpinner'); - expect(loaders.length).toBe(0); - }); - }); - - test('should render a initial state with an error', () => { - mockedUseAvailabeUpdates.mockImplementation(() => ({ - isLoading: false, - error: 'This is an error', - })); - - const { container, getByText } = render( - ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - mayor: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - })} - /> - ); - - expect(container).toMatchSnapshot(); - - const loaders = container.getElementsByClassName('euiLoadingSpinner'); - expect(loaders.length).toBe(0); - - const availableUpdates = getByText('Error trying to get available updates'); - expect(availableUpdates).toBeInTheDocument(); - }); -}); diff --git a/plugins/wazuh-check-updates/public/components/up-to-date-status.tsx b/plugins/wazuh-check-updates/public/components/up-to-date-status.tsx deleted file mode 100644 index fa8b823abe..0000000000 --- a/plugins/wazuh-check-updates/public/components/up-to-date-status.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiGlobalToastList, - EuiHealth, - EuiIconTip, - EuiLoadingSpinner, -} from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; -import { useAvailableUpdates } from '../hooks'; -import { formatUIDate, getCurrentAvailableUpdate } from '../utils'; -import { Update } from '../../common/types'; -import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; - -export interface UpToDateStatusProps { - setCurrentUpdate: (currentUpdate?: Update) => void; -} - -let toastId = 0; - -export const UpToDateStatus = ({ setCurrentUpdate }: UpToDateStatusProps) => { - const [toasts, setToasts] = useState([]); - - const addToastHandler = (error: any) => { - const toast = { - id: `${toastId++}`, - title: ( - - ), - color: 'danger', - iconType: 'alert', - text: error?.body?.message, - } as Toast; - setToasts(toasts.concat(toast)); - }; - - const removeToast = (removedToast: Toast) => { - setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); - }; - - const { availableUpdates, isLoading, refreshAvailableUpdates, error } = useAvailableUpdates(); - - const handleOnClick = async () => { - const response = await refreshAvailableUpdates(true, true); - if (response instanceof Error) { - addToastHandler(response); - } - }; - - useEffect(() => { - setCurrentUpdate(getCurrentAvailableUpdate(availableUpdates)); - }, [availableUpdates]); - - const currentUpdate = getCurrentAvailableUpdate(availableUpdates); - - const isUpToDate = !currentUpdate; - - const getI18nMessageId = () => { - if (error) { - return 'getAvailableUpdatesError'; - } - if (isUpToDate) { - return 'upToDate'; - } - return 'availableUpdates'; - }; - - const getDefaultMessage = () => { - if (error) { - return 'Error trying to get available updates'; - } - if (isUpToDate) { - return 'Up to date'; - } - return 'Available updates'; - }; - - const getColor = () => { - if (error) { - return 'danger'; - } - if (isUpToDate) { - return 'success'; - } - return 'warning'; - }; - - return ( - - - - {!isLoading ? ( - - - - - - - - - } - content={ - availableUpdates?.last_check - ? formatUIDate(new Date(availableUpdates.last_check)) - : '-' - } - iconProps={{ - className: 'eui-alignTop', - }} - /> - - - ) : ( - - )} - - - - - - - - - - ); -}; diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.ts index 01bd58af0e..98c332384a 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.ts @@ -4,7 +4,7 @@ import { routes } from '../../common/constants'; import { getCore } from '../plugin-services'; export const useAvailableUpdates = () => { - const [apiAvailableUpdates, setApiAvailableUpdates] = useState([]); + const [apisAvailableUpdates, setApisAvailableUpdates] = useState([]); const [lastCheck, setLastCheck] = useState(); const [isLoading, setIsLoading] = useState(true); @@ -18,7 +18,7 @@ export const useAvailableUpdates = () => { checkAvailableUpdates: forceUpdate, }, }); - setApiAvailableUpdates(response?.apiAvailableUpdates || []); + setApisAvailableUpdates(response?.apiAvailableUpdates || []); setLastCheck(response?.last_check); setError(undefined); } catch (error: any) { @@ -39,5 +39,5 @@ export const useAvailableUpdates = () => { refreshAvailableUpdates(); }, []); - return { isLoading, apiAvailableUpdates, refreshAvailableUpdates, error, lastCheck }; + return { isLoading, apisAvailableUpdates, refreshAvailableUpdates, error, lastCheck }; }; diff --git a/plugins/wazuh-check-updates/public/types.ts b/plugins/wazuh-check-updates/public/types.ts index ecac2cdfa7..154c4d5243 100644 --- a/plugins/wazuh-check-updates/public/types.ts +++ b/plugins/wazuh-check-updates/public/types.ts @@ -1,10 +1,11 @@ import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; +import { ApisUpdateStatusProps } from './components/apis-update-status'; export interface WazuhCheckUpdatesPluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface WazuhCheckUpdatesPluginStart { UpdatesNotification: () => JSX.Element | null; - ApisUpdateStatus: () => JSX.Element; + ApisUpdateStatus: (props: ApisUpdateStatusProps) => JSX.Element; } export interface AppPluginStartDependencies { diff --git a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.ts b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.ts index caa337adf7..b33975eb43 100644 --- a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.ts +++ b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.ts @@ -6,9 +6,12 @@ import { log } from '../lib/logger'; export const jobSchedulerRun = async () => { try { + //The first time should get the updates from the Wazuh API + await getUpdates(true); + const settings = await getSettings(); - cron.schedule(settings?.schedule || DEFAULT_SCHEDULE, () => getUpdates()); + cron.schedule(settings?.schedule || DEFAULT_SCHEDULE, () => getUpdates(true)); } catch (error) { const message = error instanceof Error diff --git a/plugins/wazuh-check-updates/translations/en-US.json b/plugins/wazuh-check-updates/translations/en-US.json index f9153a52cb..ab07a444fc 100644 --- a/plugins/wazuh-check-updates/translations/en-US.json +++ b/plugins/wazuh-check-updates/translations/en-US.json @@ -82,17 +82,14 @@ "wazuhCheckUpdates.updatesNotification.closeButtonText": "Close", "wazuhCheckUpdates.apisUpdateStatus.upToDate": "Up to date", "wazuhCheckUpdates.apisUpdateStatus.availableUpdates": "Available updates", - "wazuhCheckUpdates.apisUpdateStatus.getAvailableUpdatesError": "Error trying to get available updates", + "wazuhCheckUpdates.apisUpdateStatus.error": "Error checking updates", "wazuhCheckUpdates.apisUpdateStatus.lastCheck": "Last check", "wazuhCheckUpdates.apisUpdateStatus.buttonText": "Check updates", "wazuhCheckUpdates.apisUpdateStatus.onClickButtonError": "Error trying to get updates", "wazuhCheckUpdates.apisUpdateStatus.tableTitle": "Wazuh APIs version", - "wazuhCheckUpdates.apisUpdateStatus.errorCallOut": "Error trying to get updates", - "wazuhCheckUpdates.currentUpdateDetails.releaseNotesLink": "Release notes", - "wazuhCheckUpdates.currentUpdateDetails.title": "Wazuh new release is available now!", - "wazuhCheckUpdates.currentUpdateDetails.upgradeGuideLink": "Upgrade guide", - "wazuhCheckUpdates.currentUpdateDetails.showDetails": "Show details", + "wazuhCheckUpdates.apisUpdateStatus.errorCallOut": "Error trying to get APIs version and available updates", "wazuhCheckUpdates.dismissNotificationCheck.checkText": "Disable updates notifications", + "wazuhCheckUpdates.dismissNotificationCheck.checkHelp": "This setting determines if a notification will appear every time an update is released", "wazuhCheckUpdates.updateModal.closeModal": "Close", "wazuhCheckUpdates.updateModal.publishedDate": "Published", "wazuhCheckUpdates.updateModal.releaseNotesLink": "Release notes", From dd950edaedfe91da7b8dba808a66c83836c2be8f Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Thu, 5 Oct 2023 15:41:38 -0300 Subject: [PATCH 05/17] Improve notification --- plugins/main/public/app.js | 51 +++++++--------- plugins/main/public/components/index.js | 2 + .../wz-updates-notification/index.tsx | 21 +++++++ .../wazuh-check-updates/common/constants.ts | 2 +- plugins/wazuh-check-updates/common/types.ts | 9 ++- .../components/updates-notification.tsx | 58 ++++++++++--------- .../public/plugin-services.ts | 3 +- plugins/wazuh-check-updates/public/plugin.ts | 3 +- .../public/utils/are-there-new-updates.ts | 26 +++++++++ .../wazuh-check-updates/public/utils/index.ts | 1 + .../saved-object/types/user-preferences.ts | 18 +++++- .../translations/en-US.json | 4 +- 12 files changed, 135 insertions(+), 63 deletions(-) create mode 100644 plugins/main/public/components/wz-updates-notification/index.tsx create mode 100644 plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts diff --git a/plugins/main/public/app.js b/plugins/main/public/app.js index c497f9d8d9..bc098e5373 100644 --- a/plugins/main/public/app.js +++ b/plugins/main/public/app.js @@ -58,9 +58,7 @@ const app = getAngularModule(); app.config([ '$compileProvider', function ($compileProvider) { - $compileProvider.aHrefSanitizationWhitelist( - /^\s*(https?|ftp|mailto|data|blob):/, - ); + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|data|blob):/); }, ]); @@ -79,7 +77,7 @@ app.run([ // Set currentSecurity platform in Redux when app starts. checkCurrentSecurityPlatform() - .then(item => { + .then((item) => { store.dispatch(updateCurrentPlatform(item)); }) .catch(() => {}); @@ -103,35 +101,30 @@ app.run(function ($rootElement) { + `); // Add plugin help links as extension to plugin platform help menu addHelpMenuToAppChrome(); // Bind deleteExistentToken on Log out component. - $('.euiHeaderSectionItem__button, .euiHeaderSectionItemButton').on( - 'mouseleave', - function () { - // opendistro - $('button:contains(Log out)').on('click', function () { - WzAuthentication.deleteExistentToken(); - }); - // x-pack - $('a:contains(Log out)').on('click', function (event) { - // Override href's behaviour and navigate programatically - // to the logout path once the token has been deleted. - event.preventDefault(); - WzAuthentication.deleteExistentToken() - .catch(err => { - console.error( - '[ERROR] - User token could not be deprecated - ', - err, - ); - }) - .finally(() => { - window.location = event.currentTarget.href; - }); - }); - }, - ); + $('.euiHeaderSectionItem__button, .euiHeaderSectionItemButton').on('mouseleave', function () { + // opendistro + $('button:contains(Log out)').on('click', function () { + WzAuthentication.deleteExistentToken(); + }); + // x-pack + $('a:contains(Log out)').on('click', function (event) { + // Override href's behaviour and navigate programatically + // to the logout path once the token has been deleted. + event.preventDefault(); + WzAuthentication.deleteExistentToken() + .catch((err) => { + console.error('[ERROR] - User token could not be deprecated - ', err); + }) + .finally(() => { + window.location = event.currentTarget.href; + }); + }); + }); }); diff --git a/plugins/main/public/components/index.js b/plugins/main/public/components/index.js index 577910fdf0..e547529f37 100644 --- a/plugins/main/public/components/index.js +++ b/plugins/main/public/components/index.js @@ -20,6 +20,7 @@ import { ClusterTimelions } from '../components/management/cluster/cluster-timel import { KibanaVisWrapper } from '../components/management/cluster/cluster-visualization'; import { ToastNotificationsModal } from '../components/notifications/modal'; import { getAngularModule } from '../kibana-services'; +import { WzUpdatesNotification } from './wz-updates-notification'; const app = getAngularModule(); @@ -32,3 +33,4 @@ app.value('ClusterDisabled', ClusterDisabled); app.value('ClusterTimelions', ClusterTimelions); app.value('KibanaVisualization', KibanaVisWrapper); app.value('ToastNotificationsModal', ToastNotificationsModal); +app.value('WzUpdatesNotification', WzUpdatesNotification); diff --git a/plugins/main/public/components/wz-updates-notification/index.tsx b/plugins/main/public/components/wz-updates-notification/index.tsx new file mode 100644 index 0000000000..fd4abcc29b --- /dev/null +++ b/plugins/main/public/components/wz-updates-notification/index.tsx @@ -0,0 +1,21 @@ +/* + * Wazuh app - React Component component to display new updates notification. + * + * Copyright (C) 2015-2023 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 from 'react'; +import { getWazuhCheckUpdatesPlugin } from '../../kibana-services'; + +export const WzUpdatesNotification = () => { + const { UpdatesNotification } = getWazuhCheckUpdatesPlugin(); + + return ; +}; diff --git a/plugins/wazuh-check-updates/common/constants.ts b/plugins/wazuh-check-updates/common/constants.ts index 38de2b9ac6..cbae893561 100644 --- a/plugins/wazuh-check-updates/common/constants.ts +++ b/plugins/wazuh-check-updates/common/constants.ts @@ -7,7 +7,7 @@ export const SAVED_OBJECT_UPDATES = 'wazuh-check-updates-available-updates'; export const SAVED_OBJECT_SETTINGS = 'wazuh-check-updates-settings'; export const SAVED_OBJECT_USER_PREFERENCES = 'wazuh-check-updates-user-preferences'; -export const DEFAULT_SCHEDULE = '* */24 * * *'; +export const DEFAULT_SCHEDULE = '0 0 * * *'; export enum routes { checkUpdates = '/api/wazuh-check-updates/updates', diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index 6086d3ac3d..efdbedcd61 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -29,8 +29,15 @@ export interface Update { title: string; } +export interface UserPreferencesDimissedUpdate { + apiId: string; + mayor?: string; + minor?: string; + patch?: string; +} + export interface UserPreferences { - last_dismissed_update?: string; + last_dismissed_updates?: UserPreferencesDimissedUpdate[]; hide_update_notifications?: boolean; } diff --git a/plugins/wazuh-check-updates/public/components/updates-notification.tsx b/plugins/wazuh-check-updates/public/components/updates-notification.tsx index 021b3ecb83..d44930edd1 100644 --- a/plugins/wazuh-check-updates/public/components/updates-notification.tsx +++ b/plugins/wazuh-check-updates/public/components/updates-notification.tsx @@ -2,6 +2,7 @@ import { EuiBadge, EuiBottomBar, EuiButton, + EuiButtonEmpty, EuiCheckbox, EuiFlexGroup, EuiFlexItem, @@ -11,7 +12,9 @@ import { import React, { useState } from 'react'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { useAvailableUpdates, useUserPreferences } from '../hooks'; -import { getCurrentAvailableUpdate } from '../utils'; +import { areThereNewUpdates } from '../utils'; +import { last } from 'lodash'; +import { getHttp } from '../plugin-services'; export const UpdatesNotification = () => { const [isDismissed, setIsDismissed] = useState(false); @@ -25,7 +28,7 @@ export const UpdatesNotification = () => { } = useUserPreferences(); const { - availableUpdates, + apisAvailableUpdates, error: getAvailableUpdatesError, isLoading: isLoadingAvailableUpdates, } = useAvailableUpdates(); @@ -42,18 +45,16 @@ export const UpdatesNotification = () => { return null; } - const currentUpdate = getCurrentAvailableUpdate(availableUpdates); - - const hideNotification = - userPreferences?.hide_update_notifications || - userPreferences?.last_dismissed_update === currentUpdate?.tag; - - if (hideNotification) { + if (userPreferences?.hide_update_notifications) { return null; } - const releaseNotesUrl = `https://documentation.wazuh.com/${currentUpdate?.semver.mayor}.${currentUpdate?.semver.minor}/release-notes/release-${currentUpdate?.semver.mayor}-${currentUpdate?.semver.minor}-${currentUpdate?.semver.patch}.html`; - const isVisible = !isDismissed && !!currentUpdate; + if (isDismissed) return null; + + const mustNotifyUser = areThereNewUpdates( + apisAvailableUpdates, + userPreferences.last_dismissed_updates + ); const handleOnChangeDismiss = (checked: boolean) => { setDismissFutureUpdates(checked); @@ -61,15 +62,23 @@ export const UpdatesNotification = () => { const handleOnClose = () => { updateUserPreferences({ - last_dismissed_update: currentUpdate?.tag, + last_dismissed_updates: apisAvailableUpdates.map((apiAvailableUpdates) => { + const { apiId, lastMayor, lastMinor, lastPatch } = apiAvailableUpdates; + return { + apiId, + mayor: lastMayor?.tag, + minor: lastMinor?.tag, + patch: lastPatch?.tag, + }; + }), ...(dismissFutureUpdates ? { hide_update_notifications: true } : {}), }); setIsDismissed(true); }; - return isVisible ? ( + return mustNotifyUser ? ( - + @@ -77,28 +86,25 @@ export const UpdatesNotification = () => { - {currentUpdate.tag} - - - + + + + {/* { } - + */} diff --git a/plugins/wazuh-check-updates/public/plugin-services.ts b/plugins/wazuh-check-updates/public/plugin-services.ts index de618c9e18..e1d3a1e434 100644 --- a/plugins/wazuh-check-updates/public/plugin-services.ts +++ b/plugins/wazuh-check-updates/public/plugin-services.ts @@ -1,5 +1,6 @@ -import { CoreStart, IUiSettingsClient } from 'opensearch-dashboards/public'; +import { CoreStart, HttpStart, IUiSettingsClient } from 'opensearch-dashboards/public'; import { createGetterSetter } from '../../../src/plugins/opensearch_dashboards_utils/common'; export const [getCore, setCore] = createGetterSetter('Core'); export const [getUiSettings, setUiSettings] = createGetterSetter('UiSettings'); +export const [getHttp, setHttp] = createGetterSetter('Http'); diff --git a/plugins/wazuh-check-updates/public/plugin.ts b/plugins/wazuh-check-updates/public/plugin.ts index b3f5f2d393..1447799c67 100644 --- a/plugins/wazuh-check-updates/public/plugin.ts +++ b/plugins/wazuh-check-updates/public/plugin.ts @@ -1,7 +1,7 @@ import { CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; import { WazuhCheckUpdatesPluginSetup, WazuhCheckUpdatesPluginStart } from './types'; import { UpdatesNotification } from './components/updates-notification'; -import { setCore, setUiSettings } from './plugin-services'; +import { setCore, setUiSettings, setHttp } from './plugin-services'; import { ApisUpdateStatus } from './components/apis-update-status'; export class WazuhCheckUpdatesPlugin @@ -13,6 +13,7 @@ export class WazuhCheckUpdatesPlugin public start(core: CoreStart): WazuhCheckUpdatesPluginStart { setCore(core); setUiSettings(core.uiSettings); + setHttp(core.http); return { UpdatesNotification, diff --git a/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts new file mode 100644 index 0000000000..0d0ec5fe2d --- /dev/null +++ b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts @@ -0,0 +1,26 @@ +import { ApiAvailableUpdates, UserPreferencesDimissedUpdate } from '../../common/types'; + +export const areThereNewUpdates = ( + apisAvailableUpdates?: ApiAvailableUpdates[], + lastDismissedUpdates?: UserPreferencesDimissedUpdate[] +) => { + const notifyUser = !!apisAvailableUpdates?.find((apiAvailableUpdates) => { + const { apiId, lastMayor, lastMinor, lastPatch } = apiAvailableUpdates; + + const apiDismissed = lastDismissedUpdates?.find( + (lastDismissedUpdate) => lastDismissedUpdate.apiId === apiId + ); + + if (!apiDismissed && (lastMayor?.tag || lastMinor?.tag || lastPatch?.tag)) { + return true; + } + + const isNewMajor = lastMayor?.tag && lastMayor.tag !== apiDismissed?.mayor; + const isNewMinor = lastMinor?.tag && lastMinor.tag !== apiDismissed?.minor; + const isNewPatch = lastPatch?.tag && lastPatch.tag !== apiDismissed?.patch; + + return isNewMajor || isNewMinor || isNewPatch; + }); + + return notifyUser; +}; diff --git a/plugins/wazuh-check-updates/public/utils/index.ts b/plugins/wazuh-check-updates/public/utils/index.ts index b2b8c8fe08..564140e0d6 100644 --- a/plugins/wazuh-check-updates/public/utils/index.ts +++ b/plugins/wazuh-check-updates/public/utils/index.ts @@ -1 +1,2 @@ export { formatUIDate } from './time'; +export { areThereNewUpdates } from './are-there-new-updates'; diff --git a/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts b/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts index 128bacc7c7..a59ccfe503 100644 --- a/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts +++ b/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts @@ -7,8 +7,22 @@ export const userPreferencesObject: SavedObjectsType = { namespaceType: 'agnostic', mappings: { properties: { - last_dismissed_update: { - type: 'text', + last_dismissed_updates: { + type: 'nested', + properties: { + apiId: { + type: 'text', + }, + mayor: { + type: 'text', + }, + minor: { + type: 'text', + }, + patch: { + type: 'text', + }, + }, }, hide_update_notifications: { type: 'boolean', diff --git a/plugins/wazuh-check-updates/translations/en-US.json b/plugins/wazuh-check-updates/translations/en-US.json index ab07a444fc..e4dfab80b7 100644 --- a/plugins/wazuh-check-updates/translations/en-US.json +++ b/plugins/wazuh-check-updates/translations/en-US.json @@ -76,8 +76,8 @@ } }, "messages": { - "wazuhCheckUpdates.updatesNotification.message": "Wazuh new release is available now!", - "wazuhCheckUpdates.updatesNotification.linkText": "Go to the release notes for details", + "wazuhCheckUpdates.updatesNotification.message": "Wazuh new release is available!", + "wazuhCheckUpdates.updatesNotification.linkText": "Go to the about page for details", "wazuhCheckUpdates.updatesNotification.dismissCheckText": "Disable updates notifications", "wazuhCheckUpdates.updatesNotification.closeButtonText": "Close", "wazuhCheckUpdates.apisUpdateStatus.upToDate": "Up to date", From 5985c31aaaed60a4f767162dd9a2eb45851d794a Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Fri, 6 Oct 2023 17:45:13 -0300 Subject: [PATCH 06/17] Change camelCase for snake_case in API response --- plugins/wazuh-check-updates/common/types.ts | 26 +- .../current-update-details.test.tsx.snap | 193 ----------- .../dismiss-notification-check.test.tsx.snap | 26 -- .../up-to-date-status.test.tsx.snap | 315 ------------------ .../updates-notification.test.tsx.snap | 13 - .../components/apis-update-status/index.tsx | 82 ++--- .../table/columns/index.tsx | 10 +- .../table/columns/update-badge.tsx | 138 ++++---- .../apis-update-status/update-details.tsx | 93 ------ .../current-update-details.test.tsx | 56 ---- .../components/current-update-details.tsx | 97 ------ .../components/updates-notification.test.tsx | 30 +- .../components/updates-notification.tsx | 26 +- .../public/hooks/available-updates.test.ts | 18 +- .../public/hooks/available-updates.ts | 10 +- .../public/hooks/user-preferences.ts | 2 +- .../public/utils/are-there-new-updates.ts | 23 +- .../server/cronjob/job-scheduler-run.test.ts | 3 + .../server/routes/updates/get-updates.test.ts | 12 +- .../update-user-preferences.ts | 11 +- .../saved-object/types/available-updates.ts | 18 +- .../saved-object/types/user-preferences.ts | 8 +- .../server/services/updates/get-updates.ts | 8 +- .../server/services/updates/mocks.ts | 38 +-- 24 files changed, 242 insertions(+), 1014 deletions(-) delete mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/current-update-details.test.tsx.snap delete mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap delete mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/up-to-date-status.test.tsx.snap delete mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap delete mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx delete mode 100644 plugins/wazuh-check-updates/public/components/current-update-details.test.tsx delete mode 100644 plugins/wazuh-check-updates/public/components/current-update-details.tsx diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index efdbedcd61..3141c46453 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -5,12 +5,12 @@ export enum API_UPDATES_STATUS { } export interface ResponseApiAvailableUpdates { - apiId: string; - version: string; - lastMayor?: Update; - lastMinor?: Update; - lastPatch?: Update; - last_check?: Date | string | undefined; + api_id: string; + current_version: string; + last_available_major?: Update; + last_available_minor?: Update; + last_available_patch?: Update; + last_check_date?: Date | string | undefined; } export interface ApiAvailableUpdates extends ResponseApiAvailableUpdates { @@ -21,7 +21,7 @@ export interface Update { description: string; published_date: string; semver: { - mayor: number; + major: number; minor: number; patch: number; }; @@ -30,10 +30,10 @@ export interface Update { } export interface UserPreferencesDimissedUpdate { - apiId: string; - mayor?: string; - minor?: string; - patch?: string; + api_id: string; + last_major?: string; + last_minor?: string; + last_patch?: string; } export interface UserPreferences { @@ -46,8 +46,8 @@ export interface CheckUpdatesSettings { } export interface AvailableUpdates { - apiAvailableUpdates: ApiAvailableUpdates[]; - last_check: Date; + apis_available_updates: ApiAvailableUpdates[]; + last_check_date: Date; } export type savedObjectType = AvailableUpdates | UserPreferences | CheckUpdatesSettings; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/current-update-details.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/current-update-details.test.tsx.snap deleted file mode 100644 index ca5d07a489..0000000000 --- a/plugins/wazuh-check-updates/public/components/__snapshots__/current-update-details.test.tsx.snap +++ /dev/null @@ -1,193 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CurrentUpdateDetails component should render the current update tag and links to the Relese Notes and the Upgrade Guide 1`] = ` -
-
-
- - -
-
- Wazuh new release is available now! -
-
- - - - 4.2.6 - - - -
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-

- Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements. -

-
-
-
-
-
-
-
-
-
-`; - -exports[`CurrentUpdateDetails component should return null when there is no current update 1`] = `
`; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap deleted file mode 100644 index ef72b03992..0000000000 --- a/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DismissNotificationCheck component should render the check 1`] = ` -
-
- -
- -
-
-`; - -exports[`DismissNotificationCheck component should return null when there is an error 1`] = `
`; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/up-to-date-status.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/up-to-date-status.test.tsx.snap deleted file mode 100644 index 14cc6eca30..0000000000 --- a/plugins/wazuh-check-updates/public/components/__snapshots__/up-to-date-status.test.tsx.snap +++ /dev/null @@ -1,315 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UpToDateStatus component should render a initial state with a loader and a loader button 1`] = ` -
-
-
- -
-
- -
-
-
-
-`; - -exports[`UpToDateStatus component should render a initial state with an error 1`] = ` -
-
-
-
-
-
-
-
- -
-
- Error trying to get available updates -
-
-
-
-
- - - - - -
-
-
-
- -
-
-
-
-`; - -exports[`UpToDateStatus component should render the available updates status with a tooltip and a button to check updates without loaders 1`] = ` -
-
-
-
-
-
-
-
- -
-
- Available updates -
-
-
-
-
- - - -
-
-
-
- -
-
-
-
-`; - -exports[`UpToDateStatus component should retrieve available updates when click the button 1`] = ` -
-
-
- -
-
- -
-
-
-
-`; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap deleted file mode 100644 index 5e205ef07e..0000000000 --- a/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UpdatesNotification component should return null when is loading 1`] = `
`; - -exports[`UpdatesNotification component should return null when there are no available updates 1`] = `
`; - -exports[`UpdatesNotification component should return null when user already dismissed the notifications for current update 1`] = `
`; - -exports[`UpdatesNotification component should return null when user close notification 1`] = `
`; - -exports[`UpdatesNotification component should return null when user dismissed notifications for future 1`] = `
`; - -exports[`UpdatesNotification component should return the nofication component 1`] = `
`; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx index 5d4c83ea5a..4ac500e4a3 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -82,49 +82,51 @@ export const ApisUpdateStatus = ({ setApisAvailableUpdates }: ApisUpdateStatusPr return ( - -

- -

-
- - - - + <> + +

- - - {lastCheck ? ( - - - ), - description: formatUIDate(new Date(lastCheck)), - }, - ]} + id={`wazuhCheckUpdates.apisUpdateStatus.tableTitle`} + defaultMessage="Wazuh APIs version" /> +

+
+ + + + + + + + {lastCheck ? ( + + + ), + description: formatUIDate(new Date(lastCheck)), + }, + ]} + /> + + ) : null} + + - ) : null} - - - - - - - +
+ + + +
); }; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx index 4926504e8d..a564175508 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/index.tsx @@ -7,12 +7,12 @@ import { UpdateBadge } from './update-badge'; export const getApisUpdateStatusColumns = () => { const baseColumns = [ { - field: 'apiId', + field: 'api_id', name: 'ID', width: '100px', }, { - field: 'version', + field: 'current_version', name: 'Version', width: '100px', }, @@ -65,9 +65,9 @@ export const getApisUpdateStatusColumns = () => { const finalColumns = [ ...baseColumns, - updatesColumn('lastMayor', 'Last major'), - updatesColumn('lastMinor', 'Last minor'), - updatesColumn('lastPatch', 'Last patch'), + updatesColumn('last_available_major', 'Last major'), + updatesColumn('last_available_minor', 'Last minor'), + updatesColumn('last_available_patch', 'Last patch'), ]; return finalColumns; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx index d784892e24..2aebc39e50 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx @@ -2,7 +2,6 @@ import React, { useState, MouseEvent } from 'react'; import { Update } from '../../../../../common/types'; import { EuiBadge, - EuiButtonEmpty, EuiDescriptionList, EuiModal, EuiModalBody, @@ -14,6 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, + EuiButton, } from '@elastic/eui'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { Markdown } from '../../../../../../../src/plugins/opensearch_dashboards_react/public'; @@ -36,81 +36,83 @@ export const UpdateBadge = ({ update }: UpdateProps) => { setIsModalVisible(false); }; - const minorVersion = `${semver.mayor}.${semver.minor}`; - const releaseNotesUrl = `https://documentation.wazuh.com/${minorVersion}/release-notes/release-${semver.mayor}-${semver.minor}-${semver.patch}.html`; + const minorVersion = `${semver.major}.${semver.minor}`; + const releaseNotesUrl = `https://documentation.wazuh.com/${minorVersion}/release-notes/release-${semver.major}-${semver.minor}-${semver.patch}.html`; const upgradeGuideUrl = `https://documentation.wazuh.com/${minorVersion}/upgrade-guide/index.html`; return ( - ) => { - e.stopPropagation(); - }} - onClick={(e: MouseEvent) => { - e.stopPropagation(); - handleOnClickBadge(); - }} - style={{ maxWidth: 'max-content' }} - > - {tag} - - {isModalVisible ? ( - - - - {title} - + <> + ) => { + e.stopPropagation(); + }} + onClick={(e: MouseEvent) => { + e.stopPropagation(); + handleOnClickBadge(); + }} + style={{ maxWidth: 'max-content' }} + > + {tag} + + {isModalVisible ? ( + + + + {title} + - - + + ), + description: formatUIDate(new Date(published_date)), + }, + ]} + /> + + + + + + + + + - ), - description: formatUIDate(new Date(published_date)), - }, - ]} - /> - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - ) : null} + + + + + + + + ) : null} + ); }; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx deleted file mode 100644 index 3b6bd5d241..0000000000 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/update-details.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import { - EuiAccordion, - EuiBadge, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiHeaderLink, - EuiText, - EuiSpacer, -} from '@elastic/eui'; -import { Update } from '../../../common/types'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; - -export interface UpdateDetailsProps { - update: Update; -} - -export const UpdateDetails = ({ update }: UpdateDetailsProps) => { - const release = `${update?.semver.mayor}.${update?.semver.minor}`; - const releaseNotesUrl = `https://documentation.wazuh.com/${release}/release-notes/release-${update.semver.mayor}-${update.semver.minor}-${update.semver.patch}.html`; - const upgradeGuideUrl = `https://documentation.wazuh.com/${release}/upgrade-guide/index.html`; - - return ( - - - - - - - {update.tag} - - - } - color="warning" - iconType="bell" - > - - - - - - - - - - - - - - - } - paddingSize="m" - > - - {update.description.split('\r\n').map((line, index) => ( -

{line}

- ))} -
-
-
-
- ); -}; diff --git a/plugins/wazuh-check-updates/public/components/current-update-details.test.tsx b/plugins/wazuh-check-updates/public/components/current-update-details.test.tsx deleted file mode 100644 index 865bd1bc1c..0000000000 --- a/plugins/wazuh-check-updates/public/components/current-update-details.test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import { CurrentUpdateDetails } from './current-update-details'; - -jest.mock( - '../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', - () => ({ - htmlIdGenerator: () => () => 'htmlId', - }) -); - -describe('CurrentUpdateDetails component', () => { - test('should render the current update tag and links to the Relese Notes and the Upgrade Guide', () => { - const { container, getByText, getByRole } = render( - // - - // - ); - - expect(container).toMatchSnapshot(); - - const elementWithTag = getByText('4.2.6'); - expect(elementWithTag).toBeInTheDocument(); - - const releaseNotesUrl = 'https://documentation.wazuh.com/4.2/release-notes/release-4-2-6.html'; - const releaseNotesLink = getByRole('link', { name: 'Release notes' }); - expect(releaseNotesLink).toHaveAttribute('href', releaseNotesUrl); - - const upgradeGuideUrl = `https://documentation.wazuh.com/4.2/upgrade-guide/index.html`; - const upgradeGuideLink = getByRole('link', { name: 'Upgrade guide' }); - expect(upgradeGuideLink).toHaveAttribute('href', upgradeGuideUrl); - }); - - test('should return null when there is no current update', () => { - const { container } = render(); - - expect(container).toMatchSnapshot(); - - const firstChild = container.firstChild; - expect(firstChild).toBeNull(); - }); -}); diff --git a/plugins/wazuh-check-updates/public/components/current-update-details.tsx b/plugins/wazuh-check-updates/public/components/current-update-details.tsx deleted file mode 100644 index b004603773..0000000000 --- a/plugins/wazuh-check-updates/public/components/current-update-details.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react'; -import { - EuiAccordion, - EuiBadge, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiHeaderLink, - EuiText, - EuiSpacer, -} from '@elastic/eui'; -import { Update } from '../../common/types'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; - -export interface CurrentUpdateDetailsProps { - currentUpdate?: Update; -} - -export const CurrentUpdateDetails = ({ currentUpdate }: CurrentUpdateDetailsProps) => { - if (!currentUpdate) { - return null; - } - - const currentRelease = `${currentUpdate?.semver.mayor}.${currentUpdate?.semver.minor}`; - const releaseNotesUrl = `https://documentation.wazuh.com/${currentRelease}/release-notes/release-${currentUpdate.semver.mayor}-${currentUpdate.semver.minor}-${currentUpdate.semver.patch}.html`; - const upgradeGuideUrl = `https://documentation.wazuh.com/${currentRelease}/upgrade-guide/index.html`; - - return ( - - - - - - - {currentUpdate.tag} - - - } - color="warning" - iconType="bell" - > - - - - - - - - - - - - - - - } - paddingSize="m" - > - - {currentUpdate.description.split('\r\n').map((line, index) => ( -

{line}

- ))} -
-
-
-
- ); -}; diff --git a/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx b/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx index 01c8804391..21377e5471 100644 --- a/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx +++ b/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx @@ -27,15 +27,15 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, availableUpdates: { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -56,7 +56,7 @@ describe('UpdatesNotification component', () => { 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -88,15 +88,15 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, availableUpdates: { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -118,7 +118,7 @@ describe('UpdatesNotification component', () => { 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -173,15 +173,15 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, availableUpdates: { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -209,15 +209,15 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, availableUpdates: { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -238,7 +238,7 @@ describe('UpdatesNotification component', () => { 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, diff --git a/plugins/wazuh-check-updates/public/components/updates-notification.tsx b/plugins/wazuh-check-updates/public/components/updates-notification.tsx index d44930edd1..c6dc951fcf 100644 --- a/plugins/wazuh-check-updates/public/components/updates-notification.tsx +++ b/plugins/wazuh-check-updates/public/components/updates-notification.tsx @@ -1,19 +1,16 @@ import { - EuiBadge, EuiBottomBar, EuiButton, EuiButtonEmpty, EuiCheckbox, EuiFlexGroup, EuiFlexItem, - EuiHeaderLink, EuiText, } from '@elastic/eui'; import React, { useState } from 'react'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { useAvailableUpdates, useUserPreferences } from '../hooks'; import { areThereNewUpdates } from '../utils'; -import { last } from 'lodash'; import { getHttp } from '../plugin-services'; export const UpdatesNotification = () => { @@ -63,12 +60,17 @@ export const UpdatesNotification = () => { const handleOnClose = () => { updateUserPreferences({ last_dismissed_updates: apisAvailableUpdates.map((apiAvailableUpdates) => { - const { apiId, lastMayor, lastMinor, lastPatch } = apiAvailableUpdates; + const { + api_id, + last_available_major, + last_available_minor, + last_available_patch, + } = apiAvailableUpdates; return { - apiId, - mayor: lastMayor?.tag, - minor: lastMinor?.tag, - patch: lastPatch?.tag, + api_id, + last_major: last_available_major?.tag, + last_minor: last_available_minor?.tag, + last_patch: last_available_patch?.tag, }; }), ...(dismissFutureUpdates ? { hide_update_notifications: true } : {}), @@ -97,14 +99,6 @@ export const UpdatesNotification = () => { defaultMessage="Go to the about page for details" /> - {/* - { - - } - */} diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.test.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.test.ts index f39de11ffb..beeb4c7b0f 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.test.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.test.ts @@ -7,15 +7,15 @@ jest.mock('../plugin-services', () => ({ getCore: jest.fn().mockReturnValue({ http: { get: jest.fn().mockResolvedValue({ - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -32,15 +32,15 @@ jest.mock('../plugin-services', () => ({ describe('useAvailableUpdates hook', () => { test('should fetch initial data without any error', async () => { const mockAvailableUpdates: AvailableUpdates = { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -62,15 +62,15 @@ describe('useAvailableUpdates hook', () => { test('should update availableUpdates', async () => { const mockAvailableUpdates: AvailableUpdates = { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.ts index 98c332384a..f3aa8f1470 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.ts @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { ApiAvailableUpdates } from '../../common/types'; +import { ApiAvailableUpdates, AvailableUpdates } from '../../common/types'; import { routes } from '../../common/constants'; import { getCore } from '../plugin-services'; @@ -13,13 +13,13 @@ export const useAvailableUpdates = () => { const refreshAvailableUpdates = async (forceUpdate = false, returnError = false) => { try { setIsLoading(true); - const response = await getCore().http.get(routes.checkUpdates, { + const response = (await getCore().http.get(routes.checkUpdates, { query: { checkAvailableUpdates: forceUpdate, }, - }); - setApisAvailableUpdates(response?.apiAvailableUpdates || []); - setLastCheck(response?.last_check); + })) as AvailableUpdates; + setApisAvailableUpdates(response?.apis_available_updates || []); + setLastCheck(response?.last_check_date); setError(undefined); } catch (error: any) { setError(error); diff --git a/plugins/wazuh-check-updates/public/hooks/user-preferences.ts b/plugins/wazuh-check-updates/public/hooks/user-preferences.ts index 227816c84c..ca5026cde6 100644 --- a/plugins/wazuh-check-updates/public/hooks/user-preferences.ts +++ b/plugins/wazuh-check-updates/public/hooks/user-preferences.ts @@ -12,7 +12,7 @@ export const useUserPreferences = () => { (async () => { try { setIsLoading(true); - const response = await getCore().http.get(routes.userPreferences); + const response = (await getCore().http.get(routes.userPreferences)) as UserPreferences; setUserPreferences(response); setError(undefined); } catch (error: any) { diff --git a/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts index 0d0ec5fe2d..3341f7364c 100644 --- a/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts +++ b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.ts @@ -5,19 +5,30 @@ export const areThereNewUpdates = ( lastDismissedUpdates?: UserPreferencesDimissedUpdate[] ) => { const notifyUser = !!apisAvailableUpdates?.find((apiAvailableUpdates) => { - const { apiId, lastMayor, lastMinor, lastPatch } = apiAvailableUpdates; + const { + api_id, + last_available_major, + last_available_minor, + last_available_patch, + } = apiAvailableUpdates; const apiDismissed = lastDismissedUpdates?.find( - (lastDismissedUpdate) => lastDismissedUpdate.apiId === apiId + (lastDismissedUpdate) => lastDismissedUpdate.api_id === api_id ); - if (!apiDismissed && (lastMayor?.tag || lastMinor?.tag || lastPatch?.tag)) { + if ( + !apiDismissed && + (last_available_major?.tag || last_available_minor?.tag || last_available_patch?.tag) + ) { return true; } - const isNewMajor = lastMayor?.tag && lastMayor.tag !== apiDismissed?.mayor; - const isNewMinor = lastMinor?.tag && lastMinor.tag !== apiDismissed?.minor; - const isNewPatch = lastPatch?.tag && lastPatch.tag !== apiDismissed?.patch; + const isNewMajor = + last_available_major?.tag && last_available_major.tag !== apiDismissed?.last_major; + const isNewMinor = + last_available_minor?.tag && last_available_minor.tag !== apiDismissed?.last_minor; + const isNewPatch = + last_available_patch?.tag && last_available_patch.tag !== apiDismissed?.last_patch; return isNewMajor || isNewMinor || isNewPatch; }); diff --git a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts index 5f7018860f..2ae5607599 100644 --- a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts +++ b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts @@ -24,6 +24,9 @@ describe('jobSchedulerRun function', () => { const response = await jobSchedulerRun(); + expect(getUpdates).toHaveBeenCalledTimes(1); + expect(getUpdates).toHaveBeenCalledWith(true); + expect(getSettings).toHaveBeenCalledTimes(1); expect(getSettings).toHaveBeenCalledWith(); diff --git a/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts b/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts index 9c2d6c8e37..2271fc1f31 100644 --- a/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts +++ b/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts @@ -77,15 +77,15 @@ describe(`[endpoint] GET ${routes.checkUpdates}`, () => { test('get available updates from saved object', async () => { const mockResponse = { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, @@ -104,15 +104,15 @@ describe(`[endpoint] GET ${routes.checkUpdates}`, () => { test('get available updates from the external service', async () => { const mockResponse = { - last_check: '2021-09-30T14:00:00.000Z', - mayor: [ + last_check_date: '2021-09-30T14:00:00.000Z', + major: [ { title: 'Wazuh 4.2.6', description: 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', published_date: '2021-09-30T14:00:00.000Z', semver: { - mayor: 4, + major: 4, minor: 2, patch: 6, }, diff --git a/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.ts b/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.ts index 3abc6a72c0..ecfe03e72b 100644 --- a/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.ts +++ b/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.ts @@ -9,7 +9,16 @@ export const updateUserPreferencesRoutes = (router: IRouter) => { path: routes.userPreferences, validate: { body: schema.object({ - last_dismissed_update: schema.maybe(schema.string()), + last_dismissed_updates: schema.maybe( + schema.arrayOf( + schema.object({ + api_id: schema.string(), + last_major: schema.maybe(schema.string()), + last_minor: schema.maybe(schema.string()), + last_patch: schema.maybe(schema.string()), + }) + ) + ), hide_update_notifications: schema.maybe(schema.boolean()), }), }, diff --git a/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts b/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts index 47ba8cb062..05370c71d1 100644 --- a/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts +++ b/plugins/wazuh-check-updates/server/services/saved-object/types/available-updates.ts @@ -12,7 +12,7 @@ const updateObjectType: SavedObjectsFieldMapping = { semver: { type: 'nested', properties: { - mayor: { + major: { type: 'integer', }, minor: { @@ -38,27 +38,27 @@ export const availableUpdatesObject: SavedObjectsType = { namespaceType: 'agnostic', mappings: { properties: { - last_check: { + last_check_date: { type: 'date', }, - apiAvailableUpdates: { + apis_available_updates: { type: 'nested', properties: { - apiId: { + api_id: { type: 'text', }, - version: { + current_version: { type: 'text', }, status: { type: 'text', }, - last_check: { + last_check_date: { type: 'date', }, - lastMayor: updateObjectType, - lastMinor: updateObjectType, - lastPatch: updateObjectType, + last_available_major: updateObjectType, + last_available_minor: updateObjectType, + last_available_patch: updateObjectType, }, }, }, diff --git a/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts b/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts index a59ccfe503..8e41f5d82d 100644 --- a/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts +++ b/plugins/wazuh-check-updates/server/services/saved-object/types/user-preferences.ts @@ -10,16 +10,16 @@ export const userPreferencesObject: SavedObjectsType = { last_dismissed_updates: { type: 'nested', properties: { - apiId: { + api_id: { type: 'text', }, - mayor: { + last_major: { type: 'text', }, - minor: { + last_minor: { type: 'text', }, - patch: { + last_patch: { type: 'text', }, }, diff --git a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts index 0c83914540..27197cacab 100644 --- a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts @@ -28,9 +28,9 @@ export const getUpdates = async (checkAvailableUpdates?: boolean): Promise { + const apisAvailableUpdates = updates?.map((update) => { const status = - update.lastMayor || update.lastMinor || update.lastPatch + update.last_major || update.last_minor || update.last_patch ? API_UPDATES_STATUS.AVAILABLE_UPDATES : API_UPDATES_STATUS.UP_TO_DATE; @@ -41,8 +41,8 @@ export const getUpdates = async (checkAvailableUpdates?: boolean): Promise Date: Fri, 6 Oct 2023 18:09:34 -0300 Subject: [PATCH 07/17] Fix server unit tests --- plugins/wazuh-check-updates/common/types.ts | 4 +- .../server/cronjob/job-scheduler-run.test.ts | 4 -- .../server/routes/updates/get-updates.test.ts | 65 ++++++------------- .../get-user-preferences.test.ts | 10 ++- .../update-user-preferences.test.ts | 10 ++- .../get-user-preferences.test.ts | 15 ++++- .../update-user-preferences.test.ts | 28 ++++++-- 7 files changed, 73 insertions(+), 63 deletions(-) diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index 3141c46453..1786202420 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -10,7 +10,7 @@ export interface ResponseApiAvailableUpdates { last_available_major?: Update; last_available_minor?: Update; last_available_patch?: Update; - last_check_date?: Date | string | undefined; + last_check_date?: Date | string; } export interface ApiAvailableUpdates extends ResponseApiAvailableUpdates { @@ -47,7 +47,7 @@ export interface CheckUpdatesSettings { export interface AvailableUpdates { apis_available_updates: ApiAvailableUpdates[]; - last_check_date: Date; + last_check_date: Date | string; } export type savedObjectType = AvailableUpdates | UserPreferences | CheckUpdatesSettings; diff --git a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts index 2ae5607599..8e3bcd55e2 100644 --- a/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts +++ b/plugins/wazuh-check-updates/server/cronjob/job-scheduler-run.test.ts @@ -13,10 +13,6 @@ const mockedGetUpdates = getUpdates as jest.Mock; jest.mock('../services/updates'); describe('jobSchedulerRun function', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - test('schedule job to check updates', async () => { mockedCron.mockImplementation(() => {}); mockedGetSettings.mockImplementation(() => ({ schedule: '* * * * *' })); diff --git a/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts b/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts index 2271fc1f31..41ffa5a9fc 100644 --- a/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts +++ b/plugins/wazuh-check-updates/server/routes/updates/get-updates.test.ts @@ -3,10 +3,10 @@ import { HttpServer } from '../../../../../src/core/server/http/http_server'; import { loggingSystemMock } from '../../../../../src/core/server/logging/logging_system.mock'; import { ByteSizeValue } from '@osd/config-schema'; import { getUpdates } from '../../services/updates'; -import { getSavedObject } from '../../services/saved-object'; import { routes } from '../../../common/constants'; import { getUpdatesRoute } from './get-updates'; import axios from 'axios'; +import { API_UPDATES_STATUS, AvailableUpdates } from '../../../common/types'; const serverAddress = '127.0.0.1'; const port = 10002; //assign a different port in each unit test @@ -15,9 +15,6 @@ axios.defaults.baseURL = `http://${serverAddress}:${port}`; const mockedGetUpdates = getUpdates as jest.Mock; jest.mock('../../services/updates'); -const mockedGetSavedObject = getSavedObject as jest.Mock; -jest.mock('../../services/saved-object'); - const loggingService = loggingSystemMock.create(); const logger = loggingService.get(); const context = { @@ -75,52 +72,28 @@ describe(`[endpoint] GET ${routes.checkUpdates}`, () => { jest.clearAllMocks(); }); - test('get available updates from saved object', async () => { - const mockResponse = { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ - { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, - }, - tag: '4.2.6', - }, - ], - minor: [], - patch: [], - }; - - mockedGetSavedObject.mockImplementation(() => mockResponse); - const response = await axios.get(routes.checkUpdates); - - expect(response.data).toEqual(mockResponse); - }); - - test('get available updates from the external service', async () => { - const mockResponse = { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ + test('get available updates', async () => { + const mockResponse: AvailableUpdates = { + last_check_date: '2023-09-30T14:00:00.000Z', + apis_available_updates: [ { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + api_id: 'api id', + current_version: '4.3.1', + status: API_UPDATES_STATUS.UP_TO_DATE, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - tag: '4.2.6', }, ], - minor: [], - patch: [], }; mockedGetUpdates.mockImplementation(() => mockResponse); diff --git a/plugins/wazuh-check-updates/server/routes/user-preferences/get-user-preferences.test.ts b/plugins/wazuh-check-updates/server/routes/user-preferences/get-user-preferences.test.ts index c2d75354e5..08d2cc374f 100644 --- a/plugins/wazuh-check-updates/server/routes/user-preferences/get-user-preferences.test.ts +++ b/plugins/wazuh-check-updates/server/routes/user-preferences/get-user-preferences.test.ts @@ -6,6 +6,7 @@ import { routes } from '../../../common/constants'; import axios from 'axios'; import { getUserPreferences } from '../../services/user-preferences'; import { getUserPreferencesRoutes } from './get-user-preferences'; +import { UserPreferences } from '../../../common/types'; const serverAddress = '127.0.0.1'; const port = 10003; //assign a different port in each unit test @@ -72,8 +73,13 @@ describe(`[endpoint] GET ${routes.userPreferences}`, () => { }); test('get user preferences', async () => { - const mockResponse = { - last_dismissed_update: 'v4.3.1', + const mockResponse: UserPreferences = { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }; diff --git a/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.test.ts b/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.test.ts index abdc80e74a..0c3cbedd96 100644 --- a/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.test.ts +++ b/plugins/wazuh-check-updates/server/routes/user-preferences/update-user-preferences.test.ts @@ -6,6 +6,7 @@ import { routes } from '../../../common/constants'; import axios from 'axios'; import { updateUserPreferences } from '../../services/user-preferences'; import { updateUserPreferencesRoutes } from './update-user-preferences'; +import { UserPreferences } from '../../../common/types'; const serverAddress = '127.0.0.1'; const port = 10004; //assign a different port in each unit test @@ -72,8 +73,13 @@ describe(`[endpoint] PATCH ${routes.userPreferences}`, () => { }); test('update user preferences', async () => { - const mockResponse = { - last_dismissed_update: 'v4.3.1', + const mockResponse: UserPreferences = { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }; diff --git a/plugins/wazuh-check-updates/server/services/user-preferences/get-user-preferences.test.ts b/plugins/wazuh-check-updates/server/services/user-preferences/get-user-preferences.test.ts index c404786f31..5497f77ac1 100644 --- a/plugins/wazuh-check-updates/server/services/user-preferences/get-user-preferences.test.ts +++ b/plugins/wazuh-check-updates/server/services/user-preferences/get-user-preferences.test.ts @@ -12,8 +12,12 @@ describe('getUserPreferences function', () => { test('should return user preferences', async () => { mockedGetSavedObject.mockImplementation(() => ({ - username: 'admin', - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, })); @@ -23,7 +27,12 @@ describe('getUserPreferences function', () => { expect(getSavedObject).toHaveBeenCalledWith(SAVED_OBJECT_USER_PREFERENCES, 'admin'); expect(response).toEqual({ - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }); }); diff --git a/plugins/wazuh-check-updates/server/services/user-preferences/update-user-preferences.test.ts b/plugins/wazuh-check-updates/server/services/user-preferences/update-user-preferences.test.ts index 05b40d0d05..b777bb20de 100644 --- a/plugins/wazuh-check-updates/server/services/user-preferences/update-user-preferences.test.ts +++ b/plugins/wazuh-check-updates/server/services/user-preferences/update-user-preferences.test.ts @@ -16,14 +16,24 @@ describe('updateUserPreferences function', () => { test('should return user preferences', async () => { mockedGetSavedObject.mockImplementation(() => ({ - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, })); mockedSetSavedObject.mockImplementation(() => {}); const response = await updateUserPreferences('admin', { - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }); @@ -31,7 +41,12 @@ describe('updateUserPreferences function', () => { expect(getSavedObject).toHaveBeenCalledWith(SAVED_OBJECT_USER_PREFERENCES, 'admin'); expect(response).toEqual({ - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }); }); @@ -40,7 +55,12 @@ describe('updateUserPreferences function', () => { mockedSetSavedObject.mockRejectedValue(new Error('getSavedObject error')); const promise = updateUserPreferences('admin', { - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }); From 6e192659088dda7ba2c381a029ac1869802b148a Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Fri, 6 Oct 2023 19:01:22 -0300 Subject: [PATCH 08/17] Fix frontend unit tests --- plugins/wazuh-check-updates/common/types.ts | 4 +- .../dismiss-notification-check.test.tsx.snap | 43 ++++ .../updates-notification.test.tsx.snap | 13 + .../dismiss-notification-check.test.tsx | 14 +- .../components/updates-notification.test.tsx | 224 +++++++++--------- .../components/updates-notification.tsx | 6 +- .../public/hooks/available-updates.test.ts | 97 ++++---- .../public/hooks/available-updates.ts | 2 +- .../public/hooks/user-preferences.test.ts | 45 +++- .../public/plugin-services.ts | 3 +- plugins/wazuh-check-updates/public/plugin.ts | 3 +- .../utils/are-there-new-updates.test.ts | 93 ++++++++ 12 files changed, 375 insertions(+), 172 deletions(-) create mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap create mode 100644 plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap create mode 100644 plugins/wazuh-check-updates/public/utils/are-there-new-updates.test.ts diff --git a/plugins/wazuh-check-updates/common/types.ts b/plugins/wazuh-check-updates/common/types.ts index 1786202420..c10576e5a0 100644 --- a/plugins/wazuh-check-updates/common/types.ts +++ b/plugins/wazuh-check-updates/common/types.ts @@ -10,7 +10,7 @@ export interface ResponseApiAvailableUpdates { last_available_major?: Update; last_available_minor?: Update; last_available_patch?: Update; - last_check_date?: Date | string; + last_check_date?: string; } export interface ApiAvailableUpdates extends ResponseApiAvailableUpdates { @@ -47,7 +47,7 @@ export interface CheckUpdatesSettings { export interface AvailableUpdates { apis_available_updates: ApiAvailableUpdates[]; - last_check_date: Date | string; + last_check_date: string; } export type savedObjectType = AvailableUpdates | UserPreferences | CheckUpdatesSettings; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap new file mode 100644 index 0000000000..03d28de0a9 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/__snapshots__/dismiss-notification-check.test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DismissNotificationCheck component should render the check 1`] = ` +
+
+ +
+ +
+
+`; + +exports[`DismissNotificationCheck component should return null when there is an error 1`] = `
`; diff --git a/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap b/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap new file mode 100644 index 0000000000..d69c187531 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/__snapshots__/updates-notification.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UpdatesNotification component should return null when is loading 1`] = `
`; + +exports[`UpdatesNotification component should return null when there are no available updates 1`] = `
`; + +exports[`UpdatesNotification component should return null when user already dismissed the notifications for available updates 1`] = `
`; + +exports[`UpdatesNotification component should return null when user close notification 1`] = `
`; + +exports[`UpdatesNotification component should return null when user dismissed notifications for future 1`] = `
`; + +exports[`UpdatesNotification component should return the nofication component 1`] = `
`; diff --git a/plugins/wazuh-check-updates/public/components/dismiss-notification-check.test.tsx b/plugins/wazuh-check-updates/public/components/dismiss-notification-check.test.tsx index 976bfe97b3..b4f8ce82bf 100644 --- a/plugins/wazuh-check-updates/public/components/dismiss-notification-check.test.tsx +++ b/plugins/wazuh-check-updates/public/components/dismiss-notification-check.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { CurrentUpdateDetails } from './current-update-details'; import { DismissNotificationCheck } from './dismiss-notification-check'; import { useUserPreferences } from '../hooks'; @@ -19,7 +18,16 @@ describe('DismissNotificationCheck component', () => { test('should render the check', () => { mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.1' }, + userPreferences: { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: 'v4.3.1', + }, + ], + hide_update_notifications: false, + }, + updateUserPreferences: () => {}, })); const { container, getByText } = render(); @@ -35,7 +43,7 @@ describe('DismissNotificationCheck component', () => { error: 'Error', })); - const { container } = render(); + const { container } = render(); expect(container).toMatchSnapshot(); diff --git a/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx b/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx index 21377e5471..d049206446 100644 --- a/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx +++ b/plugins/wazuh-check-updates/public/components/updates-notification.test.tsx @@ -2,9 +2,10 @@ import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; import { useAvailableUpdates, useUserPreferences } from '../hooks'; -import { getCurrentAvailableUpdate } from '../utils'; +import { areThereNewUpdates } from '../utils'; import { UpdatesNotification } from './updates-notification'; import userEvent from '@testing-library/user-event'; +import { API_UPDATES_STATUS } from '../../common/types'; jest.mock( '../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', @@ -13,69 +14,72 @@ jest.mock( }) ); +jest.mock('../plugin-services', () => ({ + getCore: jest.fn().mockReturnValue({ + http: { + basePath: { + prepend: () => 'http://url', + }, + }, + }), +})); + const mockedUseAvailabeUpdates = useAvailableUpdates as jest.Mock; jest.mock('../hooks/available-updates'); const mockedUseUserPreferences = useUserPreferences as jest.Mock; jest.mock('../hooks/user-preferences'); -const mockedGetCurrentAvailableUpdate = getCurrentAvailableUpdate as jest.Mock; -jest.mock('../utils/get-current-available-update'); +const mockedAreThereNewUpdates = areThereNewUpdates as jest.Mock; +jest.mock('../utils/are-there-new-updates'); describe('UpdatesNotification component', () => { test('should return the nofication component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, - availableUpdates: { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ - { - title: 'Wazuh 4.2.6', + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', semver: { major: 4, - minor: 2, - patch: 6, + minor: 3, + patch: 8, }, - tag: 'v4.2.6', + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - ], - minor: [], - patch: [], - }, + }, + ], })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.1' }, - })); - mockedGetCurrentAvailableUpdate.mockImplementation(() => ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + userPreferences: { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: 'v4.3.1', + }, + ], + hide_update_notifications: false, }, - tag: 'v4.2.6', })); + mockedAreThereNewUpdates.mockImplementation(() => true); const { container, getByText, getByRole } = render(); expect(container).toMatchSnapshot(); - const message = getByText('Wazuh new release is available now!'); + const message = getByText('Wazuh new release is available!'); expect(message).toBeInTheDocument(); - const elementWithTag = getByText('v4.2.6'); - expect(elementWithTag).toBeInTheDocument(); - - const releaseNotesUrl = 'https://documentation.wazuh.com/4.2/release-notes/release-4-2-6.html'; - const releaseNotesLink = getByRole('link', { name: 'Go to the release notes for details' }); - expect(releaseNotesLink).toHaveAttribute('href', releaseNotesUrl); + const releaseNotesLink = getByRole('link', { name: 'Go to the about page for details' }); + expect(releaseNotesLink).toBeInTheDocument(); const dismissCheck = getByText('Disable updates notifications'); expect(dismissCheck).toBeInTheDocument(); @@ -87,43 +91,40 @@ describe('UpdatesNotification component', () => { test('should return null when user close notification', async () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, - availableUpdates: { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ - { - title: 'Wazuh 4.2.6', + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', semver: { major: 4, - minor: 2, - patch: 6, + minor: 3, + patch: 8, }, - tag: 'v4.2.6', + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - ], - minor: [], - patch: [], - }, + }, + ], })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.1' }, - updateUserPreferences: () => {}, - })); - mockedGetCurrentAvailableUpdate.mockImplementation(() => ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + userPreferences: { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: 'v4.3.1', + }, + ], + hide_update_notifications: false, }, - tag: 'v4.2.6', + updateUserPreferences: () => {}, })); + mockedAreThereNewUpdates.mockImplementation(() => true); const { container, getByRole } = render(); @@ -141,9 +142,8 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: true })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: true, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.1' }, })); - mockedGetCurrentAvailableUpdate.mockImplementation(() => undefined); + mockedAreThereNewUpdates.mockImplementation(() => undefined); const { container } = render(); @@ -157,9 +157,9 @@ describe('UpdatesNotification component', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.1' }, + userPreferences: { hide_update_notifications: false }, })); - mockedGetCurrentAvailableUpdate.mockImplementation(() => undefined); + mockedAreThereNewUpdates.mockImplementation(() => undefined); const { container } = render(); @@ -172,30 +172,39 @@ describe('UpdatesNotification component', () => { test('should return null when user dismissed notifications for future', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, - availableUpdates: { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ - { - title: 'Wazuh 4.2.6', + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', semver: { major: 4, - minor: 2, - patch: 6, + minor: 3, + patch: 8, }, - tag: 'v4.2.6', + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - ], - minor: [], - patch: [], - }, + }, + ], })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: true, last_dismissed_update: 'v4.2.1' }, + userPreferences: { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: 'v4.3.1', + }, + ], + hide_update_notifications: true, + }, })); + mockedAreThereNewUpdates.mockImplementation(() => true); const { container } = render(); @@ -205,45 +214,42 @@ describe('UpdatesNotification component', () => { expect(firstChild).toBeNull(); }); - test('should return null when user already dismissed the notifications for current update', () => { + test('should return null when user already dismissed the notifications for available updates', () => { mockedUseAvailabeUpdates.mockImplementation(() => ({ isLoading: false, - availableUpdates: { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ - { - title: 'Wazuh 4.2.6', + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', semver: { major: 4, - minor: 2, - patch: 6, + minor: 3, + patch: 8, }, - tag: 'v4.2.6', + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - ], - minor: [], - patch: [], - }, + }, + ], })); mockedUseUserPreferences.mockImplementation(() => ({ isLoading: false, - userPreferences: { hide_update_notifications: false, last_dismissed_update: 'v4.2.6' }, - })); - mockedGetCurrentAvailableUpdate.mockImplementation(() => ({ - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + userPreferences: { + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: 'v4.3.8', + }, + ], + hide_update_notifications: false, }, - tag: 'v4.2.6', })); + mockedAreThereNewUpdates.mockImplementation(() => false); const { container } = render(); diff --git a/plugins/wazuh-check-updates/public/components/updates-notification.tsx b/plugins/wazuh-check-updates/public/components/updates-notification.tsx index c6dc951fcf..186bfdf701 100644 --- a/plugins/wazuh-check-updates/public/components/updates-notification.tsx +++ b/plugins/wazuh-check-updates/public/components/updates-notification.tsx @@ -11,7 +11,7 @@ import React, { useState } from 'react'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { useAvailableUpdates, useUserPreferences } from '../hooks'; import { areThereNewUpdates } from '../utils'; -import { getHttp } from '../plugin-services'; +import { getCore } from '../plugin-services'; export const UpdatesNotification = () => { const [isDismissed, setIsDismissed] = useState(false); @@ -93,7 +93,9 @@ export const UpdatesNotification = () => { - + ({ getCore: jest.fn().mockReturnValue({ http: { get: jest.fn().mockResolvedValue({ - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ + last_check_date: '2023-09-30T14:00:00.000Z', + apis_available_updates: [ { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates', + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - tag: '4.2.6', }, ], - minor: [], - patch: [], }), }, }), @@ -32,23 +35,26 @@ jest.mock('../plugin-services', () => ({ describe('useAvailableUpdates hook', () => { test('should fetch initial data without any error', async () => { const mockAvailableUpdates: AvailableUpdates = { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ + last_check_date: '2023-09-30T14:00:00.000Z', + apis_available_updates: [ { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - tag: '4.2.6', }, ], - minor: [], - patch: [], }; const { result, waitForNextUpdate } = renderHook(() => useAvailableUpdates()); @@ -56,29 +62,34 @@ describe('useAvailableUpdates hook', () => { expect(result.current.isLoading).toBeTruthy(); await waitForNextUpdate(); - expect(result.current.availableUpdates).toEqual(mockAvailableUpdates); + expect(result.current.apisAvailableUpdates).toEqual( + mockAvailableUpdates.apis_available_updates + ); expect(result.current.isLoading).toBeFalsy(); }); test('should update availableUpdates', async () => { const mockAvailableUpdates: AvailableUpdates = { - last_check_date: '2021-09-30T14:00:00.000Z', - major: [ + last_check_date: '2023-09-30T14:00:00.000Z', + apis_available_updates: [ { - title: 'Wazuh 4.2.6', - description: - 'Wazuh 4.2.6 is now available. This version includes several bug fixes and improvements.', - published_date: '2021-09-30T14:00:00.000Z', - semver: { - major: 4, - minor: 2, - patch: 6, + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', }, - tag: '4.2.6', }, ], - minor: [], - patch: [], }; const { result, waitForNextUpdate } = renderHook(() => useAvailableUpdates()); @@ -92,7 +103,9 @@ describe('useAvailableUpdates hook', () => { expect(result.current.isLoading).toBeTruthy(); await waitForNextUpdate(); - expect(result.current.availableUpdates).toEqual(mockAvailableUpdates); + expect(result.current.apisAvailableUpdates).toEqual( + mockAvailableUpdates.apis_available_updates + ); expect(result.current.isLoading).toBeFalsy(); }); diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.ts index f3aa8f1470..7b8d194138 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.ts @@ -5,7 +5,7 @@ import { getCore } from '../plugin-services'; export const useAvailableUpdates = () => { const [apisAvailableUpdates, setApisAvailableUpdates] = useState([]); - const [lastCheck, setLastCheck] = useState(); + const [lastCheck, setLastCheck] = useState(); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); diff --git a/plugins/wazuh-check-updates/public/hooks/user-preferences.test.ts b/plugins/wazuh-check-updates/public/hooks/user-preferences.test.ts index 75801e3156..640cfbc809 100644 --- a/plugins/wazuh-check-updates/public/hooks/user-preferences.test.ts +++ b/plugins/wazuh-check-updates/public/hooks/user-preferences.test.ts @@ -6,12 +6,24 @@ import { getCore } from '../plugin-services'; jest.mock('../plugin-services', () => ({ getCore: jest.fn().mockReturnValue({ http: { - get: jest - .fn() - .mockResolvedValue({ last_dismissed_update: 'v4.3.1', hide_update_notifications: false }), - patch: jest - .fn() - .mockResolvedValue({ last_dismissed_update: 'v4.3.1', hide_update_notifications: false }), + get: jest.fn().mockResolvedValue({ + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], + hide_update_notifications: false, + }), + patch: jest.fn().mockResolvedValue({ + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], + hide_update_notifications: false, + }), }, }), })); @@ -19,7 +31,12 @@ jest.mock('../plugin-services', () => ({ describe('useUserPreferences hook', () => { it('should fetch initial data without any error', async () => { const mockUserPreferences: UserPreferences = { - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }; const { result, waitForNextUpdate } = renderHook(() => useUserPreferences()); @@ -32,7 +49,12 @@ describe('useUserPreferences hook', () => { it('should update user preferences', async () => { const mockUserPreferences: UserPreferences = { - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }; const { result, waitForNextUpdate } = renderHook(() => useUserPreferences()); @@ -66,7 +88,12 @@ describe('useUserPreferences hook', () => { it('should handle error while updating user preferences', async () => { const mockUserPreferences: UserPreferences = { - last_dismissed_update: 'v4.3.1', + last_dismissed_updates: [ + { + api_id: 'api id', + last_patch: '4.3.1', + }, + ], hide_update_notifications: false, }; const mockErrorMessage = 'Some error occurred'; diff --git a/plugins/wazuh-check-updates/public/plugin-services.ts b/plugins/wazuh-check-updates/public/plugin-services.ts index e1d3a1e434..de618c9e18 100644 --- a/plugins/wazuh-check-updates/public/plugin-services.ts +++ b/plugins/wazuh-check-updates/public/plugin-services.ts @@ -1,6 +1,5 @@ -import { CoreStart, HttpStart, IUiSettingsClient } from 'opensearch-dashboards/public'; +import { CoreStart, IUiSettingsClient } from 'opensearch-dashboards/public'; import { createGetterSetter } from '../../../src/plugins/opensearch_dashboards_utils/common'; export const [getCore, setCore] = createGetterSetter('Core'); export const [getUiSettings, setUiSettings] = createGetterSetter('UiSettings'); -export const [getHttp, setHttp] = createGetterSetter('Http'); diff --git a/plugins/wazuh-check-updates/public/plugin.ts b/plugins/wazuh-check-updates/public/plugin.ts index 1447799c67..b3f5f2d393 100644 --- a/plugins/wazuh-check-updates/public/plugin.ts +++ b/plugins/wazuh-check-updates/public/plugin.ts @@ -1,7 +1,7 @@ import { CoreSetup, CoreStart, Plugin } from 'opensearch-dashboards/public'; import { WazuhCheckUpdatesPluginSetup, WazuhCheckUpdatesPluginStart } from './types'; import { UpdatesNotification } from './components/updates-notification'; -import { setCore, setUiSettings, setHttp } from './plugin-services'; +import { setCore, setUiSettings } from './plugin-services'; import { ApisUpdateStatus } from './components/apis-update-status'; export class WazuhCheckUpdatesPlugin @@ -13,7 +13,6 @@ export class WazuhCheckUpdatesPlugin public start(core: CoreStart): WazuhCheckUpdatesPluginStart { setCore(core); setUiSettings(core.uiSettings); - setHttp(core.http); return { UpdatesNotification, diff --git a/plugins/wazuh-check-updates/public/utils/are-there-new-updates.test.ts b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.test.ts new file mode 100644 index 0000000000..d49ae34961 --- /dev/null +++ b/plugins/wazuh-check-updates/public/utils/are-there-new-updates.test.ts @@ -0,0 +1,93 @@ +import { + API_UPDATES_STATUS, + ApiAvailableUpdates, + UserPreferencesDimissedUpdate, +} from '../../common/types'; +import { areThereNewUpdates } from './are-there-new-updates'; + +describe('areThereNewUpdates function', () => { + it('should return true', async () => { + const mockApisAvailableUpdates: ApiAvailableUpdates[] = [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', + }, + }, + ]; + const mockLastDismissedUpdates: UserPreferencesDimissedUpdate[] = []; + + const result = areThereNewUpdates(mockApisAvailableUpdates, mockLastDismissedUpdates); + + expect(result).toBe(true); + }); + + it('should return false', async () => { + const mockApisAvailableUpdates: ApiAvailableUpdates[] = [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', + }, + }, + ]; + const mockLastDismissedUpdates: UserPreferencesDimissedUpdate[] = [ + { api_id: 'api id', last_patch: 'v4.3.8' }, + ]; + + const result = areThereNewUpdates(mockApisAvailableUpdates, mockLastDismissedUpdates); + + expect(result).toBe(false); + }); + + it('should return true', async () => { + const mockApisAvailableUpdates: ApiAvailableUpdates[] = [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', + }, + }, + ]; + const mockLastDismissedUpdates: UserPreferencesDimissedUpdate[] = [ + { api_id: 'api id', last_patch: 'v4.3.9' }, + ]; + + const result = areThereNewUpdates(mockApisAvailableUpdates, mockLastDismissedUpdates); + + expect(result).toBe(true); + }); +}); From fd140b550fe124749160c44e35b8c9bcb543caf4 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 10:23:41 -0300 Subject: [PATCH 09/17] Fix main plugin about page unit tests --- .../about/__snapshots__/appInfo.test.tsx.snap | 77 +++++++++++++++++++ .../settings/about/appInfo.test.tsx | 18 ++--- .../components/settings/about/index.test.tsx | 9 +-- 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap b/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap index 032044e00a..e274187214 100644 --- a/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap +++ b/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap @@ -1,5 +1,82 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`SettingsAboutAppInfo component should render version, revision, install date and ApisUpdateStatus component 1`] = ` +
+

+ Wazuh Dashboard version +

+
+
+
+
+
+ Version +
+
+ 4.8.0 +
+
+
+
+
+
+ Revision +
+
+ 01 +
+
+
+
+
+
+ Install date +
+
+ Sep 25, 2023 @ 14:03:40.816 +
+
+
+
+
+
+ APIs Updates Status component +
+
+`; + exports[`SettingsAboutAppInfo component should render version, revision, install date and UpToDateStatus and DismissNotificationCheck components 1`] = `
({ getWazuhCheckUpdatesPlugin: jest.fn().mockReturnValue({ - UpToDateStatus: () =>
Up to date status component
, - DismissNotificationCheck: () =>
Dismiss notification check component
, + ApisUpdateStatus: () =>
APIs Updates Status component
, }), })); describe('SettingsAboutAppInfo component', () => { - test('should render version, revision, install date and UpToDateStatus and DismissNotificationCheck components', () => { + test('should render version, revision, install date and ApisUpdateStatus component', () => { const { container, getByText } = render( { revision: '01', installationDate: 'Sep 25, 2023 @ 14:03:40.816', }} - setCurrentUpdate={() => {}} /> ); expect(container).toMatchSnapshot(); - const loaders = container.getElementsByClassName('euiLoadingSpinner'); - expect(loaders.length).toBe(0); - - expect(getByText('App version:')).toBeInTheDocument(); + expect(getByText('Version')).toBeInTheDocument(); expect(getByText('4.8.0')).toBeInTheDocument(); - expect(getByText('App revision:')).toBeInTheDocument(); + expect(getByText('Revision')).toBeInTheDocument(); expect(getByText('01')).toBeInTheDocument(); - expect(getByText('Install date:')).toBeInTheDocument(); + expect(getByText('Install date')).toBeInTheDocument(); expect(getByText('Sep 25, 2023 @ 14:03:40.816')).toBeInTheDocument(); - expect(getByText('Up to date status component')).toBeInTheDocument(); - expect(getByText('Dismiss notification check component')).toBeInTheDocument(); + expect(getByText('APIs Updates Status component')).toBeInTheDocument(); }); }); diff --git a/plugins/main/public/components/settings/about/index.test.tsx b/plugins/main/public/components/settings/about/index.test.tsx index 1285320325..2f94be05aa 100644 --- a/plugins/main/public/components/settings/about/index.test.tsx +++ b/plugins/main/public/components/settings/about/index.test.tsx @@ -3,12 +3,6 @@ import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; import { SettingsAbout } from '.'; -jest.mock('../../../kibana-services', () => ({ - getWazuhCheckUpdatesPlugin: jest.fn().mockReturnValue({ - CurrentUpdateDetails: () =>
Current update
, - }), -})); - jest.mock('./appInfo', () => ({ SettingsAboutAppInfo: jest.fn().mockReturnValue(
App info
), })); @@ -43,5 +37,8 @@ describe('SettingsAbout component', () => { const loaders = container.getElementsByClassName('euiLoadingContent'); expect(loaders.length).toBe(0); + + const appInfo = getByText('App info'); + expect(appInfo).toBeInTheDocument(); }); }); From 0521c9923ac18795bde39c3c2f9e4f8073e2654d Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 11:45:00 -0300 Subject: [PATCH 10/17] Apis table components unit tests --- .../__snapshots__/index.test.tsx.snap | 167 ++++++++++ .../apis-update-status/index.test.tsx | 112 +++++++ .../table/__snapshots__/index.test.tsx.snap | 288 ++++++++++++++++++ .../__snapshots__/update-badge.test.tsx.snap | 43 +++ .../table/columns/update-badge.test.tsx | 73 +++++ .../apis-update-status/table/index.test.tsx | 48 +++ .../apis-update-status/table/index.tsx | 17 +- 7 files changed, 741 insertions(+), 7 deletions(-) create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/__snapshots__/index.test.tsx.snap create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/index.test.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/__snapshots__/index.test.tsx.snap create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/__snapshots__/update-badge.test.tsx.snap create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.test.tsx create mode 100644 plugins/wazuh-check-updates/public/components/apis-update-status/table/index.test.tsx diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/__snapshots__/index.test.tsx.snap b/plugins/wazuh-check-updates/public/components/apis-update-status/__snapshots__/index.test.tsx.snap new file mode 100644 index 0000000000..a0bbc8a5c5 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/__snapshots__/index.test.tsx.snap @@ -0,0 +1,167 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UpdatesNotification component should retrieve available updates when click the button 1`] = ` +
+

+ Wazuh APIs version +

+
+
+
+ +
+
+
+
+ Last check +
+
+ 2023-09-18T14:00:00.000Z +
+
+
+
+
+ Dismiss Notification Check component +
+
+
+
+
+ APIs Updates Table component +
+
+
+`; + +exports[`UpdatesNotification component should return the ApisUpdateStatus component 1`] = ` +
+

+ Wazuh APIs version +

+
+
+
+ +
+
+
+
+ Last check +
+
+ 2023-09-18T14:00:00.000Z +
+
+
+
+
+ Dismiss Notification Check component +
+
+
+
+
+ APIs Updates Table component +
+
+
+`; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.test.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.test.tsx new file mode 100644 index 0000000000..c88387f1f9 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.test.tsx @@ -0,0 +1,112 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { ApisUpdateStatus } from '.'; +import { useAvailableUpdates } from '../../hooks'; +import { API_UPDATES_STATUS } from '../../../common/types'; +import userEvent from '@testing-library/user-event'; + +jest.mock('../dismiss-notification-check', () => ({ + DismissNotificationCheck: jest + .fn() + .mockReturnValue(
Dismiss Notification Check component
), +})); + +jest.mock('./table', () => ({ + ApisUpdateTable: jest.fn().mockReturnValue(
APIs Updates Table component
), +})); + +jest.mock('../../utils', () => ({ + formatUIDate: jest.fn().mockReturnValue('2023-09-18T14:00:00.000Z'), +})); + +const mockedUseAvailabeUpdates = useAvailableUpdates as jest.Mock; +jest.mock('../../hooks/available-updates'); + +describe('UpdatesNotification component', () => { + test('should return the ApisUpdateStatus component', () => { + mockedUseAvailabeUpdates.mockImplementation(() => ({ + isLoading: false, + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', + }, + }, + ], + lastCheck: '2023-09-18T14:00:00.000Z', + refreshAvailableUpdates: jest.fn().mockResolvedValue({}), + })); + + const { container, getByText } = render( + {}} /> + ); + + expect(container).toMatchSnapshot(); + + const dismissNotificationCheck = getByText('Dismiss Notification Check component'); + expect(dismissNotificationCheck).toBeInTheDocument(); + + const apisUpdateTable = getByText('APIs Updates Table component'); + expect(apisUpdateTable).toBeInTheDocument(); + + const lastCheck = getByText('2023-09-18T14:00:00.000Z'); + expect(lastCheck).toBeInTheDocument(); + }); + + test('should retrieve available updates when click the button', async () => { + mockedUseAvailabeUpdates.mockImplementation(() => ({ + isLoading: false, + apisAvailableUpdates: [ + { + api_id: 'api id', + current_version: '4.3.1', + status: 'availableUpdates' as API_UPDATES_STATUS, + last_available_patch: { + description: + '## Manager\r\n\r\n### Fixed\r\n\r\n- Fixed a crash when overwrite rules are triggered...', + published_date: '2022-05-18T10:12:43Z', + semver: { + major: 4, + minor: 3, + patch: 8, + }, + tag: 'v4.3.8', + title: 'Wazuh v4.3.8', + }, + }, + ], + lastCheck: '2023-09-18T14:00:00.000Z', + refreshAvailableUpdates: jest.fn().mockResolvedValue({}), + })); + + const { container, getByRole, getByText } = render( + {}} /> + ); + + expect(container).toMatchSnapshot(); + + const checkUpdatesButton = getByRole('button', { name: 'Check updates' }); + expect(checkUpdatesButton).toBeInTheDocument(); + await userEvent.click(checkUpdatesButton); + waitFor(async () => { + const apisUpdateTable = getByText('APIs Updates Table component'); + expect(apisUpdateTable).toBeInTheDocument(); + + const lastCheck = getByText('2023-09-18T14:00:00.000Z'); + expect(lastCheck).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/__snapshots__/index.test.tsx.snap b/plugins/wazuh-check-updates/public/components/apis-update-status/table/__snapshots__/index.test.tsx.snap new file mode 100644 index 0000000000..e1e2536f44 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/__snapshots__/index.test.tsx.snap @@ -0,0 +1,288 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ApisUpdateTable component should return the ApisUpdateTable component 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + + ID + + + + + + Version + + + + + + Update status + + + + + + Last major + + + + + + Last minor + + + + + + Last patch + + +
+
+ ID +
+
+ + api id + +
+
+
+ Version +
+
+ + 4.3.1 + +
+
+
+ Update status +
+
+
+
+
+ +
+
+ Available updates +
+
+
+
+
+
+ Last major +
+
+
+
+ Last minor +
+
+
+
+ Last patch +
+
+ +
+
+
+
+
+`; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/__snapshots__/update-badge.test.tsx.snap b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/__snapshots__/update-badge.test.tsx.snap new file mode 100644 index 0000000000..6c873cdb7e --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/__snapshots__/update-badge.test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UpdateBadge component should open a modal when click the badge 1`] = ` +
+ +
+`; + +exports[`UpdateBadge component should return the UpdateBadge component 1`] = ` +
+ +
+`; diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.test.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.test.tsx new file mode 100644 index 0000000000..566522869c --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.test.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { UpdateBadge } from './update-badge'; +import userEvent from '@testing-library/user-event'; + +jest.mock( + '../../../../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', + () => ({ + htmlIdGenerator: () => () => 'htmlId', + }) +); + +jest.mock('../../../../utils', () => ({ + formatUIDate: jest.fn().mockReturnValue('2022-05-18T10:12:43Z'), +})); + +describe('UpdateBadge component', () => { + test('should return the UpdateBadge component', () => { + const { container, getByText } = render( + + ); + + expect(container).toMatchSnapshot(); + + expect(getByText('v4.3.8')).toBeInTheDocument(); + }); + + test('should open a modal when click the badge', async () => { + const { container, getByRole, getByText } = render( + + ); + + expect(container).toMatchSnapshot(); + + const badge = getByRole('button'); + expect(badge).toBeInTheDocument(); + await userEvent.click(badge); + waitFor(async () => { + const modalHeader = getByText('Wazuh v4.3.8'); + expect(modalHeader).toBeInTheDocument(); + + const modalPublishDate = getByText('2022-05-18T10:12:43Z'); + expect(modalPublishDate).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.test.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.test.tsx new file mode 100644 index 0000000000..9783c5daf4 --- /dev/null +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.test.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { ApisUpdateTable } from '.'; +import { API_UPDATES_STATUS } from '../../../../common/types'; + +jest.mock( + '../../../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', + () => ({ + htmlIdGenerator: () => () => 'htmlId', + }) +); + +describe('ApisUpdateTable component', () => { + test('should return the ApisUpdateTable component', () => { + const { container, getByText } = render( + + ); + + expect(container).toMatchSnapshot(); + + expect(getByText('api id')).toBeInTheDocument(); + expect(getByText('4.3.1')).toBeInTheDocument(); + expect(getByText('Available updates')).toBeInTheDocument(); + expect(getByText('v4.3.8')).toBeInTheDocument(); + }); +}); diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx index f7eb0fd827..2bac8e2e37 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/index.tsx @@ -2,6 +2,7 @@ import { EuiInMemoryTable } from '@elastic/eui'; import React from 'react'; import { getApisUpdateStatusColumns } from './columns'; import { ApiAvailableUpdates } from '../../../../common/types'; +import { I18nProvider } from '@osd/i18n/react'; export interface ApisUpdateTableProps { isLoading: boolean; @@ -10,12 +11,14 @@ export interface ApisUpdateTableProps { export const ApisUpdateTable = ({ isLoading, apisAvailableUpdates }: ApisUpdateTableProps) => { return ( - + + + ); }; From 230232e9aab8c7b3c8dc49ca3d2522196cddabaa Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 11:51:20 -0300 Subject: [PATCH 11/17] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2ec770b7..eb4b86185d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,9 @@ All notable changes to the Wazuh app project will be documented in this file. ### Added - Support for Wazuh 4.8.0 -- Added `wazuh-check-updates` plugin. [#5897](https://github.com/wazuh/wazuh-kibana-app/pull/5897) +- Added `wazuh-check-updates` plugin. [#5897](https://github.com/wazuh/wazuh-kibana-app/pull/5897) [#5984](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5984) - Added new updates availability information to the About page. [#5939](https://github.com/wazuh/wazuh-kibana-app/pull/5939) +- Added new update notifications to the main plugin. [#5984](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5984) ## Wazuh v4.7.0 - OpenSearch Dashboards 2.6.0 - Revision 01 From 1099f6c5bca4c18cb14c6ff04b33d44224c4580a Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 12:44:36 -0300 Subject: [PATCH 12/17] Update unit test snapshot --- .../about/__snapshots__/appInfo.test.tsx.snap | 74 ------------------- 1 file changed, 74 deletions(-) diff --git a/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap b/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap index e274187214..c9b9856ed0 100644 --- a/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap +++ b/plugins/main/public/components/settings/about/__snapshots__/appInfo.test.tsx.snap @@ -76,77 +76,3 @@ exports[`SettingsAboutAppInfo component should render version, revision, install
`; - -exports[`SettingsAboutAppInfo component should render version, revision, install date and UpToDateStatus and DismissNotificationCheck components 1`] = ` -
-
-
-
-
- App version: - - 4.8.0 - -
-
-
-
-
- Up to date status component -
-
-
-
-
-
- App revision: - - 01 - -
-
-
-
-
- Install date: - - Sep 25, 2023 @ 14:03:40.816 - -
-
-
-
- Dismiss notification check component -
-
-`; From ad7958c5bb193ec223e0b1f3ac320ce308831c37 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 13:52:03 -0300 Subject: [PATCH 13/17] Update CHANGELOG --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4b86185d..7af24b788e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,7 @@ All notable changes to the Wazuh app project will be documented in this file. ### Added - Support for Wazuh 4.8.0 -- Added `wazuh-check-updates` plugin. [#5897](https://github.com/wazuh/wazuh-kibana-app/pull/5897) [#5984](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5984) -- Added new updates availability information to the About page. [#5939](https://github.com/wazuh/wazuh-kibana-app/pull/5939) -- Added new update notifications to the main plugin. [#5984](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5984) +- Added the ability to check if there are available updates from the UI. ## Wazuh v4.7.0 - OpenSearch Dashboards 2.6.0 - Revision 01 From d87fafb60f7bac5f9f0c6178118fd1e658665274 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 14:12:30 -0300 Subject: [PATCH 14/17] Fix get updates status --- .../wazuh-check-updates/server/services/updates/get-updates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts index 27197cacab..ffcdae9c1e 100644 --- a/plugins/wazuh-check-updates/server/services/updates/get-updates.ts +++ b/plugins/wazuh-check-updates/server/services/updates/get-updates.ts @@ -30,7 +30,7 @@ export const getUpdates = async (checkAvailableUpdates?: boolean): Promise { const status = - update.last_major || update.last_minor || update.last_patch + update.last_available_patch || update.last_available_minor || update.last_available_patch ? API_UPDATES_STATUS.AVAILABLE_UPDATES : API_UPDATES_STATUS.UP_TO_DATE; From b26b782a90ff9e70cd439e718b7563b108767505 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 14:26:19 -0300 Subject: [PATCH 15/17] Fix release notes url with current --- .../apis-update-status/table/columns/update-badge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx index 2aebc39e50..a2d3514207 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/table/columns/update-badge.tsx @@ -37,7 +37,7 @@ export const UpdateBadge = ({ update }: UpdateProps) => { }; const minorVersion = `${semver.major}.${semver.minor}`; - const releaseNotesUrl = `https://documentation.wazuh.com/${minorVersion}/release-notes/release-${semver.major}-${semver.minor}-${semver.patch}.html`; + const releaseNotesUrl = `https://documentation.wazuh.com/current/release-notes/release-${semver.major}-${semver.minor}-${semver.patch}.html`; const upgradeGuideUrl = `https://documentation.wazuh.com/${minorVersion}/upgrade-guide/index.html`; return ( From b9e81902453defe6e27079d43206bb9f38886884 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 14:44:14 -0300 Subject: [PATCH 16/17] Improve toast id on Apis table --- .../components/apis-update-status/index.tsx | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx index 4ac500e4a3..0004e9a587 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -1,6 +1,5 @@ import { EuiButton, - EuiCallOut, EuiDescriptionList, EuiFlexGroup, EuiFlexItem, @@ -21,14 +20,15 @@ export interface ApisUpdateStatusProps { setApisAvailableUpdates: (apisAvailableUpdates: ApiAvailableUpdates[]) => void; } -let toastId = 0; - export const ApisUpdateStatus = ({ setApisAvailableUpdates }: ApisUpdateStatusProps) => { + const [toastId, setToastId] = useState(0); const [toasts, setToasts] = useState([]); const addToastHandler = (error: any) => { + const newToastId = toastId + 1; + setToastId(newToastId); const toast = { - id: `${toastId++}`, + id: `${newToastId}`, title: ( - } - /> - ); - } - const handleOnClick = async () => { const response = await refreshAvailableUpdates(true, true); if (response instanceof Error) { From d7f3eb2a19d6bea69724d35d8f7ba589af7c8d21 Mon Sep 17 00:00:00 2001 From: Luciano Gorza Date: Mon, 9 Oct 2023 15:46:36 -0300 Subject: [PATCH 17/17] ApisUpdateStatus: Show error callout only the first time --- .../components/apis-update-status/index.tsx | 17 +++++++++++++++++ .../public/hooks/available-updates.ts | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx index 0004e9a587..8dfff00e96 100644 --- a/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx +++ b/plugins/wazuh-check-updates/public/components/apis-update-status/index.tsx @@ -1,5 +1,6 @@ import { EuiButton, + EuiCallOut, EuiDescriptionList, EuiFlexGroup, EuiFlexItem, @@ -50,6 +51,7 @@ export const ApisUpdateStatus = ({ setApisAvailableUpdates }: ApisUpdateStatusPr apisAvailableUpdates, isLoading, refreshAvailableUpdates, + error, lastCheck, } = useAvailableUpdates(); @@ -57,6 +59,21 @@ export const ApisUpdateStatus = ({ setApisAvailableUpdates }: ApisUpdateStatusPr setApisAvailableUpdates(apisAvailableUpdates); }, [apisAvailableUpdates]); + if (error) { + return ( + + } + /> + ); + } + const handleOnClick = async () => { const response = await refreshAvailableUpdates(true, true); if (response instanceof Error) { diff --git a/plugins/wazuh-check-updates/public/hooks/available-updates.ts b/plugins/wazuh-check-updates/public/hooks/available-updates.ts index 7b8d194138..b044677fdf 100644 --- a/plugins/wazuh-check-updates/public/hooks/available-updates.ts +++ b/plugins/wazuh-check-updates/public/hooks/available-updates.ts @@ -22,13 +22,14 @@ export const useAvailableUpdates = () => { setLastCheck(response?.last_check_date); setError(undefined); } catch (error: any) { - setError(error); if (returnError) { return error instanceof Error ? error : typeof error === 'string' ? new Error(error) : new Error('Error trying to get available updates'); + } else { + setError(error); } } finally { setIsLoading(false);